1 /* vi: set sw=4 ts=4: */
3 * ash shell port for busybox
5 * Copyright (c) 1989, 1991, 1993, 1994
6 * The Regents of the University of California. All rights reserved.
8 * This code is derived from software contributed to Berkeley by
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.
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.
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
25 * This version of ash is adapted from the source in Debian's ash 0.3.8-5
28 * Modified by Erik Andersen <andersee@debian.org> to be used in
29 * busybox, based in part on prior work done by Vladimir Oleynik
32 * Original copyright notice is retained at the end of this file.
38 #undef ASH_MATH_SUPPORT
60 #include <sys/cdefs.h>
61 #include <sys/ioctl.h>
62 #include <sys/param.h>
63 #include <sys/resource.h>
65 #include <sys/times.h>
66 #include <sys/types.h>
70 #if !defined(FNMATCH_BROKEN)
73 #if !defined(GLOB_BROKEN)
79 #undef CEOF /* syntax.h redefines this */
87 #define _DIAGASSERT(x)
91 #define S_DFL 1 /* default signal handling (SIG_DFL) */
92 #define S_CATCH 2 /* signal is caught */
93 #define S_IGN 3 /* signal is ignored (SIG_IGN) */
94 #define S_HARD_IGN 4 /* signal is ignored permenantly */
95 #define S_RESET 5 /* temporary - to reset a hard ignored sig */
99 struct alias *atab[ATABSIZE];
101 static void setalias __P((char *, char *));
102 static struct alias **hashalias __P((const char *));
103 static struct alias *freealias __P((struct alias *));
104 static struct alias **__lookupalias __P((const char *));
105 static char *trap[NSIG]; /* trap handler commands */
106 static char sigmode[NSIG - 1]; /* current value of signal */
107 static char gotsig[NSIG - 1]; /* indicates specified signal received */
108 static int pendingsigs; /* indicates some signal received */
115 struct alias *ap, **app;
117 app = __lookupalias(name);
121 if (!(ap->flag & ALIASINUSE)) {
124 ap->val = savestr(val);
125 ap->flag &= ~ALIASDEAD;
128 ap = ckmalloc(sizeof (struct alias));
129 ap->name = savestr(name);
130 ap->val = savestr(val);
144 app = __lookupalias(name);
148 *app = freealias(*app);
157 static void rmaliases __P((void));
166 struct alias *ap, **app;
170 for (i = 0; i < ATABSIZE; i++) {
172 for (ap = *app; ap; ap = *app) {
173 *app = freealias(*app);
183 lookupalias(name, check)
187 struct alias *ap = *__lookupalias(name);
189 if (check && ap && (ap->flag & ALIASINUSE))
210 for (i = 0; i < ATABSIZE; i++)
211 for (ap = atab[i]; ap; ap = ap->next) {
216 while ((n = *++argv) != NULL) {
217 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
218 if ((ap = *__lookupalias(n)) == NULL) {
219 outfmt(out2, "%s: %s not found\n", "alias", n);
234 unaliascmd(argc, argv)
240 while ((i = nextopt("a")) != '\0') {
246 for (i = 0; *argptr; argptr++) {
247 if (unalias(*argptr)) {
248 outfmt(out2, "%s: %s not found\n", "unalias", *argptr);
256 static struct alias **
260 unsigned int hashval;
265 return &atab[hashval % ATABSIZE];
268 static struct alias *
269 freealias(struct alias *ap) {
272 if (ap->flag & ALIASINUSE) {
273 ap->flag |= ALIASDEAD;
285 printalias(const struct alias *ap) {
288 p = single_quote(ap->val);
289 out1fmt("alias %s=%s\n", ap->name, p);
293 static struct alias **
294 __lookupalias(const char *name) {
295 struct alias **app = hashalias(name);
297 for (; *app; app = &(*app)->next) {
298 if (equal(name, (*app)->name)) {
306 #ifdef ASH_MATH_SUPPORT
307 /* The generated file arith.c has been snipped. If you want this
308 * stuff back in, feel free to add it to your own copy. */
312 * This file was generated by the mkbuiltins program.
315 static int bgcmd __P((int, char **));
316 static int breakcmd __P((int, char **));
317 static int cdcmd __P((int, char **));
318 static int commandcmd __P((int, char **));
319 static int dotcmd __P((int, char **));
320 static int evalcmd __P((int, char **));
321 static int execcmd __P((int, char **));
322 static int exitcmd __P((int, char **));
323 static int exportcmd __P((int, char **));
324 static int histcmd __P((int, char **));
325 static int fgcmd __P((int, char **));
326 static int hashcmd __P((int, char **));
327 static int jobscmd __P((int, char **));
328 static int killcmd __P((int, char **));
329 static int localcmd __P((int, char **));
330 static int pwdcmd __P((int, char **));
331 static int readcmd __P((int, char **));
332 static int returncmd __P((int, char **));
333 static int setcmd __P((int, char **));
334 static int setvarcmd __P((int, char **));
335 static int shiftcmd __P((int, char **));
336 static int trapcmd __P((int, char **));
337 static int umaskcmd __P((int, char **));
338 static int unaliascmd __P((int, char **));
339 static int unsetcmd __P((int, char **));
340 static int waitcmd __P((int, char **));
341 static int aliascmd __P((int, char **));
342 static int ulimitcmd __P((int, char **));
343 static int timescmd __P((int, char **));
344 #ifdef ASH_MATH_SUPPORT
345 static int expcmd __P((int, char **));
348 static int typecmd __P((int, char **));
351 static int getoptscmd __P((int, char **));
353 #ifndef BB_TRUE_FALSE
354 static int true_main __P((int, char **));
355 static int false_main __P((int, char **));
358 static struct builtincmd *DOTCMD;
359 static struct builtincmd *BLTINCMD;
360 static struct builtincmd *COMMANDCMD;
361 static struct builtincmd *EXECCMD;
362 static struct builtincmd *EVALCMD;
364 /* It is CRUCIAL that this listing be kept in ascii order, otherwise
365 * the binary search in find_builtin() will stop working. If you value
366 * your kneecaps, you'll be sure to *make sure* that any changes made
367 * to this array result in the listing remaining in ascii order. You
370 static const struct builtincmd builtincmds[] = {
372 { ":", true_main, 1 },
373 { "alias", aliascmd, 6 },
375 { "break", breakcmd, 1 },
376 { "builtin", bltincmd, 1 },
378 { "chdir", cdcmd, 0 },
379 { "command", commandcmd, 2 },
380 { "continue", breakcmd, 1 },
381 { "eval", evalcmd, 1 },
382 { "exec", execcmd, 1 },
383 { "exit", exitcmd, 1 },
384 #ifdef ASH_MATH_SUPPORT
385 { "exp", expcmd, 0 },
387 { "export", exportcmd, 5 },
388 { "false", false_main, 2 },
389 { "fc", histcmd, 2 },
392 { "getopts", getoptscmd, 2 },
394 { "hash", hashcmd, 0 },
395 { "jobs", jobscmd, 2 },
396 { "kill", killcmd, 2 },
397 #ifdef ASH_MATH_SUPPORT
398 { "let", expcmd, 0 },
400 { "local", localcmd, 4 },
401 { "pwd", pwdcmd, 0 },
402 { "read", readcmd, 2 },
403 { "readonly", exportcmd, 5 },
404 { "return", returncmd, 1 },
405 { "set", setcmd, 1 },
406 { "setvar", setvarcmd, 0 },
407 { "shift", shiftcmd, 1 },
408 { "times", timescmd, 1 },
409 { "trap", trapcmd, 1 },
410 { "true", true_main, 2 },
412 { "type", typecmd, 0 },
414 { "ulimit", ulimitcmd, 0 },
415 { "umask", umaskcmd, 2 },
416 { "unalias", unaliascmd, 2 },
417 { "unset", unsetcmd, 1 },
418 { "wait", waitcmd, 2 },
420 #define NUMBUILTINS (sizeof (builtincmds) / sizeof (struct builtincmd) )
423 /* $NetBSD: cd.c,v 1.27 1999/07/09 03:05:49 christos Exp $ */
425 static int docd __P((char *, int));
426 static char *getcomponent __P((void));
427 static void updatepwd __P((char *));
428 static void getpwd __P((void));
430 static char *curdir = nullstr; /* current working directory */
431 static char *cdcomppath;
452 if ((dest = *argptr) == NULL && (dest = bltinlookup("HOME")) == NULL)
453 error("HOME not set");
456 if (dest[0] == '-' && dest[1] == '\0') {
457 dest = bltinlookup("OLDPWD");
458 if (!dest || !*dest) {
467 if (*dest == '/' || (path = bltinlookup("CDPATH")) == NULL)
469 while ((p = padvance(&path, dest)) != NULL) {
470 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
475 if (p[0] == '.' && p[1] == '/' && p[2] != '\0')
477 print = strcmp(p, dest);
479 if (docd(p, print) >= 0)
484 error("can't cd to %s", dest);
490 * Actually do the chdir. In an interactive shell, print the
491 * directory name if "print" is nonzero.
506 TRACE(("docd(\"%s\", %d) called\n", dest, print));
509 * Check each component of the path. If we find a symlink or
510 * something we can't stat, clear curdir to force a getcwd()
511 * next time we get the value of the current directory.
514 cdcomppath = sstrdup(dest);
521 while ((q = getcomponent()) != NULL) {
522 if (q[0] == '\0' || (q[0] == '.' && q[1] == '\0'))
530 if (equal(component, ".."))
533 if ((lstat(stackblock(), &statb) < 0)
534 || (S_ISLNK(statb.st_mode))) {
542 if (chdir(dest) < 0) {
546 updatepwd(badstat ? NULL : dest);
549 out1fmt(snlfmt, curdir);
555 * Get the next component of the path name pointed to by cdcomppath.
556 * This routine overwrites the string pointed to by cdcomppath.
564 if ((p = cdcomppath) == NULL)
567 while (*p != '/' && *p != '\0')
581 * Update curdir (the name of the current directory) in response to a
582 * cd command. We also call hashcd to let the routines in exec.c know
583 * that the current directory has changed.
594 hashcd(); /* update command hash table */
597 * If our argument is NULL, we don't know the current directory
598 * any more because we traversed a symbolic link or something
599 * we couldn't stat().
601 if (dir == NULL || curdir == nullstr) {
606 cdcomppath = sstrdup(dir);
615 while ((p = getcomponent()) != NULL) {
616 if (equal(p, "..")) {
617 while (new > stackblock() && (STUNPUTC(new), *new) != '/');
618 } else if (*p != '\0' && ! equal(p, ".")) {
624 if (new == stackblock())
627 setpwd(stackblock(), 1);
637 out1fmt(snlfmt, curdir);
647 * Find out what the current directory is. If we already know the current
648 * directory, this routine returns immediately.
656 * Things are a bit complicated here; we could have just used
657 * getcwd, but traditionally getcwd is implemented using popen
658 * to /bin/pwd. This creates a problem for us, since we cannot
659 * keep track of the job if it is being ran behind our backs.
660 * So we re-implement getcwd(), and we suppress interrupts
661 * throughout the process. This is not completely safe, since
662 * the user can still break out of it by killing the pwd program.
663 * We still try to use getcwd for systems that we know have a
664 * c implementation of getcwd, that does not open a pipe to
667 #if defined(__NetBSD__) || defined(__SVR4) || defined(__GLIBC__)
669 if (getcwd(buf, sizeof(buf)) == NULL) {
670 char *pwd = getenv("PWD");
671 struct stat stdot, stpwd;
673 if (pwd && *pwd == '/' && stat(".", &stdot) != -1 &&
674 stat(pwd, &stpwd) != -1 &&
675 stdot.st_dev == stpwd.st_dev &&
676 stdot.st_ino == stpwd.st_ino) {
677 curdir = savestr(pwd);
680 error("getcwd() failed: %s", strerror(errno));
682 curdir = savestr(buf);
692 error("Pipe call failed");
693 jp = makejob((union node *)NULL, 1);
694 if (forkshell(jp, (union node *)NULL, FORK_NOJOB) == 0) {
695 (void) close(pip[0]);
698 dup_as_newfd(pip[1], 1);
701 (void) execl("/bin/pwd", "pwd", (char *)0);
702 error("Cannot exec /bin/pwd");
704 (void) close(pip[1]);
707 while ((i = read(pip[0], p, buf + MAXPWD - p)) > 0
708 || (i == -1 && errno == EINTR)) {
712 (void) close(pip[0]);
714 status = waitforjob(jp);
717 if (i < 0 || p == buf || p[-1] != '\n')
718 error("pwd command failed");
721 curdir = savestr(buf);
726 setpwd(const char *val, int setold)
729 setvar("OLDPWD", curdir, VEXPORT);
732 if (curdir != nullstr) {
739 curdir = savestr(val);
742 setvar("PWD", curdir, VEXPORT);
745 /* $NetBSD: error.c,v 1.23 2000/07/03 03:26:19 matt Exp $ */
748 * Errors and exceptions.
752 * Code to handle exceptions in C.
755 struct jmploc *handler;
756 static int exception;
757 volatile int suppressint;
758 volatile int intpending;
761 static void exverror __P((int, const char *, va_list))
762 __attribute__((__noreturn__));
765 * Called to raise an exception. Since C doesn't include exceptions, we
766 * just do a longjmp to the exception handler. The type of exception is
767 * stored in the global variable "exception".
779 longjmp(handler->loc, 1);
784 * Called from trap.c when a SIGINT is received. (If the user specifies
785 * that SIGINT is to be trapped or ignored using the trap builtin, then
786 * this routine is not called.) Suppressint is nonzero when interrupts
787 * are held using the INTOFF macro. The call to _exit is necessary because
788 * there is a short period after a fork before the signal handlers are
789 * set to the appropriate value for the child. (The test for iflag is
790 * just defensive programming.)
802 sigemptyset(&mysigset);
803 sigprocmask(SIG_SETMASK, &mysigset, NULL);
804 if (rootshell && iflag)
807 signal(SIGINT, SIG_DFL);
815 * Exverror is called to raise the error exception. If the first argument
816 * is not NULL then error prints an error message using printf style
817 * formatting. It then raises the error exception.
820 exverror(cond, msg, ap)
830 TRACE(("exverror(%d, \"%s\") pid=%d\n", cond, msg, getpid()));
832 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
836 outfmt(&errout, "%s: ", commandname);
837 doformat(&errout, msg, ap);
841 outcslow('\n', &errout);
852 error(const char *msg, ...)
867 msg = va_arg(ap, const char *);
869 exverror(EXERROR, msg, ap);
877 exerror(int cond, const char *msg, ...)
893 cond = va_arg(ap, int);
894 msg = va_arg(ap, const char *);
896 exverror(cond, msg, ap);
904 * Table of error messages.
908 short errcode; /* error number */
909 short action; /* operation which encountered the error */
910 const char *msg; /* text describing the error */
914 #define ALL (E_OPEN|E_CREAT|E_EXEC)
916 static const struct errname errormsg[] = {
917 { EINTR, ALL, "interrupted" },
918 { EACCES, ALL, "permission denied" },
919 { EIO, ALL, "I/O error" },
920 { ENOENT, E_OPEN, "no such file" },
921 { ENOENT, E_CREAT,"directory nonexistent" },
922 { ENOENT, E_EXEC, "not found" },
923 { ENOTDIR, E_OPEN, "no such file" },
924 { ENOTDIR, E_CREAT,"directory nonexistent" },
925 { ENOTDIR, E_EXEC, "not found" },
926 { EISDIR, ALL, "is a directory" },
927 { EEXIST, E_CREAT,"file exists" },
929 { EMFILE, ALL, "too many open files" },
931 { ENFILE, ALL, "file table overflow" },
932 { ENOSPC, ALL, "file system full" },
934 { EDQUOT, ALL, "disk quota exceeded" },
937 { ENOSR, ALL, "no streams resources" },
939 { ENXIO, ALL, "no such device or address" },
940 { EROFS, ALL, "read-only file system" },
941 { ETXTBSY, ALL, "text busy" },
943 { EAGAIN, E_EXEC, "not enough memory" },
945 { ENOMEM, ALL, "not enough memory" },
947 { ENOLINK, ALL, "remote access failed" },
950 { EMULTIHOP, ALL, "remote access failed" },
953 { ECOMM, ALL, "remote access failed" },
956 { ESTALE, ALL, "remote access failed" },
959 { ETIMEDOUT, ALL, "remote access failed" },
962 { ELOOP, ALL, "symbolic link loop" },
964 { E2BIG, E_EXEC, "argument list too long" },
966 { ELIBACC, E_EXEC, "shared library missing" },
973 * Return a string describing an error. The returned string may be a
974 * pointer to a static buffer that will be overwritten on the next call.
975 * Action describes the operation that got the error.
983 struct errname const *ep;
986 for (ep = errormsg ; ep->errcode ; ep++) {
987 if (ep->errcode == e && (ep->action & action) != 0)
990 fmtstr(buf, sizeof buf, "error %d", e);
998 if (--suppressint == 0 && intpending) {
1003 /* $NetBSD: eval.c,v 1.57 2001/02/04 19:52:06 christos Exp $ */
1006 /* flags in argument to evaltree */
1007 #define EV_EXIT 01 /* exit after evaluating tree */
1008 #define EV_TESTED 02 /* exit status is checked; ignore -e flag */
1009 #define EV_BACKCMD 04 /* command executing within back quotes */
1011 static int evalskip; /* set if we are skipping commands */
1012 static int skipcount; /* number of levels to skip */
1013 static int loopnest; /* current loop nesting level */
1014 static int funcnest; /* depth of function calls */
1017 static char *commandname;
1018 struct strlist *cmdenviron;
1019 static int exitstatus; /* exit status of last command */
1020 static int oexitstatus; /* saved exit status */
1023 static void evalloop __P((union node *, int));
1024 static void evalfor __P((union node *, int));
1025 static void evalcase __P((union node *, int));
1026 static void evalsubshell __P((union node *, int));
1027 static void expredir __P((union node *));
1028 static void evalpipe __P((union node *));
1030 static void evalcommand __P((union node *, int, struct backcmd *));
1032 static void evalcommand __P((union node *, int));
1034 static void prehash __P((union node *));
1035 static void eprintlist __P((struct strlist *));
1039 * Called to reset things after an exception.
1059 * The eval commmand.
1074 STARTSTACKSTR(concat);
1078 STPUTC(*p++, concat);
1079 if ((p = *ap++) == NULL)
1081 STPUTC(' ', concat);
1083 STPUTC('\0', concat);
1084 p = grabstackstr(concat);
1086 evalstring(p, EV_TESTED);
1093 * Execute a command or commands contained in a string.
1102 struct stackmark smark;
1104 setstackmark(&smark);
1106 while ((n = parsecmd(0)) != NEOF) {
1108 popstackmark(&smark);
1111 popstackmark(&smark);
1117 * Evaluate a parse tree. The value is left in the global variable
1128 TRACE(("evaltree(NULL) called\n"));
1131 TRACE(("evaltree(0x%lx: %d) called\n", (long)n, n->type));
1134 evaltree(n->nbinary.ch1, flags & EV_TESTED);
1137 evaltree(n->nbinary.ch2, flags);
1140 evaltree(n->nbinary.ch1, EV_TESTED);
1141 if (evalskip || exitstatus != 0)
1143 evaltree(n->nbinary.ch2, flags);
1146 evaltree(n->nbinary.ch1, EV_TESTED);
1147 if (evalskip || exitstatus == 0)
1149 evaltree(n->nbinary.ch2, flags);
1152 expredir(n->nredir.redirect);
1153 redirect(n->nredir.redirect, REDIR_PUSH);
1154 evaltree(n->nredir.n, flags);
1158 evalsubshell(n, flags);
1161 evalsubshell(n, flags);
1164 evaltree(n->nif.test, EV_TESTED);
1167 if (exitstatus == 0)
1168 evaltree(n->nif.ifpart, flags);
1169 else if (n->nif.elsepart)
1170 evaltree(n->nif.elsepart, flags);
1186 struct builtincmd *bcmd;
1188 (bcmd = find_builtin(n->narg.text)) &&
1189 bcmd->flags & BUILTIN_SPECIAL
1191 outfmt(out2, "%s is a special built-in\n", n->narg.text);
1195 defun(n->narg.text, n->narg.next);
1200 evaltree(n->nnot.com, EV_TESTED);
1201 exitstatus = !exitstatus;
1210 evalcommand(n, flags, (struct backcmd *)NULL);
1212 evalcommand(n, flags);
1218 out1fmt("Node type = %d\n", n->type);
1219 #ifndef USE_GLIBC_STDIO
1230 (checkexit && eflag && exitstatus && !(flags & EV_TESTED))
1232 exitshell(exitstatus);
1246 evaltree(n->nbinary.ch1, EV_TESTED);
1248 skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
1252 if (evalskip == SKIPBREAK && --skipcount <= 0)
1256 if (n->type == NWHILE) {
1257 if (exitstatus != 0)
1260 if (exitstatus == 0)
1263 evaltree(n->nbinary.ch2, flags & EV_TESTED);
1264 status = exitstatus;
1269 exitstatus = status;
1279 struct arglist arglist;
1282 struct stackmark smark;
1284 setstackmark(&smark);
1285 arglist.lastp = &arglist.list;
1286 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
1287 oexitstatus = exitstatus;
1288 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
1292 *arglist.lastp = NULL;
1296 for (sp = arglist.list ; sp ; sp = sp->next) {
1297 setvar(n->nfor.var, sp->text, 0);
1298 evaltree(n->nfor.body, flags & EV_TESTED);
1300 if (evalskip == SKIPCONT && --skipcount <= 0) {
1304 if (evalskip == SKIPBREAK && --skipcount <= 0)
1311 popstackmark(&smark);
1323 struct arglist arglist;
1324 struct stackmark smark;
1326 setstackmark(&smark);
1327 arglist.lastp = &arglist.list;
1328 oexitstatus = exitstatus;
1329 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
1330 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
1331 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
1332 if (casematch(patp, arglist.list->text)) {
1333 if (evalskip == 0) {
1334 evaltree(cp->nclist.body, flags);
1341 popstackmark(&smark);
1347 * Kick off a subshell to evaluate a tree.
1351 evalsubshell(n, flags)
1356 int backgnd = (n->type == NBACKGND);
1358 expredir(n->nredir.redirect);
1360 if (forkshell(jp, n, backgnd) == 0) {
1362 flags &=~ EV_TESTED;
1363 redirect(n->nredir.redirect, 0);
1364 evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */
1368 exitstatus = waitforjob(jp);
1376 * Compute the names of the files in a redirection list.
1385 for (redir = n ; redir ; redir = redir->nfile.next) {
1387 fn.lastp = &fn.list;
1388 oexitstatus = exitstatus;
1389 switch (redir->type) {
1395 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
1396 redir->nfile.expfname = fn.list->text;
1400 if (redir->ndup.vname) {
1401 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
1402 fixredir(redir, fn.list->text, 1);
1412 * Evaluate a pipeline. All the processes in the pipeline are children
1413 * of the process creating the pipeline. (This differs from some versions
1414 * of the shell, which make the last process in a pipeline the parent
1423 struct nodelist *lp;
1428 TRACE(("evalpipe(0x%lx) called\n", (long)n));
1430 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
1433 jp = makejob(n, pipelen);
1435 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
1439 if (pipe(pip) < 0) {
1441 error("Pipe call failed");
1444 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
1448 dup_as_newfd(prevfd, 0);
1460 dup_as_newfd(pip[1], 1);
1464 evaltree(lp->n, EV_EXIT);
1472 if (n->npipe.backgnd == 0) {
1474 exitstatus = waitforjob(jp);
1475 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
1483 * Execute a command inside back quotes. If it's a builtin command, we
1484 * want to save its output in a block obtained from malloc. Otherwise
1485 * we fork off a subprocess and get the output of the command via a pipe.
1486 * Should be called with interrupts off.
1490 evalbackcmd(n, result)
1492 struct backcmd *result;
1496 struct stackmark smark; /* unnecessary */
1498 setstackmark(&smark);
1509 * For now we disable executing builtins in the same
1510 * context as the shell, because we are not keeping
1511 * enough state to recover from changes that are
1512 * supposed only to affect subshells. eg. echo "`cd /`"
1514 if (n->type == NCMD) {
1515 exitstatus = oexitstatus;
1516 evalcommand(n, EV_BACKCMD, result);
1522 error("Pipe call failed");
1524 if (forkshell(jp, n, FORK_NOJOB) == 0) {
1529 dup_as_newfd(pip[1], 1);
1533 evaltree(n, EV_EXIT);
1536 result->fd = pip[0];
1540 popstackmark(&smark);
1541 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
1542 result->fd, result->buf, result->nleft, result->jp));
1548 * Execute a simple command.
1553 evalcommand(cmd, flags, backcmd)
1556 struct backcmd *backcmd;
1558 evalcommand(cmd, flags)
1563 struct stackmark smark;
1565 struct arglist arglist;
1566 struct arglist varlist;
1575 struct cmdentry cmdentry;
1577 char *volatile savecmdname;
1578 volatile struct shparam saveparam;
1579 struct localvar *volatile savelocalvars;
1583 const struct builtincmd *firstbltin;
1584 struct jmploc *volatile savehandler;
1585 struct jmploc jmploc;
1587 /* Avoid longjmp clobbering */
1594 /* First expand the arguments. */
1595 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
1596 setstackmark(&smark);
1597 arglist.lastp = &arglist.list;
1598 varlist.lastp = &varlist.list;
1600 oexitstatus = exitstatus;
1603 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
1604 expandarg(argp, &varlist, EXP_VARTILDE);
1607 argp = cmd->ncmd.args; argp && !arglist.list;
1608 argp = argp->narg.next
1610 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
1613 struct builtincmd *bcmd;
1615 bcmd = find_builtin(arglist.list->text);
1616 pseudovarflag = bcmd && bcmd->flags & BUILTIN_ASSIGN;
1617 for (; argp; argp = argp->narg.next) {
1618 if (pseudovarflag && isassignment(argp->narg.text)) {
1619 expandarg(argp, &arglist, EXP_VARTILDE);
1622 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
1625 *arglist.lastp = NULL;
1626 *varlist.lastp = NULL;
1627 expredir(cmd->ncmd.redirect);
1629 for (sp = arglist.list ; sp ; sp = sp->next)
1631 argv = stalloc(sizeof (char *) * (argc + 1));
1633 for (sp = arglist.list ; sp ; sp = sp->next) {
1634 TRACE(("evalcommand arg: %s\n", sp->text));
1639 if (iflag && funcnest == 0 && argc > 0)
1643 /* Print the command if xflag is set. */
1648 outcslow('+', &errout);
1650 eprintlist(varlist.list);
1651 eprintlist(arglist.list);
1653 outc('\n', &errout);
1656 outcslow('\n', &errout);
1660 /* Now locate the command. */
1662 cmdentry.cmdtype = CMDBUILTIN;
1663 firstbltin = cmdentry.u.cmd = BLTINCMD;
1665 const char *oldpath;
1666 int findflag = DO_ERR;
1670 * Modify the command lookup path, if a PATH= assignment
1673 for (sp = varlist.list ; sp ; sp = sp->next)
1674 if (varequal(sp->text, defpathvar)) {
1675 path = sp->text + 5;
1676 findflag |= DO_BRUTE;
1679 oldfindflag = findflag;
1682 find_command(argv[0], &cmdentry, findflag, path);
1683 if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */
1690 /* implement bltin and command here */
1691 if (cmdentry.cmdtype != CMDBUILTIN) {
1695 firstbltin = cmdentry.u.cmd;
1697 if (cmdentry.u.cmd == BLTINCMD) {
1699 struct builtincmd *bcmd;
1704 if (!(bcmd = find_builtin(*argv))) {
1705 outfmt(&errout, "%s: not found\n", *argv);
1712 cmdentry.u.cmd = bcmd;
1713 if (bcmd != BLTINCMD)
1717 if (cmdentry.u.cmd == COMMANDCMD) {
1722 if (*argv[0] == '-') {
1723 if (!equal(argv[0], "-p")) {
1733 findflag |= DO_BRUTE;
1736 findflag = oldfindflag;
1738 findflag |= DO_NOFUN;
1746 /* Fork off a child process if necessary. */
1747 if (cmd->ncmd.backgnd
1748 || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0)
1750 || ((flags & EV_BACKCMD) != 0
1751 && (cmdentry.cmdtype != CMDBUILTIN
1752 || cmdentry.u.bcmd == DOTCMD
1753 || cmdentry.u.bcmd == EVALCMD))
1756 jp = makejob(cmd, 1);
1757 mode = cmd->ncmd.backgnd;
1759 if (flags & EV_BACKCMD) {
1762 error("Pipe call failed");
1765 if (forkshell(jp, cmd, mode) != 0)
1766 goto parent; /* at end of routine */
1768 if (flags & EV_BACKCMD) {
1773 dup_as_newfd(pip[1], 1);
1781 /* This is the child process if a fork occurred. */
1782 /* Execute the command. */
1783 if (cmdentry.cmdtype == CMDFUNCTION) {
1785 trputs("Shell function: "); trargs(argv);
1787 exitstatus = oexitstatus;
1788 redirect(cmd->ncmd.redirect, REDIR_PUSH);
1789 saveparam = shellparam;
1790 shellparam.malloc = 0;
1791 shellparam.nparam = argc - 1;
1792 shellparam.p = argv + 1;
1794 savelocalvars = localvars;
1797 if (setjmp(jmploc.loc)) {
1798 if (exception == EXSHELLPROC) {
1799 freeparam((volatile struct shparam *)
1802 saveparam.optind = shellparam.optind;
1803 saveparam.optoff = shellparam.optoff;
1804 freeparam(&shellparam);
1805 shellparam = saveparam;
1808 localvars = savelocalvars;
1809 handler = savehandler;
1810 longjmp(handler->loc, 1);
1812 savehandler = handler;
1814 for (sp = varlist.list ; sp ; sp = sp->next)
1817 evaltree(cmdentry.u.func, flags & EV_TESTED);
1821 localvars = savelocalvars;
1822 saveparam.optind = shellparam.optind;
1823 saveparam.optoff = shellparam.optoff;
1824 freeparam(&shellparam);
1825 shellparam = saveparam;
1826 handler = savehandler;
1829 if (evalskip == SKIPFUNC) {
1833 if (flags & EV_EXIT)
1834 exitshell(exitstatus);
1835 } else if (cmdentry.cmdtype == CMDBUILTIN) {
1837 trputs("builtin command: "); trargs(argv);
1839 mode = (cmdentry.u.cmd == EXECCMD)? 0 : REDIR_PUSH;
1841 if (flags == EV_BACKCMD) {
1842 #ifdef USE_GLIBC_STDIO
1846 memout.nextc = memout.buf;
1847 memout.bufsize = 64;
1849 mode |= REDIR_BACKQ;
1852 redirect(cmd->ncmd.redirect, mode);
1853 savecmdname = commandname;
1854 if (firstbltin->flags & BUILTIN_SPECIAL) {
1855 listsetvar(varlist.list);
1857 cmdenviron = varlist.list;
1860 if (setjmp(jmploc.loc)) {
1862 exitstatus = (e == EXINT)? SIGINT+128 : 2;
1865 savehandler = handler;
1867 commandname = argv[0];
1869 optptr = NULL; /* initialize nextopt */
1870 exitstatus = (*cmdentry.u.cmd->builtinfunc)(argc, argv);
1873 exitstatus |= outerr(out1);
1878 if (e != EXSHELLPROC) {
1879 commandname = savecmdname;
1880 if (flags & EV_EXIT)
1881 exitshell(exitstatus);
1883 handler = savehandler;
1885 if ((e != EXERROR && e != EXEXEC)
1886 || cmdentry.u.cmd == BLTINCMD
1887 || cmdentry.u.cmd == DOTCMD
1888 || cmdentry.u.cmd == EVALCMD
1889 || cmdentry.u.cmd == EXECCMD)
1893 if (cmdentry.u.cmd != EXECCMD)
1896 if (flags == EV_BACKCMD) {
1898 #ifdef USE_GLIBC_STDIO
1899 if (__closememout()) {
1901 "__closememout() failed: %s",
1906 backcmd->buf = memout.buf;
1907 #ifdef USE_GLIBC_STDIO
1908 backcmd->nleft = memout.bufsize;
1910 backcmd->nleft = memout.nextc - memout.buf;
1918 trputs("normal command: "); trargs(argv);
1920 redirect(cmd->ncmd.redirect, 0);
1922 for (sp = varlist.list ; sp ; sp = sp->next)
1923 setvareq(sp->text, VEXPORT|VSTACK);
1924 envp = environment();
1925 shellexec(argv, envp, path, cmdentry.u.index);
1929 parent: /* parent process gets here (if we forked) */
1930 if (mode == 0) { /* argument to fork */
1932 exitstatus = waitforjob(jp);
1935 } else if (mode == 2) {
1936 backcmd->fd = pip[0];
1944 setvar("_", lastarg, 0);
1945 popstackmark(&smark);
1951 * Search for a command. This is called before we fork so that the
1952 * location of the command will be available in the parent as well as
1953 * the child. The check for "goodname" is an overly conservative
1954 * check that the name will not be subject to expansion.
1961 struct cmdentry entry;
1963 if (n->type == NCMD && n->ncmd.args)
1964 if (goodname(n->ncmd.args->narg.text))
1965 find_command(n->ncmd.args->narg.text, &entry, 0,
1972 * Builtin commands. Builtin commands whose functions are closely
1973 * tied to evaluation are implemented here.
1977 * No command given, or a bltin command with no arguments. Set the
1978 * specified variables.
1982 bltincmd(argc, argv)
1987 * Preserve exitstatus of a previous possible redirection
1995 * Handle break and continue commands. Break, continue, and return are
1996 * all handled by setting the evalskip flag. The evaluation routines
1997 * above all check this flag, and if it is set they start skipping
1998 * commands rather than executing them. The variable skipcount is
1999 * the number of loops to break/continue, or the number of function
2000 * levels to return. (The latter is always 1.) It should probably
2001 * be an error to break out of more loops than exist, but it isn't
2002 * in the standard shell so we don't make it one here.
2006 breakcmd(argc, argv)
2010 int n = argc > 1 ? number(argv[1]) : 1;
2015 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
2023 * The return command.
2027 returncmd(argc, argv)
2031 int ret = argc > 1 ? number(argv[1]) : oexitstatus;
2034 evalskip = SKIPFUNC;
2039 /* Do what ksh does; skip the rest of the file */
2040 evalskip = SKIPFILE;
2047 #ifndef BB_TRUE_FALSE
2049 false_main(argc, argv)
2058 true_main(argc, argv)
2074 iflag = 0; /* exit on error */
2077 for (sp = cmdenviron; sp ; sp = sp->next)
2078 setvareq(sp->text, VEXPORT|VSTACK);
2079 shellexec(argv + 1, environment(), pathval(), 0);
2085 eprintlist(struct strlist *sp)
2087 for (; sp; sp = sp->next) {
2088 outfmt(&errout, " %s",sp->text);
2091 /* $NetBSD: exec.c,v 1.32 2001/02/04 19:52:06 christos Exp $ */
2094 * When commands are first encountered, they are entered in a hash table.
2095 * This ensures that a full path search will not have to be done for them
2096 * on each invocation.
2098 * We should investigate converting to a linear search, even though that
2099 * would make the command name "hash" a misnomer.
2101 #define CMDTABLESIZE 31 /* should be prime */
2102 #define ARB 1 /* actual size determined at run time */
2107 struct tblentry *next; /* next entry in hash chain */
2108 union param param; /* definition of builtin function */
2109 short cmdtype; /* index identifying command */
2110 char rehash; /* if set, cd done since entry created */
2111 char cmdname[ARB]; /* name of command */
2115 static struct tblentry *cmdtable[CMDTABLESIZE];
2116 static int builtinloc = -1; /* index in path of %builtin, or -1 */
2117 static int exerrno = 0; /* Last exec error */
2120 static void tryexec __P((char *, char **, char **));
2121 #if !defined(BSD) && !defined(linux)
2122 static void execinterp __P((char **, char **));
2124 static void printentry __P((struct tblentry *, int));
2125 static void clearcmdentry __P((int));
2126 static struct tblentry *cmdlookup __P((char *, int));
2127 static void delete_cmd_entry __P((void));
2129 static int describe_command __P((char *, int));
2131 static int path_change __P((const char *, int *));
2135 * Exec a program. Never returns. If you change this routine, you may
2136 * have to change the find_command routine as well.
2140 shellexec(argv, envp, path, idx)
2141 char **argv, **envp;
2148 if (strchr(argv[0], '/') != NULL) {
2149 tryexec(argv[0], argv, envp);
2153 while ((cmdname = padvance(&path, argv[0])) != NULL) {
2154 if (--idx < 0 && pathopt == NULL) {
2155 tryexec(cmdname, argv, envp);
2156 if (errno != ENOENT && errno != ENOTDIR)
2163 /* Map to POSIX errors */
2175 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
2181 tryexec(cmd, argv, envp)
2187 #if !defined(BSD) && !defined(linux)
2193 execve(cmd, argv, envp);
2194 } while (errno == EINTR);
2196 execve(cmd, argv, envp);
2202 setinputfile(cmd, 0);
2203 commandname = arg0 = savestr(argv[0]);
2204 #if !defined(BSD) && !defined(linux)
2206 pgetc(); pungetc(); /* fill up input buffer */
2208 if (parsenleft > 2 && p[0] == '#' && p[1] == '!') {
2210 execinterp(argv, envp);
2215 exraise(EXSHELLPROC);
2221 #if !defined(BSD) && !defined(linux)
2223 * Execute an interpreter introduced by "#!", for systems where this
2224 * feature has not been built into the kernel. If the interpreter is
2225 * the shell, return (effectively ignoring the "#!"). If the execution
2226 * of the interpreter fails, exit.
2228 * This code peeks inside the input buffer in order to avoid actually
2229 * reading any input. It would benefit from a rewrite.
2235 execinterp(argv, envp)
2236 char **argv, **envp;
2244 char *newargs[NEWARGS];
2250 inp = parsenextc + 2;
2253 while (--n >= 0 && (*inp == ' ' || *inp == '\t'))
2257 if ((c = *inp++) == '\n')
2259 if (ap == &newargs[NEWARGS])
2260 bad: error("Bad #! line");
2261 STARTSTACKSTR(outp);
2264 } while (--n >= 0 && (c = *inp++) != ' ' && c != '\t' && c != '\n');
2267 *ap++ = grabstackstr(outp);
2269 if (ap == newargs + 1) { /* if no args, maybe no exec is needed */
2272 if (equal(p, "sh") || equal(p, "ash")) {
2284 i = (char *)ap - (char *)newargs; /* size in bytes */
2286 error("Bad #! line");
2287 for (ap2 = argv ; *ap2++ != NULL ; );
2288 new = ckmalloc(i + ((char *)ap2 - (char *)argv));
2289 ap = newargs, ap2 = new;
2290 while ((i -= sizeof (char **)) >= 0)
2293 while (*ap2++ = *ap++);
2294 shellexec(new, envp, pathval(), 0);
2302 * Do a path search. The variable path (passed by reference) should be
2303 * set to the start of the path before the first call; padvance will update
2304 * this value as it proceeds. Successive calls to padvance will return
2305 * the possible path expansions in sequence. If an option (indicated by
2306 * a percent sign) appears in the path entry then the global variable
2307 * pathopt will be set to point to it; otherwise pathopt will be set to
2311 static const char *pathopt;
2314 padvance(path, name)
2326 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
2327 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2328 while (stackblocksize() < len)
2332 memcpy(q, start, p - start);
2340 while (*p && *p != ':') p++;
2346 return stalloc(len);
2351 /*** Command hashing code ***/
2359 struct tblentry **pp;
2360 struct tblentry *cmdp;
2363 struct cmdentry entry;
2367 while ((c = nextopt("rv")) != '\0') {
2371 } else if (c == 'v') {
2375 if (*argptr == NULL) {
2376 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
2377 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
2378 if (cmdp->cmdtype != CMDBUILTIN) {
2379 printentry(cmdp, verbose);
2386 while ((name = *argptr) != NULL) {
2387 if ((cmdp = cmdlookup(name, 0)) != NULL
2388 && (cmdp->cmdtype == CMDNORMAL
2389 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
2391 find_command(name, &entry, DO_ERR, pathval());
2392 if (entry.cmdtype == CMDUNKNOWN) c = 1;
2394 cmdp = cmdlookup(name, 0);
2395 if (cmdp) printentry(cmdp, verbose);
2405 printentry(cmdp, verbose)
2406 struct tblentry *cmdp;
2413 if (cmdp->cmdtype == CMDNORMAL) {
2414 idx = cmdp->param.index;
2417 name = padvance(&path, cmdp->cmdname);
2419 } while (--idx >= 0);
2421 } else if (cmdp->cmdtype == CMDBUILTIN) {
2422 out1fmt("builtin %s", cmdp->cmdname);
2423 } else if (cmdp->cmdtype == CMDFUNCTION) {
2424 out1fmt("function %s", cmdp->cmdname);
2427 name = commandtext(cmdp->param.func);
2428 out1fmt(" %s", name);
2434 error("internal error: cmdtype %d", cmdp->cmdtype);
2437 out1fmt(snlfmt, cmdp->rehash ? "*" : nullstr);
2443 * Resolve a command name. If you change this routine, you may have to
2444 * change the shellexec routine as well.
2448 find_command(name, entry, act, path)
2450 struct cmdentry *entry;
2454 struct tblentry *cmdp;
2464 struct builtincmd *bcmd;
2466 /* If name contains a slash, don't use the hash table */
2467 if (strchr(name, '/') != NULL) {
2469 while (stat(name, &statb) < 0) {
2474 if (errno != ENOENT && errno != ENOTDIR)
2476 entry->cmdtype = CMDUNKNOWN;
2477 entry->u.index = -1;
2480 entry->cmdtype = CMDNORMAL;
2481 entry->u.index = -1;
2484 entry->cmdtype = CMDNORMAL;
2490 if (act & DO_BRUTE) {
2491 firstchange = path_change(path, &bltin);
2497 /* If name is in the table, and not invalidated by cd, we're done */
2498 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0) {
2499 if (cmdp->cmdtype == CMDFUNCTION) {
2500 if (act & DO_NOFUN) {
2505 } else if (act & DO_BRUTE) {
2506 if ((cmdp->cmdtype == CMDNORMAL &&
2507 cmdp->param.index >= firstchange) ||
2508 (cmdp->cmdtype == CMDBUILTIN &&
2509 ((builtinloc < 0 && bltin >= 0) ?
2510 bltin : builtinloc) >= firstchange)) {
2511 /* need to recompute the entry */
2520 bcmd = find_builtin(name);
2521 regular = bcmd && bcmd->flags & BUILTIN_REGULAR;
2524 if (cmdp && (cmdp->cmdtype == CMDBUILTIN)) {
2527 } else if (act & DO_BRUTE) {
2528 if (firstchange == 0) {
2533 /* If %builtin not in path, check for builtin next */
2534 if (regular || (bltin < 0 && bcmd)) {
2537 entry->cmdtype = CMDBUILTIN;
2538 entry->u.cmd = bcmd;
2542 cmdp = cmdlookup(name, 1);
2543 cmdp->cmdtype = CMDBUILTIN;
2544 cmdp->param.cmd = bcmd;
2549 /* We have to search path. */
2550 prev = -1; /* where to start */
2551 if (cmdp && cmdp->rehash) { /* doing a rehash */
2552 if (cmdp->cmdtype == CMDBUILTIN)
2555 prev = cmdp->param.index;
2561 while ((fullname = padvance(&path, name)) != NULL) {
2562 stunalloc(fullname);
2564 if (idx >= firstchange) {
2568 if (prefix("builtin", pathopt)) {
2569 if ((bcmd = find_builtin(name))) {
2573 } else if (!(act & DO_NOFUN) &&
2574 prefix("func", pathopt)) {
2577 continue; /* ignore unimplemented options */
2580 /* if rehash, don't redo absolute path names */
2581 if (fullname[0] == '/' && idx <= prev &&
2582 idx < firstchange) {
2585 TRACE(("searchexec \"%s\": no change\n", name));
2588 while (stat(fullname, &statb) < 0) {
2593 if (errno != ENOENT && errno != ENOTDIR)
2597 e = EACCES; /* if we fail, this will be the error */
2598 if (!S_ISREG(statb.st_mode))
2600 if (pathopt) { /* this is a %func directory */
2601 stalloc(strlen(fullname) + 1);
2602 readcmdfile(fullname);
2603 if ((cmdp = cmdlookup(name, 0)) == NULL || cmdp->cmdtype != CMDFUNCTION)
2604 error("%s not defined in %s", name, fullname);
2605 stunalloc(fullname);
2609 if (statb.st_uid == geteuid()) {
2610 if ((statb.st_mode & 0100) == 0)
2612 } else if (statb.st_gid == getegid()) {
2613 if ((statb.st_mode & 010) == 0)
2616 if ((statb.st_mode & 01) == 0)
2620 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
2621 /* If we aren't called with DO_BRUTE and cmdp is set, it must
2622 be a function and we're being called with DO_NOFUN */
2624 entry->cmdtype = CMDNORMAL;
2625 entry->u.index = idx;
2629 cmdp = cmdlookup(name, 1);
2630 cmdp->cmdtype = CMDNORMAL;
2631 cmdp->param.index = idx;
2636 /* We failed. If there was an entry for this command, delete it */
2637 if (cmdp && updatetbl)
2640 outfmt(out2, "%s: %s\n", name, errmsg(e, E_EXEC));
2641 entry->cmdtype = CMDUNKNOWN;
2646 entry->cmdtype = cmdp->cmdtype;
2647 entry->u = cmdp->param;
2653 * Search the table of builtin commands.
2660 struct builtincmd *bp;
2662 bp = bsearch( &name, builtincmds, NUMBUILTINS, sizeof(struct builtincmd),
2670 * Called when a cd is done. Marks all commands so the next time they
2671 * are executed they will be rehashed.
2676 struct tblentry **pp;
2677 struct tblentry *cmdp;
2679 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
2680 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
2681 if (cmdp->cmdtype == CMDNORMAL
2682 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
2691 * Called before PATH is changed. The argument is the new value of PATH;
2692 * pathval() still returns the old value at this point. Called with
2703 firstchange = path_change(newval, &bltin);
2704 if (builtinloc < 0 && bltin >= 0)
2705 builtinloc = bltin; /* zap builtins */
2706 clearcmdentry(firstchange);
2712 * Clear out command entries. The argument specifies the first entry in
2713 * PATH which has changed.
2717 clearcmdentry(firstchange)
2720 struct tblentry **tblp;
2721 struct tblentry **pp;
2722 struct tblentry *cmdp;
2725 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
2727 while ((cmdp = *pp) != NULL) {
2728 if ((cmdp->cmdtype == CMDNORMAL &&
2729 cmdp->param.index >= firstchange)
2730 || (cmdp->cmdtype == CMDBUILTIN &&
2731 builtinloc >= firstchange)) {
2744 * Delete all functions.
2748 static void deletefuncs __P((void));
2757 struct tblentry **tblp;
2758 struct tblentry **pp;
2759 struct tblentry *cmdp;
2762 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
2764 while ((cmdp = *pp) != NULL) {
2765 if (cmdp->cmdtype == CMDFUNCTION) {
2767 freefunc(cmdp->param.func);
2780 * Locate a command in the command hash table. If "add" is nonzero,
2781 * add the command to the table if it is not already present. The
2782 * variable "lastcmdentry" is set to point to the address of the link
2783 * pointing to the entry, so that delete_cmd_entry can delete the
2787 struct tblentry **lastcmdentry;
2790 static struct tblentry *
2791 cmdlookup(name, add)
2797 struct tblentry *cmdp;
2798 struct tblentry **pp;
2805 pp = &cmdtable[hashval % CMDTABLESIZE];
2806 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
2807 if (equal(cmdp->cmdname, name))
2811 if (add && cmdp == NULL) {
2813 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
2814 + strlen(name) + 1);
2816 cmdp->cmdtype = CMDUNKNOWN;
2818 strcpy(cmdp->cmdname, name);
2826 * Delete the command entry returned on the last lookup.
2830 delete_cmd_entry() {
2831 struct tblentry *cmdp;
2834 cmdp = *lastcmdentry;
2835 *lastcmdentry = cmdp->next;
2844 getcmdentry(name, entry)
2846 struct cmdentry *entry;
2848 struct tblentry *cmdp = cmdlookup(name, 0);
2851 entry->u = cmdp->param;
2852 entry->cmdtype = cmdp->cmdtype;
2854 entry->cmdtype = CMDUNKNOWN;
2862 * Add a new command entry, replacing any existing command entry for
2867 addcmdentry(name, entry)
2869 struct cmdentry *entry;
2871 struct tblentry *cmdp;
2874 cmdp = cmdlookup(name, 1);
2875 if (cmdp->cmdtype == CMDFUNCTION) {
2876 freefunc(cmdp->param.func);
2878 cmdp->cmdtype = entry->cmdtype;
2879 cmdp->param = entry->u;
2885 * Define a shell function.
2893 struct cmdentry entry;
2895 entry.cmdtype = CMDFUNCTION;
2896 entry.u.func = copyfunc(func);
2897 addcmdentry(name, &entry);
2902 * Delete a function if it exists.
2909 struct tblentry *cmdp;
2911 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) {
2912 freefunc(cmdp->param.func);
2919 * Locate and print what a word is...
2930 for (i = 1; i < argc; i++) {
2931 err |= describe_command(argv[i], 1);
2937 describe_command(command, verbose)
2941 struct cmdentry entry;
2942 struct tblentry *cmdp;
2943 const struct alias *ap;
2944 const char *path = pathval();
2950 /* First look at the keywords */
2951 if (findkwd(command)) {
2952 out1str(verbose ? " is a shell keyword" : command);
2956 /* Then look at the aliases */
2957 if ((ap = lookupalias(command, 0)) != NULL) {
2959 out1fmt(" is an alias for %s", ap->val);
2966 /* Then check if it is a tracked alias */
2967 if ((cmdp = cmdlookup(command, 0)) != NULL) {
2968 entry.cmdtype = cmdp->cmdtype;
2969 entry.u = cmdp->param;
2971 /* Finally use brute force */
2972 find_command(command, &entry, DO_ABS, path);
2975 switch (entry.cmdtype) {
2977 int j = entry.u.index;
2983 p = padvance(&path, command);
2990 cmdp ? " a tracked alias for" : nullstr, p
3000 out1str(" is a shell function");
3009 " is a %sshell builtin",
3010 entry.u.cmd->flags & BUILTIN_SPECIAL ?
3011 "special " : nullstr
3020 out1str(": not found\n");
3032 commandcmd(argc, argv)
3037 int default_path = 0;
3038 int verify_only = 0;
3039 int verbose_verify_only = 0;
3041 while ((c = nextopt("pvV")) != '\0')
3050 verbose_verify_only = 1;
3054 "command: nextopt returned character code 0%o\n", c);
3058 if (default_path + verify_only + verbose_verify_only > 1 ||
3061 "command [-p] command [arg ...]\n");
3063 "command {-v|-V} command\n");
3068 if (verify_only || verbose_verify_only) {
3069 return describe_command(*argptr, verbose_verify_only);
3077 path_change(newval, bltin)
3081 const char *old, *new;
3087 firstchange = 9999; /* assume no change */
3093 if ((*old == '\0' && *new == ':')
3094 || (*old == ':' && *new == '\0'))
3096 old = new; /* ignore subsequent differences */
3100 if (*new == '%' && *bltin < 0 && prefix("builtin", new + 1))
3107 if (builtinloc >= 0 && *bltin < 0)
3111 /* $NetBSD: expand.c,v 1.50 2001/02/04 19:52:06 christos Exp $ */
3114 * Routines to expand arguments to commands. We have to deal with
3115 * backquotes, shell variables, and file metacharacters.
3120 #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
3121 #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
3124 * Structure specifying which parts of the string should be searched
3125 * for IFS characters.
3129 struct ifsregion *next; /* next region in list */
3130 int begoff; /* offset of start of region */
3131 int endoff; /* offset of end of region */
3132 int nulonly; /* search for nul bytes only */
3136 static char *expdest; /* output of current string */
3137 struct nodelist *argbackq; /* list of back quote expressions */
3138 struct ifsregion ifsfirst; /* first struct in list of ifs regions */
3139 struct ifsregion *ifslastp; /* last struct in list */
3140 struct arglist exparg; /* holds expanded arg list */
3142 static void argstr __P((char *, int));
3143 static char *exptilde __P((char *, int));
3144 static void expbackq __P((union node *, int, int));
3145 static int subevalvar __P((char *, char *, int, int, int, int, int));
3146 static char *evalvar __P((char *, int));
3147 static int varisset __P((char *, int));
3148 static void strtodest __P((const char *, const char *, int));
3149 static void varvalue __P((char *, int, int));
3150 static void recordregion __P((int, int, int));
3151 static void removerecordregions __P((int));
3152 static void ifsbreakup __P((char *, struct arglist *));
3153 static void ifsfree __P((void));
3154 static void expandmeta __P((struct strlist *, int));
3155 #if defined(__GLIBC__) && !defined(FNMATCH_BROKEN)
3156 #define preglob(p) _rmescapes((p), RMESCAPE_ALLOC | RMESCAPE_GLOB)
3157 #if !defined(GLOB_BROKEN)
3158 static void addglob __P((const glob_t *));
3161 #if !(defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
3162 static void expmeta __P((char *, char *));
3164 static void addfname __P((char *));
3165 #if !(defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
3166 static struct strlist *expsort __P((struct strlist *));
3167 static struct strlist *msort __P((struct strlist *, int));
3169 #if defined(__GLIBC__) && !defined(FNMATCH_BROKEN)
3170 static int patmatch __P((char *, char *, int));
3171 static int patmatch2 __P((char *, char *, int));
3173 static int pmatch __P((char *, char *, int));
3174 #define patmatch2 patmatch
3176 static char *cvtnum __P((int, char *));
3178 extern int oexitstatus;
3181 * Expand shell variables and backquotes inside a here document.
3186 union node *arg; /* the document */
3187 int fd; /* where to write the expanded version */
3190 expandarg(arg, (struct arglist *)NULL, 0);
3191 xwrite(fd, stackblock(), expdest - stackblock());
3196 * Perform variable substitution and command substitution on an argument,
3197 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
3198 * perform splitting and file name expansion. When arglist is NULL, perform
3199 * here document expansion.
3203 expandarg(arg, arglist, flag)
3205 struct arglist *arglist;
3211 argbackq = arg->narg.backquote;
3212 STARTSTACKSTR(expdest);
3213 ifsfirst.next = NULL;
3215 argstr(arg->narg.text, flag);
3216 if (arglist == NULL) {
3217 return; /* here document expanded */
3219 STPUTC('\0', expdest);
3220 p = grabstackstr(expdest);
3221 exparg.lastp = &exparg.list;
3225 if (flag & EXP_FULL) {
3226 ifsbreakup(p, &exparg);
3227 *exparg.lastp = NULL;
3228 exparg.lastp = &exparg.list;
3229 expandmeta(exparg.list, flag);
3231 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
3233 sp = (struct strlist *)stalloc(sizeof (struct strlist));
3236 exparg.lastp = &sp->next;
3239 *exparg.lastp = NULL;
3241 *arglist->lastp = exparg.list;
3242 arglist->lastp = exparg.lastp;
3249 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
3250 * characters to allow for further processing. Otherwise treat
3251 * $@ like $* since no splitting will be performed.
3260 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
3263 if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
3264 p = exptilde(p, flag);
3268 case CTLENDVAR: /* ??? */
3271 /* "$@" syntax adherence hack */
3272 if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=')
3274 if ((flag & EXP_FULL) != 0)
3284 p = evalvar(p, flag);
3287 case CTLBACKQ|CTLQUOTE:
3288 expbackq(argbackq->n, c & CTLQUOTE, flag);
3289 argbackq = argbackq->next;
3291 #ifdef ASH_MATH_SUPPORT
3299 * sort of a hack - expand tildes in variable
3300 * assignments (after the first '=' and after ':'s).
3303 if (flag & EXP_VARTILDE && *p == '~') {
3310 p = exptilde(p, flag);
3326 char c, *startp = p;
3329 int quotes = flag & (EXP_FULL | EXP_CASE);
3331 while ((c = *p) != '\0') {
3338 if (flag & EXP_VARTILDE)
3348 if (*(startp+1) == '\0') {
3349 if ((home = lookupvar("HOME")) == NULL)
3352 if ((pw = getpwnam(startp+1)) == NULL)
3359 strtodest(home, SQSYNTAX, quotes);
3368 removerecordregions(endoff)
3371 if (ifslastp == NULL)
3374 if (ifsfirst.endoff > endoff) {
3375 while (ifsfirst.next != NULL) {
3376 struct ifsregion *ifsp;
3378 ifsp = ifsfirst.next->next;
3379 ckfree(ifsfirst.next);
3380 ifsfirst.next = ifsp;
3383 if (ifsfirst.begoff > endoff)
3386 ifslastp = &ifsfirst;
3387 ifsfirst.endoff = endoff;
3392 ifslastp = &ifsfirst;
3393 while (ifslastp->next && ifslastp->next->begoff < endoff)
3394 ifslastp=ifslastp->next;
3395 while (ifslastp->next != NULL) {
3396 struct ifsregion *ifsp;
3398 ifsp = ifslastp->next->next;
3399 ckfree(ifslastp->next);
3400 ifslastp->next = ifsp;
3403 if (ifslastp->endoff > endoff)
3404 ifslastp->endoff = endoff;
3408 #ifdef ASH_MATH_SUPPORT
3410 * Expand arithmetic expression. Backup to start of expression,
3411 * evaluate, place result in (backed up) result, adjust string position.
3420 int quotes = flag & (EXP_FULL | EXP_CASE);
3426 * This routine is slightly over-complicated for
3427 * efficiency. First we make sure there is
3428 * enough space for the result, which may be bigger
3429 * than the expression if we add exponentation. Next we
3430 * scan backwards looking for the start of arithmetic. If the
3431 * next previous character is a CTLESC character, then we
3432 * have to rescan starting from the beginning since CTLESC
3433 * characters have to be processed left to right.
3435 CHECKSTRSPACE(10, expdest);
3436 USTPUTC('\0', expdest);
3437 start = stackblock();
3439 while (*p != CTLARI && p >= start)
3442 error("missing CTLARI (shouldn't happen)");
3443 if (p > start && *(p-1) == CTLESC)
3444 for (p = start; *p != CTLARI; p++)
3453 removerecordregions(begoff);
3456 result = arith(p+2);
3457 fmtstr(p, 12, "%d", result);
3463 recordregion(begoff, p - 1 - start, 0);
3464 result = expdest - p + 1;
3465 STADJUST(-result, expdest);
3471 * Expand stuff in backwards quotes.
3475 expbackq(cmd, quoted, flag)
3480 volatile struct backcmd in;
3484 char *dest = expdest;
3485 volatile struct ifsregion saveifs;
3486 struct ifsregion *volatile savelastp;
3487 struct nodelist *volatile saveargbackq;
3489 int startloc = dest - stackblock();
3490 char const *syntax = quoted? DQSYNTAX : BASESYNTAX;
3491 volatile int saveherefd;
3492 int quotes = flag & (EXP_FULL | EXP_CASE);
3493 struct jmploc jmploc;
3494 struct jmploc *volatile savehandler;
3498 /* Avoid longjmp clobbering */
3509 savelastp = ifslastp;
3510 saveargbackq = argbackq;
3511 saveherefd = herefd;
3513 if ((ex = setjmp(jmploc.loc))) {
3516 savehandler = handler;
3519 p = grabstackstr(dest);
3520 evalbackcmd(cmd, (struct backcmd *) &in);
3521 ungrabstackstr(p, dest);
3525 ifslastp = savelastp;
3526 argbackq = saveargbackq;
3527 herefd = saveherefd;
3535 if (--in.nleft < 0) {
3538 while ((i = read(in.fd, buf, sizeof buf)) < 0 && errno == EINTR);
3539 TRACE(("expbackq: read returns %d\n", i));
3546 if (lastc != '\0') {
3547 if (quotes && syntax[(int)lastc] == CCTL)
3548 STPUTC(CTLESC, dest);
3549 STPUTC(lastc, dest);
3553 /* Eat all trailing newlines */
3554 for (; dest > stackblock() && dest[-1] == '\n';)
3563 exitstatus = waitforjob(in.jp);
3564 handler = savehandler;
3566 longjmp(handler->loc, 1);
3569 recordregion(startloc, dest - stackblock(), 0);
3570 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
3571 (dest - stackblock()) - startloc,
3572 (dest - stackblock()) - startloc,
3573 stackblock() + startloc));
3581 subevalvar(p, str, strloc, subtype, startloc, varflags, quotes)
3594 int saveherefd = herefd;
3595 struct nodelist *saveargbackq = argbackq;
3599 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
3600 STACKSTRNUL(expdest);
3601 herefd = saveherefd;
3602 argbackq = saveargbackq;
3603 startp = stackblock() + startloc;
3605 str = stackblock() + strloc;
3609 setvar(str, startp, 0);
3610 amount = startp - expdest;
3611 STADJUST(amount, expdest);
3618 if (*p != CTLENDVAR) {
3619 outfmt(&errout, snlfmt, startp);
3620 error((char *)NULL);
3622 error("%.*s: parameter %snot set", p - str - 1,
3623 str, (varflags & VSNUL) ? "null or "
3628 for (loc = startp; loc < str; loc++) {
3631 if (patmatch2(str, startp, quotes))
3634 if (quotes && *loc == CTLESC)
3640 for (loc = str - 1; loc >= startp;) {
3643 if (patmatch2(str, startp, quotes))
3647 if (quotes && loc > startp && *(loc - 1) == CTLESC) {
3648 for (q = startp; q < loc; q++)
3658 for (loc = str - 1; loc >= startp;) {
3659 if (patmatch2(str, loc, quotes))
3662 if (quotes && loc > startp && *(loc - 1) == CTLESC) {
3663 for (q = startp; q < loc; q++)
3672 case VSTRIMRIGHTMAX:
3673 for (loc = startp; loc < str - 1; loc++) {
3674 if (patmatch2(str, loc, quotes))
3676 if (quotes && *loc == CTLESC)
3689 amount = ((str - 1) - (loc - startp)) - expdest;
3690 STADJUST(amount, expdest);
3691 while (loc != str - 1)
3696 amount = loc - expdest;
3697 STADJUST(amount, expdest);
3698 STPUTC('\0', expdest);
3699 STADJUST(-1, expdest);
3705 * Expand a variable, and return a pointer to the next character in the
3725 int quotes = flag & (EXP_FULL | EXP_CASE);
3728 subtype = varflags & VSTYPE;
3733 p = strchr(p, '=') + 1;
3734 again: /* jump here after setting a variable with ${var=text} */
3736 set = varisset(var, varflags & VSNUL);
3739 val = lookupvar(var);
3740 if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
3747 startloc = expdest - stackblock();
3748 if (set && subtype != VSPLUS) {
3749 /* insert the value of the variable */
3751 varvalue(var, varflags & VSQUOTE, flag);
3752 if (subtype == VSLENGTH) {
3753 varlen = expdest - stackblock() - startloc;
3754 STADJUST(-varlen, expdest);
3757 if (subtype == VSLENGTH) {
3758 varlen = strlen(val);
3762 varflags & VSQUOTE ?
3763 DQSYNTAX : BASESYNTAX,
3770 if (subtype == VSPLUS)
3773 easy = ((varflags & VSQUOTE) == 0 ||
3774 (*var == '@' && shellparam.nparam != 1));
3779 expdest = cvtnum(varlen, expdest);
3786 recordregion(startloc, expdest - stackblock(),
3787 varflags & VSQUOTE);
3803 case VSTRIMRIGHTMAX:
3807 * Terminate the string and start recording the pattern
3810 STPUTC('\0', expdest);
3811 patloc = expdest - stackblock();
3812 if (subevalvar(p, NULL, patloc, subtype,
3813 startloc, varflags, quotes) == 0) {
3814 int amount = (expdest - stackblock() - patloc) + 1;
3815 STADJUST(-amount, expdest);
3817 /* Remove any recorded regions beyond start of variable */
3818 removerecordregions(startloc);
3824 if (subevalvar(p, var, 0, subtype, startloc,
3825 varflags, quotes)) {
3828 * Remove any recorded regions beyond
3831 removerecordregions(startloc);
3846 if (subtype != VSNORMAL) { /* skip to end of alternative */
3849 if ((c = *p++) == CTLESC)
3851 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
3853 argbackq = argbackq->next;
3854 } else if (c == CTLVAR) {
3855 if ((*p++ & VSTYPE) != VSNORMAL)
3857 } else if (c == CTLENDVAR) {
3869 * Test whether a specialized variable is set.
3873 varisset(name, nulok)
3878 return backgndpid != -1;
3879 else if (*name == '@' || *name == '*') {
3880 if (*shellparam.p == NULL)
3886 for (av = shellparam.p; *av; av++)
3891 } else if (is_digit(*name)) {
3893 int num = atoi(name);
3895 if (num > shellparam.nparam)
3901 ap = shellparam.p[num - 1];
3903 if (nulok && (ap == NULL || *ap == '\0'))
3912 * Put a string on the stack.
3916 strtodest(p, syntax, quotes)
3922 if (quotes && syntax[(int) *p] == CCTL)
3923 STPUTC(CTLESC, expdest);
3924 STPUTC(*p++, expdest);
3931 * Add the value of a specialized variable to the stack string.
3935 varvalue(name, quoted, flags)
3947 int allow_split = flags & EXP_FULL;
3948 int quotes = flags & (EXP_FULL | EXP_CASE);
3950 syntax = quoted ? DQSYNTAX : BASESYNTAX;
3959 num = shellparam.nparam;
3964 expdest = cvtnum(num, expdest);
3967 for (i = 0 ; i < NOPTS ; i++) {
3969 STPUTC(optlist[i].letter, expdest);
3973 if (allow_split && quoted) {
3974 sep = 1 << CHAR_BIT;
3979 sep = ifsset() ? ifsval()[0] : ' ';
3981 sepq = syntax[(int) sep] == CCTL;
3984 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
3985 strtodest(p, syntax, quotes);
3988 STPUTC(CTLESC, expdest);
3989 STPUTC(sep, expdest);
3994 strtodest(arg0, syntax, quotes);
3998 if (num > 0 && num <= shellparam.nparam) {
3999 strtodest(shellparam.p[num - 1], syntax, quotes);
4008 * Record the fact that we have to scan this region of the
4009 * string for IFS characters.
4013 recordregion(start, end, nulonly)
4018 struct ifsregion *ifsp;
4020 if (ifslastp == NULL) {
4024 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
4026 ifslastp->next = ifsp;
4030 ifslastp->begoff = start;
4031 ifslastp->endoff = end;
4032 ifslastp->nulonly = nulonly;
4038 * Break the argument string into pieces based upon IFS and add the
4039 * strings to the argument list. The regions of the string to be
4040 * searched for IFS characters have been stored by recordregion.
4043 ifsbreakup(string, arglist)
4045 struct arglist *arglist;
4047 struct ifsregion *ifsp;
4052 const char *ifs, *realifs;
4060 realifs = ifsset() ? ifsval() : defifs;
4061 if (ifslastp != NULL) {
4064 p = string + ifsp->begoff;
4065 nulonly = ifsp->nulonly;
4066 ifs = nulonly ? nullstr : realifs;
4068 while (p < string + ifsp->endoff) {
4072 if (strchr(ifs, *p)) {
4074 ifsspc = (strchr(defifs, *p) != NULL);
4075 /* Ignore IFS whitespace at start */
4076 if (q == start && ifsspc) {
4082 sp = (struct strlist *)stalloc(sizeof *sp);
4084 *arglist->lastp = sp;
4085 arglist->lastp = &sp->next;
4089 if (p >= string + ifsp->endoff) {
4095 if (strchr(ifs, *p) == NULL ) {
4098 } else if (strchr(defifs, *p) == NULL) {
4114 } while ((ifsp = ifsp->next) != NULL);
4115 if (!(*start || (!ifsspc && start > string && nulonly))) {
4120 sp = (struct strlist *)stalloc(sizeof *sp);
4122 *arglist->lastp = sp;
4123 arglist->lastp = &sp->next;
4129 while (ifsfirst.next != NULL) {
4130 struct ifsregion *ifsp;
4132 ifsp = ifsfirst.next->next;
4133 ckfree(ifsfirst.next);
4134 ifsfirst.next = ifsp;
4138 ifsfirst.next = NULL;
4144 * Expand shell metacharacters. At this point, the only control characters
4145 * should be escapes. The results are stored in the list exparg.
4148 #if defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)
4150 expandmeta(str, flag)
4151 struct strlist *str;
4156 /* TODO - EXP_REDIR */
4161 p = preglob(str->text);
4163 switch (glob(p, GLOB_NOMAGIC, 0, &pglob)) {
4165 if (!(pglob.gl_flags & GLOB_MAGCHAR))
4176 *exparg.lastp = str;
4177 rmescapes(str->text);
4178 exparg.lastp = &str->next;
4180 default: /* GLOB_NOSPACE */
4181 error("Out of space");
4189 * Add the result of glob(3) to the list.
4194 const glob_t *pglob;
4196 char **p = pglob->gl_pathv;
4204 #else /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
4205 static char *expdir;
4209 expandmeta(str, flag)
4210 struct strlist *str;
4214 struct strlist **savelastp;
4217 /* TODO - EXP_REDIR */
4223 for (;;) { /* fast check for meta chars */
4224 if ((c = *p++) == '\0')
4226 if (c == '*' || c == '?' || c == '[' || c == '!')
4229 savelastp = exparg.lastp;
4231 if (expdir == NULL) {
4232 int i = strlen(str->text);
4233 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
4236 expmeta(expdir, str->text);
4240 if (exparg.lastp == savelastp) {
4245 *exparg.lastp = str;
4246 rmescapes(str->text);
4247 exparg.lastp = &str->next;
4249 *exparg.lastp = NULL;
4250 *savelastp = sp = expsort(*savelastp);
4251 while (sp->next != NULL)
4253 exparg.lastp = &sp->next;
4261 * Do metacharacter (i.e. *, ?, [...]) expansion.
4265 expmeta(enddir, name)
4283 for (p = name ; ; p++) {
4284 if (*p == '*' || *p == '?')
4286 else if (*p == '[') {
4291 while (*q == CTLQUOTEMARK)
4295 if (*q == '/' || *q == '\0')
4302 } else if (*p == '!' && p[1] == '!' && (p == name || p[-1] == '/')) {
4304 } else if (*p == '\0')
4306 else if (*p == CTLQUOTEMARK)
4308 else if (*p == CTLESC)
4316 if (metaflag == 0) { /* we've reached the end of the file name */
4317 if (enddir != expdir)
4319 for (p = name ; ; p++) {
4320 if (*p == CTLQUOTEMARK)
4328 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
4333 if (start != name) {
4336 while (*p == CTLQUOTEMARK)
4343 if (enddir == expdir) {
4345 } else if (enddir == expdir + 1 && *expdir == '/') {
4351 if ((dirp = opendir(cp)) == NULL)
4353 if (enddir != expdir)
4355 if (*endname == 0) {
4363 while (*p == CTLQUOTEMARK)
4369 while (! int_pending() && (dp = readdir(dirp)) != NULL) {
4370 if (dp->d_name[0] == '.' && ! matchdot)
4372 if (patmatch(start, dp->d_name, 0)) {
4374 scopy(dp->d_name, enddir);
4377 for (p = enddir, cp = dp->d_name;
4378 (*p++ = *cp++) != '\0';)
4381 expmeta(p, endname);
4389 #endif /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
4393 * Add a file name to the list.
4404 sp = (struct strlist *)stalloc(sizeof *sp);
4407 exparg.lastp = &sp->next;
4411 #if !(defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
4413 * Sort the results of file name expansion. It calculates the number of
4414 * strings to sort and then calls msort (short for merge sort) to do the
4418 static struct strlist *
4420 struct strlist *str;
4426 for (sp = str ; sp ; sp = sp->next)
4428 return msort(str, len);
4432 static struct strlist *
4434 struct strlist *list;
4437 struct strlist *p, *q = NULL;
4438 struct strlist **lpp;
4446 for (n = half ; --n >= 0 ; ) {
4450 q->next = NULL; /* terminate first half of list */
4451 q = msort(list, half); /* sort first half of list */
4452 p = msort(p, len - half); /* sort second half */
4455 if (strcmp(p->text, q->text) < 0) {
4458 if ((p = *lpp) == NULL) {
4465 if ((q = *lpp) == NULL) {
4478 * Returns true if the pattern matches the string.
4481 #if defined(__GLIBC__) && !defined(FNMATCH_BROKEN)
4483 patmatch(pattern, string, squoted)
4486 int squoted; /* string might have quote chars */
4491 p = preglob(pattern);
4492 q = squoted ? _rmescapes(string, RMESCAPE_ALLOC) : string;
4494 return !fnmatch(p, q, 0);
4499 patmatch2(pattern, string, squoted)
4502 int squoted; /* string might have quote chars */
4508 p = grabstackstr(expdest);
4509 res = patmatch(pattern, string, squoted);
4510 ungrabstackstr(p, expdest);
4515 patmatch(pattern, string, squoted)
4518 int squoted; /* string might have quote chars */
4521 if (pattern[0] == '!' && pattern[1] == '!')
4522 return 1 - pmatch(pattern + 2, string);
4525 return pmatch(pattern, string, squoted);
4530 pmatch(pattern, string, squoted)
4545 if (squoted && *q == CTLESC)
4553 if (squoted && *q == CTLESC)
4560 while (c == CTLQUOTEMARK || c == '*')
4562 if (c != CTLESC && c != CTLQUOTEMARK &&
4563 c != '?' && c != '*' && c != '[') {
4565 if (squoted && *q == CTLESC &&
4570 if (squoted && *q == CTLESC)
4576 if (pmatch(p, q, squoted))
4578 if (squoted && *q == CTLESC)
4580 } while (*q++ != '\0');
4591 while (*endp == CTLQUOTEMARK)
4594 goto dft; /* no matching ] */
4595 if (*endp == CTLESC)
4607 if (squoted && chr == CTLESC)
4613 if (c == CTLQUOTEMARK)
4617 if (*p == '-' && p[1] != ']') {
4619 while (*p == CTLQUOTEMARK)
4623 if (chr >= c && chr <= *p)
4630 } while ((c = *p++) != ']');
4631 if (found == invert)
4636 if (squoted && *q == CTLESC)
4653 * Remove any CTLESC characters from a string.
4656 #if defined(__GLIBC__) && !defined(FNMATCH_BROKEN)
4658 _rmescapes(str, flag)
4663 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
4665 p = strpbrk(str, qchars);
4671 if (flag & RMESCAPE_ALLOC) {
4672 size_t len = p - str;
4673 q = r = stalloc(strlen(p) + len + 1);
4676 q = mempcpy(q, str, len);
4678 memcpy(q, str, len);
4684 if (*p == CTLQUOTEMARK) {
4690 if (flag & RMESCAPE_GLOB && *p != '/') {
4707 while (*p != CTLESC && *p != CTLQUOTEMARK) {
4713 if (*p == CTLQUOTEMARK) {
4728 * See if a pattern matches in a case statement.
4732 casematch(pattern, val)
4733 union node *pattern;
4736 struct stackmark smark;
4740 setstackmark(&smark);
4741 argbackq = pattern->narg.backquote;
4742 STARTSTACKSTR(expdest);
4744 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
4745 STPUTC('\0', expdest);
4746 p = grabstackstr(expdest);
4747 result = patmatch(p, val, 0);
4748 popstackmark(&smark);
4763 CHECKSTRSPACE(32, buf);
4764 len = sprintf(buf, "%d", num);
4768 /* $NetBSD: histedit.c,v 1.25 2001/02/04 19:52:06 christos Exp $ */
4771 * Editline and history functions (and glue).
4773 static int histcmd(argc, argv)
4777 error("not compiled with history support");
4783 * This file was generated by the mkinit program.
4786 extern void rmaliases __P((void));
4788 extern int loopnest; /* current loop nesting level */
4790 extern void deletefuncs __P((void));
4793 struct strpush *prev; /* preceding string on stack */
4796 struct alias *ap; /* if push was associated with an alias */
4797 char *string; /* remember the string since it may change */
4801 struct parsefile *prev; /* preceding file on stack */
4802 int linno; /* current line */
4803 int fd; /* file descriptor (or -1 if string) */
4804 int nleft; /* number of chars left in this line */
4805 int lleft; /* number of chars left in this buffer */
4806 char *nextc; /* next char in buffer */
4807 char *buf; /* input buffer */
4808 struct strpush *strpush; /* for pushing strings at this level */
4809 struct strpush basestrpush; /* so pushing one is fast */
4812 extern int parselleft; /* copy of parsefile->lleft */
4813 extern struct parsefile basepf; /* top level input file */
4814 extern char basebuf[BUFSIZ]; /* buffer for top level input file */
4816 extern short backgndpid; /* pid of last background process */
4819 extern int tokpushback; /* last token pushed back */
4820 extern int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */
4823 struct redirtab *next;
4827 extern struct redirtab *redirlist;
4829 extern char sigmode[NSIG - 1]; /* current value of signal */
4831 extern char **environ;
4836 * Initialization code.
4849 basepf.nextc = basepf.buf = basebuf;
4852 /* from output.c: */
4854 #ifdef USE_GLIBC_STDIO
4865 for (envp = environ ; *envp ; envp++) {
4866 if (strchr(*envp, '=')) {
4867 setvareq(*envp, VEXPORT|VTEXTFIXED);
4871 fmtstr(ppid, sizeof(ppid), "%d", (int) getppid());
4872 setvar("PPID", ppid, 0);
4879 * This routine is called when an error or an interrupt occurs in an
4880 * interactive shell and control is returned to the main command loop.
4895 if (exception != EXSHELLPROC)
4896 parselleft = parsenleft = 0; /* clear input buffer */
4900 /* from parser.c: */
4913 /* from output.c: */
4917 #ifdef USE_GLIBC_STDIO
4918 if (memout.stream != NULL)
4921 if (memout.buf != NULL) {
4931 * This routine is called to initialize the shell to run a shell procedure.
4960 /* from options.c: */
4964 for (i = 0; i < NOPTS; i++)
4980 for (sm = sigmode ; sm < sigmode + NSIG - 1; sm++) {
4991 /* $NetBSD: input.c,v 1.35 2001/02/04 19:52:06 christos Exp $ */
4994 * This file implements the input routines used by the parser.
4997 #ifdef BB_FEATURE_COMMAND_EDITING
4998 unsigned int shell_context;
4999 static const char * cmdedit_prompt;
5000 static inline void putprompt(const char *s) {
5004 static inline void putprompt(const char *s) {
5009 #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
5011 static int plinno = 1; /* input line number */
5012 static int parsenleft; /* copy of parsefile->nleft */
5013 static int parselleft; /* copy of parsefile->lleft */
5014 static char *parsenextc; /* copy of parsefile->nextc */
5015 struct parsefile basepf; /* top level input file */
5016 static char basebuf[BUFSIZ]; /* buffer for top level input file */
5017 struct parsefile *parsefile = &basepf; /* current input file */
5018 static int whichprompt; /* 1 == PS1, 2 == PS2 */
5020 static void pushfile __P((void));
5021 static int preadfd __P((void));
5029 basepf.nextc = basepf.buf = basebuf;
5033 if (exception != EXSHELLPROC)
5034 parselleft = parsenleft = 0; /* clear input buffer */
5041 * Read a line from the script.
5053 while (--nleft > 0) {
5070 * Read a character from the script, returning PEOF on end of file.
5071 * Nul characters in the input are silently discarded.
5077 return pgetc_macro();
5082 * Same as pgetc(), but ignores PEOA.
5091 } while (c == PEOA);
5100 char *buf = parsefile->buf;
5104 #ifdef BB_FEATURE_COMMAND_EDITING
5107 nr = read(parsefile->fd, buf, BUFSIZ - 1);
5110 cmdedit_read_input((char*)cmdedit_prompt, buf);
5112 } while (nr <=0 || shell_context);
5113 cmdedit_terminate();
5117 nr = read(parsefile->fd, buf, BUFSIZ - 1);
5123 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
5124 int flags = fcntl(0, F_GETFL, 0);
5125 if (flags >= 0 && flags & O_NONBLOCK) {
5126 flags &=~ O_NONBLOCK;
5127 if (fcntl(0, F_SETFL, flags) >= 0) {
5128 out2str("sh: turning off NDELAY mode\n");
5138 * Refill the input buffer and return the next input character:
5140 * 1) If a string was pushed back on the input, pop it;
5141 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
5142 * from a string so we can't refill the buffer, return EOF.
5143 * 3) If the is more stuff in this buffer, use it else call read to fill it.
5144 * 4) Process input up to the next newline, deleting nul characters.
5154 while (parsefile->strpush) {
5156 parsenleft == -1 && parsefile->strpush->ap &&
5157 parsenextc[-1] != ' ' && parsenextc[-1] != '\t'
5162 if (--parsenleft >= 0)
5163 return (*parsenextc++);
5165 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
5173 if (parselleft <= 0) {
5174 if ((parselleft = preadfd()) <= 0) {
5175 parselleft = parsenleft = EOF_NLEFT;
5182 /* delete nul characters */
5183 for (more = 1; more;) {
5191 parsenleft = q - parsenextc;
5192 more = 0; /* Stop processing here */
5198 if (--parselleft <= 0 && more) {
5199 parsenleft = q - parsenextc - 1;
5210 out2str(parsenextc);
5218 return *parsenextc++;
5222 * Undo the last call to pgetc. Only one character may be pushed back.
5223 * PEOF may be pushed back.
5233 * Push a string back onto the input at this current parsefile level.
5234 * We handle aliases this way.
5237 pushstring(s, len, ap)
5245 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
5246 if (parsefile->strpush) {
5247 sp = ckmalloc(sizeof (struct strpush));
5248 sp->prev = parsefile->strpush;
5249 parsefile->strpush = sp;
5251 sp = parsefile->strpush = &(parsefile->basestrpush);
5252 sp->prevstring = parsenextc;
5253 sp->prevnleft = parsenleft;
5254 sp->ap = (struct alias *)ap;
5256 ((struct alias *)ap)->flag |= ALIASINUSE;
5267 struct strpush *sp = parsefile->strpush;
5271 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
5276 if (sp->string != sp->ap->val) {
5279 sp->ap->flag &= ~ALIASINUSE;
5280 if (sp->ap->flag & ALIASDEAD) {
5281 unalias(sp->ap->name);
5284 parsenextc = sp->prevstring;
5285 parsenleft = sp->prevnleft;
5286 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
5287 parsefile->strpush = sp->prev;
5288 if (sp != &(parsefile->basestrpush))
5294 * Set the input to take input from a file. If push is set, push the
5295 * old input onto the stack first.
5299 setinputfile(fname, push)
5307 if ((fd = open(fname, O_RDONLY)) < 0)
5308 error("Can't open %s", fname);
5310 myfileno2 = dup_as_newfd(fd, 10);
5313 error("Out of file descriptors");
5316 setinputfd(fd, push);
5322 * Like setinputfile, but takes an open file descriptor. Call this with
5327 setinputfd(fd, push)
5330 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
5336 while (parsefile->strpush)
5340 if (parsefile->buf == NULL)
5341 parsefile->buf = ckmalloc(BUFSIZ);
5342 parselleft = parsenleft = 0;
5348 * Like setinputfile, but takes input from a string.
5352 setinputstring(string)
5357 parsenextc = string;
5358 parsenleft = strlen(string);
5359 parsefile->buf = NULL;
5367 * To handle the "." command, a stack of input files is used. Pushfile
5368 * adds a new entry to the stack and popfile restores the previous level.
5373 struct parsefile *pf;
5375 parsefile->nleft = parsenleft;
5376 parsefile->lleft = parselleft;
5377 parsefile->nextc = parsenextc;
5378 parsefile->linno = plinno;
5379 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
5380 pf->prev = parsefile;
5383 pf->basestrpush.prev = NULL;
5390 struct parsefile *pf = parsefile;
5399 parsefile = pf->prev;
5401 parsenleft = parsefile->nleft;
5402 parselleft = parsefile->lleft;
5403 parsenextc = parsefile->nextc;
5404 plinno = parsefile->linno;
5410 * Return to top level.
5415 while (parsefile != &basepf)
5422 * Close the file(s) that the shell is reading commands from. Called
5423 * after a fork is done.
5429 if (parsefile->fd > 0) {
5430 close(parsefile->fd);
5434 /* $NetBSD: jobs.c,v 1.36 2000/05/22 10:18:47 elric Exp $ */
5437 struct job *jobtab; /* array of jobs */
5438 static int njobs; /* size of array */
5439 short backgndpid = -1; /* pid of last background process */
5441 static int initialpgrp; /* pgrp of shell on invocation */
5442 short curjob; /* current job */
5444 static int intreceived;
5446 static void restartjob __P((struct job *));
5447 static void freejob __P((struct job *));
5448 static struct job *getjob __P((char *));
5449 static int dowait __P((int, struct job *));
5451 static int onsigchild __P((void));
5453 static int waitproc __P((int, int *));
5454 static void cmdtxt __P((union node *));
5455 static void cmdputs __P((const char *));
5456 static void waitonint(int);
5461 * Turn job control on and off.
5463 * Note: This code assumes that the third arg to ioctl is a character
5464 * pointer, which is true on Berkeley systems but not System V. Since
5465 * System V doesn't have job control yet, this isn't a problem now.
5470 static void setjobctl(int enable)
5472 #ifdef OLD_TTY_DRIVER
5476 if (enable == jobctl || rootshell == 0)
5479 do { /* while we are in the background */
5480 #ifdef OLD_TTY_DRIVER
5481 if (ioctl(fileno2, TIOCGPGRP, (char *)&initialpgrp) < 0) {
5483 initialpgrp = tcgetpgrp(fileno2);
5484 if (initialpgrp < 0) {
5486 out2str("sh: can't access tty; job cenabletrol turned off\n");
5490 if (initialpgrp == -1)
5491 initialpgrp = getpgrp();
5492 else if (initialpgrp != getpgrp()) {
5493 killpg(initialpgrp, SIGTTIN);
5497 #ifdef OLD_TTY_DRIVER
5498 if (ioctl(fileno2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) {
5499 out2str("sh: need new tty driver to run job cenabletrol; job cenabletrol turned off\n");
5507 setpgid(0, rootpid);
5508 #ifdef OLD_TTY_DRIVER
5509 ioctl(fileno2, TIOCSPGRP, (char *)&rootpid);
5511 tcsetpgrp(fileno2, rootpid);
5513 } else { /* turning job cenabletrol off */
5514 setpgid(0, initialpgrp);
5515 #ifdef OLD_TTY_DRIVER
5516 ioctl(fileno2, TIOCSPGRP, (char *)&initialpgrp);
5518 tcsetpgrp(fileno2, initialpgrp);
5542 /* This file was automatically created by ./mksignames.
5543 Do not edit. Edit support/mksignames.c instead. */
5545 /* A translation list so we can be polite to our users. */
5546 static char *signal_names[NSIG + 2] = {
5632 "Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
5633 "kill -l [exitstatus]"
5637 if (*argv[1] == '-') {
5638 signo = decode_signal(argv[1] + 1, 1);
5642 while ((c = nextopt("ls:")) != '\0')
5648 signo = decode_signal(optionarg, 1);
5651 "invalid signal number or name: %s",
5659 "nextopt returned character code 0%o", c);
5666 if (!list && signo < 0)
5669 if ((signo < 0 || !*argptr) ^ list) {
5676 for (i = 1; i < NSIG; i++) {
5677 out1fmt(snlfmt, signal_names[i] + 3);
5681 signo = atoi(*argptr);
5684 if (0 < signo && signo < NSIG)
5685 out1fmt(snlfmt, signal_names[signo] + 3);
5687 error("invalid signal number or exit status: %s",
5693 if (**argptr == '%') {
5694 jp = getjob(*argptr);
5695 if (jp->jobctl == 0)
5696 error("job %s not created under job control",
5698 pid = -jp->ps[0].pid;
5700 pid = atoi(*argptr);
5701 if (kill(pid, signo) != 0)
5702 error("%s: %s", *argptr, strerror(errno));
5703 } while (*++argptr);
5717 jp = getjob(argv[1]);
5718 if (jp->jobctl == 0)
5719 error("job not created under job control");
5720 pgrp = jp->ps[0].pid;
5721 #ifdef OLD_TTY_DRIVER
5722 ioctl(fileno2, TIOCSPGRP, (char *)&pgrp);
5724 tcsetpgrp(fileno2, pgrp);
5728 status = waitforjob(jp);
5742 jp = getjob(*++argv);
5743 if (jp->jobctl == 0)
5744 error("job not created under job control");
5746 } while (--argc > 1);
5755 struct procstat *ps;
5758 if (jp->state == JOBDONE)
5761 killpg(jp->ps[0].pid, SIGCONT);
5762 for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
5763 if (WIFSTOPPED(ps->status)) {
5784 * Print a list of jobs. If "change" is nonzero, only print jobs whose
5785 * statuses have changed since the last call to showjobs.
5787 * If the shell is interrupted in the process of creating a job, the
5788 * result may be a job structure containing zero processes. Such structures
5789 * will be freed here.
5800 struct procstat *ps;
5804 TRACE(("showjobs(%d) called\n", change));
5805 while (dowait(0, (struct job *)NULL) > 0);
5806 for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
5809 if (jp->nprocs == 0) {
5813 if (change && ! jp->changed)
5815 procno = jp->nprocs;
5816 for (ps = jp->ps ; ; ps++) { /* for each process */
5818 fmtstr(s, 64, "[%d] %ld ", jobno,
5821 fmtstr(s, 64, " %ld ",
5826 if (ps->status == -1) {
5827 /* don't print anything */
5828 } else if (WIFEXITED(ps->status)) {
5829 fmtstr(s, 64, "Exit %d",
5830 WEXITSTATUS(ps->status));
5833 if (WIFSTOPPED(ps->status))
5834 i = WSTOPSIG(ps->status);
5835 else /* WIFSIGNALED(ps->status) */
5837 i = WTERMSIG(ps->status);
5838 if ((i & 0x7F) < NSIG && sys_siglist[i & 0x7F])
5839 scopy(sys_siglist[i & 0x7F], s);
5841 fmtstr(s, 64, "Signal %d", i & 0x7F);
5842 if (WCOREDUMP(ps->status))
5843 strcat(s, " (core dumped)");
5848 "%*c%s\n", 30 - col >= 0 ? 30 - col : 0, ' ',
5855 if (jp->state == JOBDONE) {
5863 * Mark a job structure as unused.
5870 struct procstat *ps;
5874 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
5875 if (ps->cmd != nullstr)
5878 if (jp->ps != &jp->ps0)
5882 if (curjob == jp - jobtab + 1)
5901 job = getjob(*++argv);
5905 for (;;) { /* loop until process terminated or stopped */
5908 status = job->ps[job->nprocs - 1].status;
5914 if (WIFEXITED(status))
5915 retval = WEXITSTATUS(status);
5917 else if (WIFSTOPPED(status))
5918 retval = WSTOPSIG(status) + 128;
5921 /* XXX: limits number of signals */
5922 retval = WTERMSIG(status) + 128;
5927 for (jp = jobtab ; ; jp++) {
5928 if (jp >= jobtab + njobs) { /* no running procs */
5931 if (jp->used && jp->state == 0)
5935 if (dowait(2, 0) < 0 && errno == EINTR) {
5944 * Convert a job name to a job structure.
5959 if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0)
5960 error("No current job");
5961 return &jobtab[jobno - 1];
5963 error("No current job");
5965 } else if (name[0] == '%') {
5966 if (is_digit(name[1])) {
5967 jobno = number(name + 1);
5968 if (jobno > 0 && jobno <= njobs
5969 && jobtab[jobno - 1].used != 0)
5970 return &jobtab[jobno - 1];
5972 } else if (name[1] == '%' && name[2] == '\0') {
5976 struct job *found = NULL;
5977 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
5978 if (jp->used && jp->nprocs > 0
5979 && prefix(name + 1, jp->ps[0].cmd)) {
5981 error("%s: ambiguous", name);
5988 } else if (is_number(name)) {
5990 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
5991 if (jp->used && jp->nprocs > 0
5992 && jp->ps[jp->nprocs - 1].pid == pid)
5996 error("No such job: %s", name);
6003 * Return a new job structure,
6007 makejob(node, nprocs)
6014 for (i = njobs, jp = jobtab ; ; jp++) {
6018 jobtab = ckmalloc(4 * sizeof jobtab[0]);
6020 jp = ckmalloc((njobs + 4) * sizeof jobtab[0]);
6021 memcpy(jp, jobtab, njobs * sizeof jp[0]);
6022 /* Relocate `ps' pointers */
6023 for (i = 0; i < njobs; i++)
6024 if (jp[i].ps == &jobtab[i].ps0)
6025 jp[i].ps = &jp[i].ps0;
6029 jp = jobtab + njobs;
6030 for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0);
6043 jp->jobctl = jobctl;
6046 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
6051 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
6058 * Fork of a subshell. If we are doing job control, give the subshell its
6059 * own process group. Jp is a job structure that the job is to be added to.
6060 * N is the command that will be evaluated by the child. Both jp and n may
6061 * be NULL. The mode parameter can be one of the following:
6062 * FORK_FG - Fork off a foreground process.
6063 * FORK_BG - Fork off a background process.
6064 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
6065 * process group even if job control is on.
6067 * When job control is turned off, background processes have their standard
6068 * input redirected to /dev/null (except for the second and later processes
6073 forkshell(jp, n, mode)
6080 const char *devnull = _PATH_DEVNULL;
6081 const char *nullerr = "Can't open %s";
6083 TRACE(("forkshell(%%%d, 0x%lx, %d) called\n", jp - jobtab, (long)n,
6088 TRACE(("Fork failed, errno=%d\n", errno));
6090 error("Cannot fork");
6097 TRACE(("Child shell %d\n", getpid()));
6098 wasroot = rootshell;
6104 jobctl = 0; /* do job control only in root shell */
6105 if (wasroot && mode != FORK_NOJOB && mflag) {
6106 if (jp == NULL || jp->nprocs == 0)
6109 pgrp = jp->ps[0].pid;
6111 if (mode == FORK_FG) {
6112 /*** this causes superfluous TIOCSPGRPS ***/
6113 #ifdef OLD_TTY_DRIVER
6114 if (ioctl(fileno2, TIOCSPGRP, (char *)&pgrp) < 0)
6115 error("TIOCSPGRP failed, errno=%d", errno);
6117 if (tcsetpgrp(fileno2, pgrp) < 0)
6118 error("tcsetpgrp failed, errno=%d", errno);
6123 } else if (mode == FORK_BG) {
6126 if ((jp == NULL || jp->nprocs == 0) &&
6127 ! fd0_redirected_p ()) {
6129 if (open(devnull, O_RDONLY) != 0)
6130 error(nullerr, devnull);
6134 if (mode == FORK_BG) {
6137 if ((jp == NULL || jp->nprocs == 0) &&
6138 ! fd0_redirected_p ()) {
6140 if (open(devnull, O_RDONLY) != 0)
6141 error(nullerr, devnull);
6145 for (i = njobs, p = jobtab ; --i >= 0 ; p++)
6148 if (wasroot && iflag) {
6155 if (rootshell && mode != FORK_NOJOB && mflag) {
6156 if (jp == NULL || jp->nprocs == 0)
6159 pgrp = jp->ps[0].pid;
6162 if (mode == FORK_BG)
6163 backgndpid = pid; /* set $! */
6165 struct procstat *ps = &jp->ps[jp->nprocs++];
6169 if (iflag && rootshell && n)
6170 ps->cmd = commandtext(n);
6173 TRACE(("In parent shell: child = %d\n", pid));
6180 * Wait for job to finish.
6182 * Under job control we have the problem that while a child process is
6183 * running interrupts generated by the user are sent to the child but not
6184 * to the shell. This means that an infinite loop started by an inter-
6185 * active user may be hard to kill. With job control turned off, an
6186 * interactive user may place an interactive program inside a loop. If
6187 * the interactive program catches interrupts, the user doesn't want
6188 * these interrupts to also abort the loop. The approach we take here
6189 * is to have the shell ignore interrupt signals while waiting for a
6190 * forground process to terminate, and then send itself an interrupt
6191 * signal if the child process was terminated by an interrupt signal.
6192 * Unfortunately, some programs want to do a bit of cleanup and then
6193 * exit on interrupt; unless these processes terminate themselves by
6194 * sending a signal to themselves (instead of calling exit) they will
6195 * confuse this approach.
6203 int mypgrp = getpgrp();
6207 struct sigaction act, oact;
6216 sigaction(SIGINT, 0, &act);
6217 act.sa_handler = waitonint;
6218 sigaction(SIGINT, &act, &oact);
6220 TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
6221 while (jp->state == 0) {
6229 sigaction(SIGINT, &oact, 0);
6230 if (intreceived && trap[SIGINT]) kill(getpid(), SIGINT);
6234 #ifdef OLD_TTY_DRIVER
6235 if (ioctl(fileno2, TIOCSPGRP, (char *)&mypgrp) < 0)
6236 error("TIOCSPGRP failed, errno=%d\n", errno);
6238 if (tcsetpgrp(fileno2, mypgrp) < 0)
6239 error("tcsetpgrp failed, errno=%d\n", errno);
6242 if (jp->state == JOBSTOPPED)
6243 curjob = jp - jobtab + 1;
6245 status = jp->ps[jp->nprocs - 1].status;
6246 /* convert to 8 bits */
6247 if (WIFEXITED(status))
6248 st = WEXITSTATUS(status);
6250 else if (WIFSTOPPED(status))
6251 st = WSTOPSIG(status) + 128;
6254 st = WTERMSIG(status) + 128;
6258 * This is truly gross.
6259 * If we're doing job control, then we did a TIOCSPGRP which
6260 * caused us (the shell) to no longer be in the controlling
6261 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
6262 * intuit from the subprocess exit status whether a SIGINT
6263 * occured, and if so interrupt ourselves. Yuck. - mycroft
6265 if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
6269 if (! JOBS || jp->state == JOBDONE)
6278 * Wait for a process to terminate.
6288 struct procstat *sp;
6290 struct job *thisjob;
6296 TRACE(("dowait(%d) called\n", block));
6298 pid = waitproc(block, &status);
6299 TRACE(("wait returns %d, status=%d\n", pid, status));
6300 } while (!(block & 2) && pid == -1 && errno == EINTR);
6305 for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
6309 for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
6312 if (sp->pid == pid) {
6313 TRACE(("Changing status of proc %d from 0x%x to 0x%x\n", pid, sp->status, status));
6314 sp->status = status;
6317 if (sp->status == -1)
6319 else if (WIFSTOPPED(sp->status))
6322 if (stopped) { /* stopped or done */
6323 int state = done? JOBDONE : JOBSTOPPED;
6324 if (jp->state != state) {
6325 TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
6328 if (done && curjob == jp - jobtab + 1)
6329 curjob = 0; /* no current job */
6336 if (! rootshell || ! iflag || (job && thisjob == job)) {
6337 core = WCOREDUMP(status);
6339 if (WIFSTOPPED(status)) sig = WSTOPSIG(status);
6342 if (WIFEXITED(status)) sig = 0;
6343 else sig = WTERMSIG(status);
6345 if (sig != 0 && sig != SIGINT && sig != SIGPIPE) {
6347 outfmt(out2, "%d: ", pid);
6349 if (sig == SIGTSTP && rootshell && iflag)
6350 outfmt(out2, "%%%ld ",
6351 (long)(job - jobtab + 1));
6353 if (sig < NSIG && sys_siglist[sig])
6354 out2str(sys_siglist[sig]);
6356 outfmt(out2, "Signal %d", sig);
6358 out2str(" - core dumped");
6364 TRACE(("Not printing status: status=%d, sig=%d\n",
6368 TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell, job));
6370 thisjob->changed = 1;
6378 * Do a wait system call. If job control is compiled in, we accept
6379 * stopped processes. If block is zero, we return a value of zero
6380 * rather than blocking.
6382 * System V doesn't have a non-blocking wait system call. It does
6383 * have a SIGCLD signal that is sent to a process when one of it's
6384 * children dies. The obvious way to use SIGCLD would be to install
6385 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
6386 * was received, and have waitproc bump another counter when it got
6387 * the status of a process. Waitproc would then know that a wait
6388 * system call would not block if the two counters were different.
6389 * This approach doesn't work because if a process has children that
6390 * have not been waited for, System V will send it a SIGCLD when it
6391 * installs a signal handler for SIGCLD. What this means is that when
6392 * a child exits, the shell will be sent SIGCLD signals continuously
6393 * until is runs out of stack space, unless it does a wait call before
6394 * restoring the signal handler. The code below takes advantage of
6395 * this (mis)feature by installing a signal handler for SIGCLD and
6396 * then checking to see whether it was called. If there are any
6397 * children to be waited for, it will be.
6399 * If neither SYSV nor BSD is defined, we don't implement nonblocking
6400 * waits at all. In this case, the user will not be informed when
6401 * a background process until the next time she runs a real program
6402 * (as opposed to running a builtin command or just typing return),
6403 * and the jobs command may give out of date information.
6407 static int gotsigchild;
6409 static int onsigchild() {
6416 waitproc(block, status)
6430 return wait3(status, flags, (struct rusage *)NULL);
6437 save = signal(SIGCLD, onsigchild);
6438 signal(SIGCLD, save);
6439 if (gotsigchild == 0)
6442 return wait(status);
6446 return wait(status);
6452 * return 1 if there are stopped jobs, otherwise 0
6454 static int job_warning = 0;
6463 for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
6466 if (jp->state == JOBSTOPPED) {
6467 out2str("You have stopped jobs.\n");
6477 * Return a string identifying a command (to be printed by the
6481 static char *cmdnextc;
6482 static int cmdnleft;
6483 #define MAXCMDTEXT 200
6491 cmdnextc = name = ckmalloc(MAXCMDTEXT);
6492 cmdnleft = MAXCMDTEXT - 4;
6504 struct nodelist *lp;
6513 cmdtxt(n->nbinary.ch1);
6515 cmdtxt(n->nbinary.ch2);
6518 cmdtxt(n->nbinary.ch1);
6520 cmdtxt(n->nbinary.ch2);
6523 cmdtxt(n->nbinary.ch1);
6525 cmdtxt(n->nbinary.ch2);
6528 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
6536 cmdtxt(n->nredir.n);
6541 cmdtxt(n->nredir.n);
6545 cmdtxt(n->nif.test);
6547 cmdtxt(n->nif.ifpart);
6556 cmdtxt(n->nbinary.ch1);
6558 cmdtxt(n->nbinary.ch2);
6563 cmdputs(n->nfor.var);
6568 cmdputs(n->ncase.expr->narg.text);
6572 cmdputs(n->narg.text);
6576 for (np = n->ncmd.args ; np ; np = np->narg.next) {
6581 for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
6587 cmdputs(n->narg.text);
6590 p = ">"; i = 1; goto redir;
6592 p = ">>"; i = 1; goto redir;
6594 p = ">&"; i = 1; goto redir;
6596 p = ">|"; i = 1; goto redir;
6598 p = "<"; i = 0; goto redir;
6600 p = "<&"; i = 0; goto redir;
6602 p = "<>"; i = 0; goto redir;
6604 if (n->nfile.fd != i) {
6605 s[0] = n->nfile.fd + '0';
6610 if (n->type == NTOFD || n->type == NFROMFD) {
6611 s[0] = n->ndup.dupfd + '0';
6615 cmdtxt(n->nfile.fname);
6643 while ((c = *p++) != '\0') {
6646 else if (c == CTLVAR) {
6651 } else if (c == '=' && subtype != 0) {
6652 *q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL];
6654 } else if (c == CTLENDVAR) {
6656 } else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE)
6657 cmdnleft++; /* ignore it */
6660 if (--cmdnleft <= 0) {
6670 static void waitonint(int sig) {
6674 /* $NetBSD: mail.c,v 1.14 2000/07/03 03:26:19 matt Exp $ */
6677 * Routines to check for mail. (Perhaps make part of main.c?)
6681 #define MAXMBOXES 10
6684 static int nmboxes; /* number of mailboxes */
6685 static time_t mailtime[MAXMBOXES]; /* times of mailboxes */
6690 * Print appropriate message(s) if mail has arrived. If the argument is
6691 * nozero, then the value of MAIL has changed, so we just update the
6703 struct stackmark smark;
6710 setstackmark(&smark);
6711 mpath = mpathset()? mpathval() : mailval();
6712 for (i = 0 ; i < nmboxes ; i++) {
6713 p = padvance(&mpath, nullstr);
6718 for (q = p ; *q ; q++);
6723 q[-1] = '\0'; /* delete trailing '/' */
6724 #ifdef notdef /* this is what the System V shell claims to do (it lies) */
6725 if (stat(p, &statb) < 0)
6727 if (statb.st_mtime > mailtime[i] && ! silent) {
6730 pathopt? pathopt : "you have mail"
6733 mailtime[i] = statb.st_mtime;
6734 #else /* this is what it should do */
6735 if (stat(p, &statb) < 0)
6737 if (statb.st_size > mailtime[i] && ! silent) {
6740 pathopt? pathopt : "you have mail"
6743 mailtime[i] = statb.st_size;
6747 popstackmark(&smark);
6749 /* $NetBSD: main.c,v 1.40 2001/02/04 19:52:06 christos Exp $ */
6755 static int rootshell;
6757 short profile_buf[16384];
6761 static void read_profile __P((const char *));
6762 static char *find_dot_file __P((char *));
6763 int shell_main __P((int, char **));
6765 extern int oexitstatus;
6767 * Main routine. We initialize things, parse the arguments, execute
6768 * profiles if we're a login shell, and then call cmdloop to execute
6769 * commands. The setjmp call sets up the location to jump to when an
6770 * exception occurs. When an exception occurs the variable "state"
6771 * is used to figure out how far we had gotten.
6775 shell_main(argc, argv)
6779 struct jmploc jmploc;
6780 struct stackmark smark;
6784 DOTCMD = find_builtin(".");
6785 BLTINCMD = find_builtin("builtin");
6786 COMMANDCMD = find_builtin("command");
6787 EXECCMD = find_builtin("exec");
6788 EVALCMD = find_builtin("eval");
6791 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
6793 #if defined(linux) || defined(__GNU__)
6794 signal(SIGCHLD, SIG_DFL);
6797 if (setjmp(jmploc.loc)) {
6800 * When a shell procedure is executed, we raise the
6801 * exception EXSHELLPROC to clean up before executing
6802 * the shell procedure.
6804 switch (exception) {
6813 exitstatus = exerrno;
6824 if (exception != EXSHELLPROC) {
6825 if (state == 0 || iflag == 0 || ! rootshell)
6826 exitshell(exitstatus);
6829 if (exception == EXINT
6831 && (! attyset() || equal(termval(), "emacs"))
6839 popstackmark(&smark);
6840 FORCEINTON; /* enable interrupts */
6843 else if (state == 2)
6845 else if (state == 3)
6853 trputs("Shell args: "); trargs(argv);
6858 setstackmark(&smark);
6859 procargs(argc, argv);
6860 if (argv[0] && argv[0][0] == '-') {
6862 read_profile("/etc/profile");
6865 read_profile(".profile");
6870 if (getuid() == geteuid() && getgid() == getegid()) {
6872 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
6874 read_profile(shinit);
6881 if (sflag == 0 || minusc) {
6882 static int sigs[] = {
6883 SIGINT, SIGQUIT, SIGHUP,
6889 #define SIGSSIZE (sizeof(sigs)/sizeof(sigs[0]))
6892 for (i = 0; i < SIGSSIZE; i++)
6897 evalstring(minusc, 0);
6899 if (sflag || minusc == NULL) {
6900 state4: /* XXX ??? - why isn't this before the "if" statement */
6906 exitshell(exitstatus);
6912 * Read and execute commands. "Top" is nonzero for the top level command
6913 * loop; it turns on prompting if the shell is interactive.
6921 struct stackmark smark;
6925 TRACE(("cmdloop(%d) called\n", top));
6926 setstackmark(&smark);
6937 n = parsecmd(inter);
6938 /* showtree(n); DEBUG */
6940 if (!top || numeof >= 50)
6942 if (!stoppedjobs()) {
6945 out2str("\nUse \"exit\" to leave shell.\n");
6948 } else if (n != NULL && nflag == 0) {
6949 job_warning = (job_warning == 2) ? 1 : 0;
6953 popstackmark(&smark);
6954 setstackmark(&smark);
6955 if (evalskip == SKIPFILE) {
6960 popstackmark(&smark);
6966 * Read /etc/profile or .profile. Return on error.
6978 if ((fd = open(name, O_RDONLY)) >= 0)
6983 /* -q turns off -x and -v just when executing init files */
6986 xflag = 0, xflag_set = 1;
6988 vflag = 0, vflag_set = 1;
7003 * Read a file containing shell functions.
7013 if ((fd = open(name, O_RDONLY)) >= 0)
7016 error("Can't open %s", name);
7025 * Take commands from a file. To be compatable we should do a path
7026 * search for the file, which is necessary to find sub-commands.
7031 find_dot_file(mybasename)
7035 const char *path = pathval();
7038 /* don't try this for absolute or relative paths */
7039 if (strchr(mybasename, '/'))
7042 while ((fullname = padvance(&path, mybasename)) != NULL) {
7043 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
7045 * Don't bother freeing here, since it will
7046 * be freed by the caller.
7050 stunalloc(fullname);
7053 /* not found in the PATH */
7054 error("%s: not found", mybasename);
7066 for (sp = cmdenviron; sp ; sp = sp->next)
7067 setvareq(savestr(sp->text), VSTRFIXED|VTEXTFIXED);
7069 if (argc >= 2) { /* That's what SVR2 does */
7071 struct stackmark smark;
7073 setstackmark(&smark);
7074 fullname = find_dot_file(argv[1]);
7075 setinputfile(fullname, 1);
7076 commandname = fullname;
7079 popstackmark(&smark);
7093 exitstatus = number(argv[1]);
7095 exitstatus = oexitstatus;
7096 exitshell(exitstatus);
7099 /* $NetBSD: memalloc.c,v 1.23 2000/11/01 19:56:01 christos Exp $ */
7102 * Parse trees for commands are allocated in lifo order, so we use a stack
7103 * to make this more efficient, and also to avoid all sorts of exception
7104 * handling code to handle interrupts in the middle of a parse.
7106 * The size 504 was chosen because the Ultrix malloc handles that size
7110 #define MINSIZE 504 /* minimum size of a block */
7113 struct stack_block {
7114 struct stack_block *prev;
7115 char space[MINSIZE];
7118 struct stack_block stackbase;
7119 struct stack_block *stackp = &stackbase;
7120 struct stackmark *markp;
7121 static char *stacknxt = stackbase.space;
7122 static int stacknleft = MINSIZE;
7123 static int sstrnleft;
7124 static int herefd = -1;
7134 nbytes = ALIGN(nbytes);
7135 if (nbytes > stacknleft) {
7137 struct stack_block *sp;
7140 if (blocksize < MINSIZE)
7141 blocksize = MINSIZE;
7143 sp = ckmalloc(sizeof(struct stack_block) - MINSIZE + blocksize);
7145 stacknxt = sp->space;
7146 stacknleft = blocksize;
7152 stacknleft -= nbytes;
7162 if (p == NULL) { /*DEBUG */
7163 write(2, "stunalloc\n", 10);
7167 if (!(stacknxt >= (char *)p && (char *)p >= stackp->space)) {
7170 stacknleft += stacknxt - (char *)p;
7178 struct stackmark *mark;
7180 mark->stackp = stackp;
7181 mark->stacknxt = stacknxt;
7182 mark->stacknleft = stacknleft;
7183 mark->marknext = markp;
7190 struct stackmark *mark;
7192 struct stack_block *sp;
7195 markp = mark->marknext;
7196 while (stackp != mark->stackp) {
7201 stacknxt = mark->stacknxt;
7202 stacknleft = mark->stacknleft;
7208 * When the parser reads in a string, it wants to stick the string on the
7209 * stack and only adjust the stack pointer when it knows how big the
7210 * string is. Stackblock (defined in stack.h) returns a pointer to a block
7211 * of space on top of the stack and stackblocklen returns the length of
7212 * this block. Growstackblock will grow this space by at least one byte,
7213 * possibly moving it (like realloc). Grabstackblock actually allocates the
7214 * part of the block that has been used.
7220 int newlen = ALIGN(stacknleft * 2 + 100);
7221 char *oldspace = stacknxt;
7222 int oldlen = stacknleft;
7223 struct stack_block *sp;
7224 struct stack_block *oldstackp;
7226 if (stacknxt == stackp->space && stackp != &stackbase) {
7231 sp = ckrealloc((pointer)sp, sizeof(struct stack_block) - MINSIZE + newlen);
7234 stacknxt = sp->space;
7235 stacknleft = newlen;
7237 /* Stack marks pointing to the start of the old block
7238 * must be relocated to point to the new block
7240 struct stackmark *xmark;
7242 while (xmark != NULL && xmark->stackp == oldstackp) {
7243 xmark->stackp = stackp;
7244 xmark->stacknxt = stacknxt;
7245 xmark->stacknleft = stacknleft;
7246 xmark = xmark->marknext;
7251 p = stalloc(newlen);
7252 memcpy(p, oldspace, oldlen);
7253 stacknxt = p; /* free the space */
7254 stacknleft += newlen; /* we just allocated */
7272 * The following routines are somewhat easier to use that the above.
7273 * The user declares a variable of type STACKSTR, which may be declared
7274 * to be a register. The macro STARTSTACKSTR initializes things. Then
7275 * the user uses the macro STPUTC to add characters to the string. In
7276 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
7277 * grown as necessary. When the user is done, she can just leave the
7278 * string there and refer to it using stackblock(). Or she can allocate
7279 * the space for it using grabstackstr(). If it is necessary to allow
7280 * someone else to use the stack temporarily and then continue to grow
7281 * the string, the user should use grabstack to allocate the space, and
7282 * then call ungrabstr(p) to return to the previous mode of operation.
7284 * USTPUTC is like STPUTC except that it doesn't check for overflow.
7285 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
7286 * is space for at least one character.
7292 int len = stackblocksize();
7293 if (herefd >= 0 && len >= 1024) {
7294 xwrite(herefd, stackblock(), len);
7295 sstrnleft = len - 1;
7296 return stackblock();
7299 sstrnleft = stackblocksize() - len - 1;
7300 return stackblock() + len;
7305 * Called from CHECKSTRSPACE.
7309 makestrspace(size_t newlen) {
7310 int len = stackblocksize() - sstrnleft;
7313 sstrnleft = stackblocksize() - len;
7314 } while (sstrnleft < newlen);
7315 return stackblock() + len;
7321 ungrabstackstr(s, p)
7325 stacknleft += stacknxt - s;
7327 sstrnleft = stacknleft - (p - s);
7329 /* $NetBSD: miscbltin.c,v 1.30 2001/02/04 19:52:06 christos Exp $ */
7332 * Miscelaneous builtins.
7339 mode_t getmode(const void *, mode_t);
7340 static void *setmode(const char *);
7342 #if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
7343 typedef enum __rlimit_resource rlim_t;
7350 * The read builtin. The -e option causes backslashes to escape the
7351 * following character.
7353 * This uses unbuffered input, which may be avoidable in some cases.
7374 while ((i = nextopt("p:r")) != '\0') {
7380 if (prompt && isatty(0)) {
7384 if (*(ap = argptr) == NULL)
7386 if ((ifs = bltinlookup("IFS")) == NULL)
7393 if (read(0, &c, 1) != 1) {
7405 if (!rflag && c == '\\') {
7411 if (startword && *ifs == ' ' && strchr(ifs, c)) {
7415 if (backslash && c == '\\') {
7416 if (read(0, &c, 1) != 1) {
7421 } else if (ap[1] != NULL && strchr(ifs, c) != NULL) {
7423 setvar(*ap, stackblock(), 0);
7432 /* Remove trailing blanks */
7433 while (stackblock() <= --p && strchr(ifs, *p) != NULL)
7435 setvar(*ap, stackblock(), 0);
7436 while (*++ap != NULL)
7437 setvar(*ap, nullstr, 0);
7444 umaskcmd(argc, argv)
7451 int symbolic_mode = 0;
7453 while ((i = nextopt("S")) != '\0') {
7462 if ((ap = *argptr) == NULL) {
7463 if (symbolic_mode) {
7464 char u[4], g[4], o[4];
7467 if ((mask & S_IRUSR) == 0)
7469 if ((mask & S_IWUSR) == 0)
7471 if ((mask & S_IXUSR) == 0)
7476 if ((mask & S_IRGRP) == 0)
7478 if ((mask & S_IWGRP) == 0)
7480 if ((mask & S_IXGRP) == 0)
7485 if ((mask & S_IROTH) == 0)
7487 if ((mask & S_IWOTH) == 0)
7489 if ((mask & S_IXOTH) == 0)
7493 out1fmt("u=%s,g=%s,o=%s\n", u, g, o);
7495 out1fmt("%.4o\n", mask);
7498 if (isdigit((unsigned char)*ap)) {
7501 if (*ap >= '8' || *ap < '0')
7502 error("Illegal number: %s", argv[1]);
7503 mask = (mask << 3) + (*ap - '0');
7504 } while (*++ap != '\0');
7510 if ((set = setmode(ap)) != 0) {
7511 mask = getmode(set, ~mask & 0777);
7516 error("Illegal mode: %s", ap);
7518 umask(~mask & 0777);
7527 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
7528 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
7529 * ash by J.T. Conklin.
7537 int factor; /* multiply by to get rlim_{cur,max} values */
7541 static const struct limits limits[] = {
7543 { "time(seconds)", RLIMIT_CPU, 1, 't' },
7546 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
7549 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
7552 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
7555 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
7558 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
7560 #ifdef RLIMIT_MEMLOCK
7561 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
7564 { "process(processes)", RLIMIT_NPROC, 1, 'p' },
7566 #ifdef RLIMIT_NOFILE
7567 { "nofiles(descriptors)", RLIMIT_NOFILE, 1, 'n' },
7570 { "vmemory(kbytes)", RLIMIT_VMEM, 1024, 'v' },
7573 { "swap(kbytes)", RLIMIT_SWAP, 1024, 'w' },
7575 { (char *) 0, 0, 0, '\0' }
7579 ulimitcmd(argc, argv)
7585 enum { SOFT = 0x1, HARD = 0x2 }
7587 const struct limits *l;
7590 struct rlimit limit;
7593 while ((optc = nextopt("HSatfdsmcnpl")) != '\0')
7608 for (l = limits; l->name && l->option != what; l++)
7611 error("internal error (%c)", what);
7613 set = *argptr ? 1 : 0;
7617 if (all || argptr[1])
7618 error("too many arguments");
7619 if (strcmp(p, "unlimited") == 0)
7620 val = RLIM_INFINITY;
7624 while ((c = *p++) >= '0' && c <= '9')
7626 val = (val * 10) + (long)(c - '0');
7627 if (val < (rlim_t) 0)
7631 error("bad number");
7636 for (l = limits; l->name; l++) {
7637 getrlimit(l->cmd, &limit);
7639 val = limit.rlim_cur;
7640 else if (how & HARD)
7641 val = limit.rlim_max;
7643 out1fmt("%-20s ", l->name);
7644 if (val == RLIM_INFINITY)
7645 out1fmt("unlimited\n");
7650 out1fmt("%lld\n", (long long) val);
7652 out1fmt("%ld\n", (long) val);
7659 getrlimit(l->cmd, &limit);
7662 limit.rlim_max = val;
7664 limit.rlim_cur = val;
7665 if (setrlimit(l->cmd, &limit) < 0)
7666 error("error setting limit (%s)", strerror(errno));
7669 val = limit.rlim_cur;
7670 else if (how & HARD)
7671 val = limit.rlim_max;
7673 if (val == RLIM_INFINITY)
7674 out1fmt("unlimited\n");
7679 out1fmt("%lld\n", (long long) val);
7681 out1fmt("%ld\n", (long) val);
7687 /* $NetBSD: mystring.c,v 1.14 1999/07/09 03:05:50 christos Exp $ */
7692 * equal(s1, s2) Return true if strings are equal.
7693 * scopy(from, to) Copy a string.
7694 * scopyn(from, to, n) Like scopy, but checks for overflow.
7695 * number(s) Convert a string of digits to an integer.
7696 * is_number(s) Return true if s is a string of digits.
7699 static char nullstr[1]; /* zero length string */
7700 static const char spcstr[] = " ";
7701 static const char snlfmt[] = "%s\n";
7704 * equal - #defined in mystring.h
7708 * scopy - #defined in mystring.h
7714 * scopyn - copy a string from "from" to "to", truncating the string
7715 * if necessary. "To" is always nul terminated, even if
7716 * truncation is performed. "Size" is the size of "to".
7720 scopyn(from, to, size)
7726 while (--size > 0) {
7727 if ((*to++ = *from++) == '\0')
7736 * prefix -- see if pfx is a prefix of string.
7745 if (*pfx++ != *string++)
7753 * Convert a string of digits to an integer, printing an error message on
7763 error("Illegal number: %s", s);
7770 * Check for a valid number. This should be elsewhere.
7780 } while (*++p != '\0');
7786 * Produce a possibly single quoted string suitable as input to the shell.
7787 * The return string is allocated on the stack.
7791 single_quote(const char *s) {
7798 size_t len1, len1p, len2, len2p;
7800 len1 = strcspn(s, "'");
7801 len2 = strspn(s + len1, "'");
7803 len1p = len1 ? len1 + 2 : len1;
7815 CHECKSTRSPACE(len1p + len2p + 1, p);
7820 q = mempcpy(p + 1, s, len1);
7823 memcpy(p + 1, s, len1);
7840 *(char *) mempcpy(q + 1, s, len2) = '"';
7843 memcpy(q + 1, s, len2);
7849 STADJUST(len1p + len2p, p);
7854 return grabstackstr(p);
7858 * Like strdup but works with the ash stack.
7862 sstrdup(const char *p)
7864 size_t len = strlen(p) + 1;
7865 return memcpy(stalloc(len), p, len);
7869 * Wrapper around strcmp for qsort/bsearch/...
7872 pstrcmp(const void *a, const void *b)
7874 return strcmp(*(const char *const *) a, *(const char *const *) b);
7878 * Find a string is in a sorted array.
7880 static const char *const *
7881 findstring(const char *s, const char *const *array, size_t nmemb)
7883 return bsearch(&s, array, nmemb, sizeof(const char *), pstrcmp);
7886 * This file was generated by the mknodes program.
7889 /* $NetBSD: nodes.c.pat,v 1.8 1997/04/11 23:03:09 christos Exp $ */
7892 * Routine for dealing with parsed shell commands.
7896 static int funcblocksize; /* size of structures in function */
7897 static int funcstringsize; /* size of strings in node */
7898 pointer funcblock; /* block to allocate function from */
7899 static char *funcstring; /* block to allocate strings from */
7901 static const short nodesize[26] = {
7902 ALIGN(sizeof (struct nbinary)),
7903 ALIGN(sizeof (struct ncmd)),
7904 ALIGN(sizeof (struct npipe)),
7905 ALIGN(sizeof (struct nredir)),
7906 ALIGN(sizeof (struct nredir)),
7907 ALIGN(sizeof (struct nredir)),
7908 ALIGN(sizeof (struct nbinary)),
7909 ALIGN(sizeof (struct nbinary)),
7910 ALIGN(sizeof (struct nif)),
7911 ALIGN(sizeof (struct nbinary)),
7912 ALIGN(sizeof (struct nbinary)),
7913 ALIGN(sizeof (struct nfor)),
7914 ALIGN(sizeof (struct ncase)),
7915 ALIGN(sizeof (struct nclist)),
7916 ALIGN(sizeof (struct narg)),
7917 ALIGN(sizeof (struct narg)),
7918 ALIGN(sizeof (struct nfile)),
7919 ALIGN(sizeof (struct nfile)),
7920 ALIGN(sizeof (struct nfile)),
7921 ALIGN(sizeof (struct nfile)),
7922 ALIGN(sizeof (struct nfile)),
7923 ALIGN(sizeof (struct ndup)),
7924 ALIGN(sizeof (struct ndup)),
7925 ALIGN(sizeof (struct nhere)),
7926 ALIGN(sizeof (struct nhere)),
7927 ALIGN(sizeof (struct nnot)),
7931 static void calcsize __P((union node *));
7932 static void sizenodelist __P((struct nodelist *));
7933 static union node *copynode __P((union node *));
7934 static struct nodelist *copynodelist __P((struct nodelist *));
7935 static char *nodesavestr __P((char *));
7940 * Make a copy of a parse tree.
7952 funcblock = ckmalloc(funcblocksize + funcstringsize);
7953 funcstring = (char *) funcblock + funcblocksize;
7965 funcblocksize += nodesize[n->type];
7972 calcsize(n->nbinary.ch2);
7973 calcsize(n->nbinary.ch1);
7976 calcsize(n->ncmd.redirect);
7977 calcsize(n->ncmd.args);
7978 calcsize(n->ncmd.assign);
7981 sizenodelist(n->npipe.cmdlist);
7986 calcsize(n->nredir.redirect);
7987 calcsize(n->nredir.n);
7990 calcsize(n->nif.elsepart);
7991 calcsize(n->nif.ifpart);
7992 calcsize(n->nif.test);
7995 funcstringsize += strlen(n->nfor.var) + 1;
7996 calcsize(n->nfor.body);
7997 calcsize(n->nfor.args);
8000 calcsize(n->ncase.cases);
8001 calcsize(n->ncase.expr);
8004 calcsize(n->nclist.body);
8005 calcsize(n->nclist.pattern);
8006 calcsize(n->nclist.next);
8010 sizenodelist(n->narg.backquote);
8011 funcstringsize += strlen(n->narg.text) + 1;
8012 calcsize(n->narg.next);
8019 calcsize(n->nfile.fname);
8020 calcsize(n->nfile.next);
8024 calcsize(n->ndup.vname);
8025 calcsize(n->ndup.next);
8029 calcsize(n->nhere.doc);
8030 calcsize(n->nhere.next);
8033 calcsize(n->nnot.com);
8042 struct nodelist *lp;
8045 funcblocksize += ALIGN(sizeof(struct nodelist));
8062 funcblock = (char *) funcblock + nodesize[n->type];
8069 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8070 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8073 new->ncmd.redirect = copynode(n->ncmd.redirect);
8074 new->ncmd.args = copynode(n->ncmd.args);
8075 new->ncmd.assign = copynode(n->ncmd.assign);
8076 new->ncmd.backgnd = n->ncmd.backgnd;
8079 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8080 new->npipe.backgnd = n->npipe.backgnd;
8085 new->nredir.redirect = copynode(n->nredir.redirect);
8086 new->nredir.n = copynode(n->nredir.n);
8089 new->nif.elsepart = copynode(n->nif.elsepart);
8090 new->nif.ifpart = copynode(n->nif.ifpart);
8091 new->nif.test = copynode(n->nif.test);
8094 new->nfor.var = nodesavestr(n->nfor.var);
8095 new->nfor.body = copynode(n->nfor.body);
8096 new->nfor.args = copynode(n->nfor.args);
8099 new->ncase.cases = copynode(n->ncase.cases);
8100 new->ncase.expr = copynode(n->ncase.expr);
8103 new->nclist.body = copynode(n->nclist.body);
8104 new->nclist.pattern = copynode(n->nclist.pattern);
8105 new->nclist.next = copynode(n->nclist.next);
8109 new->narg.backquote = copynodelist(n->narg.backquote);
8110 new->narg.text = nodesavestr(n->narg.text);
8111 new->narg.next = copynode(n->narg.next);
8118 new->nfile.fname = copynode(n->nfile.fname);
8119 new->nfile.fd = n->nfile.fd;
8120 new->nfile.next = copynode(n->nfile.next);
8124 new->ndup.vname = copynode(n->ndup.vname);
8125 new->ndup.dupfd = n->ndup.dupfd;
8126 new->ndup.fd = n->ndup.fd;
8127 new->ndup.next = copynode(n->ndup.next);
8131 new->nhere.doc = copynode(n->nhere.doc);
8132 new->nhere.fd = n->nhere.fd;
8133 new->nhere.next = copynode(n->nhere.next);
8136 new->nnot.com = copynode(n->nnot.com);
8139 new->type = n->type;
8144 static struct nodelist *
8146 struct nodelist *lp;
8148 struct nodelist *start;
8149 struct nodelist **lpp;
8154 funcblock = (char *) funcblock + ALIGN(sizeof(struct nodelist));
8155 (*lpp)->n = copynode(lp->n);
8157 lpp = &(*lpp)->next;
8170 char *rtn = funcstring;
8172 funcstring = stpcpy(funcstring, s) + 1;
8175 register char *p = s;
8176 register char *q = funcstring;
8177 char *rtn = funcstring;
8179 while ((*q++ = *p++) != '\0')
8189 * Free a parse tree.
8199 /* $NetBSD: options.c,v 1.31 2001/02/26 13:06:43 wiz Exp $ */
8202 struct optent optlist[NOPTS] = {
8203 { "errexit", 'e', 0 },
8204 { "noglob", 'f', 0 },
8205 { "ignoreeof", 'I', 0 },
8206 { "interactive",'i', 0 },
8207 { "monitor", 'm', 0 },
8208 { "noexec", 'n', 0 },
8209 { "stdin", 's', 0 },
8210 { "xtrace", 'x', 0 },
8211 { "verbose", 'v', 0 },
8213 { "emacs", 'E', 0 },
8214 { "noclobber", 'C', 0 },
8215 { "allexport", 'a', 0 },
8216 { "notify", 'b', 0 },
8217 { "nounset", 'u', 0 },
8218 { "quietprofile", 'q', 0 },
8220 static char *arg0; /* value of $0 */
8221 struct shparam shellparam; /* current positional parameters */
8222 static char **argptr; /* argument list for builtin commands */
8223 static char *optionarg; /* set by nextopt (like getopt) */
8224 static char *optptr; /* used by nextopt */
8226 static char *minusc; /* argument to -c option */
8229 static void options __P((int));
8230 static void minus_o __P((char *, int));
8231 static void setoption __P((int, int));
8233 static int getopts __P((char *, char *, char **, int *, int *));
8238 * Process the shell command line arguments.
8242 procargs(argc, argv)
8251 for (i = 0; i < NOPTS; i++)
8254 if (*argptr == NULL && minusc == NULL)
8256 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8260 for (i = 0; i < NOPTS; i++)
8261 if (optlist[i].val == 2)
8264 if (sflag == 0 && minusc == NULL) {
8265 commandname = argv[0];
8267 setinputfile(arg0, 0);
8270 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8271 if (argptr && minusc && *argptr)
8274 shellparam.p = argptr;
8275 shellparam.optind = 1;
8276 shellparam.optoff = -1;
8277 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
8279 shellparam.nparam++;
8289 setinteractive(iflag);
8294 * Process shell options. The global variable argptr contains a pointer
8295 * to the argument list; we advance it past the options.
8308 while ((p = *argptr) != NULL) {
8310 if ((c = *p++) == '-') {
8312 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8314 /* "-" means turn off -x and -v */
8317 /* "--" means reset params */
8318 else if (*argptr == NULL)
8321 break; /* "-" or "--" terminates options */
8323 } else if (c == '+') {
8329 while ((c = *p++) != '\0') {
8330 if (c == 'c' && cmdline) {
8332 #ifdef NOHACK /* removing this code allows sh -ce 'foo' for compat */
8336 if (q == NULL || minusc != NULL)
8337 error("Bad -c option");
8342 } else if (c == 'o') {
8343 minus_o(*argptr, val);
8361 out1str("Current option settings\n");
8362 for (i = 0; i < NOPTS; i++)
8363 out1fmt("%-16s%s\n", optlist[i].name,
8364 optlist[i].val ? "on" : "off");
8366 for (i = 0; i < NOPTS; i++)
8367 if (equal(name, optlist[i].name)) {
8368 setoption(optlist[i].letter, val);
8371 error("Illegal option -o %s", name);
8377 setoption(flag, val)
8383 for (i = 0; i < NOPTS; i++)
8384 if (optlist[i].letter == flag) {
8385 optlist[i].val = val;
8387 /* #%$ hack for ksh semantics */
8390 else if (flag == 'E')
8395 error("Illegal option -%c", flag);
8405 for (i = 0; i < NOPTS; i++)
8414 * Set the shell parameters.
8425 for (nparam = 0 ; argv[nparam] ; nparam++);
8426 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
8428 *ap++ = savestr(*argv++);
8431 freeparam(&shellparam);
8432 shellparam.malloc = 1;
8433 shellparam.nparam = nparam;
8434 shellparam.p = newparam;
8435 shellparam.optind = 1;
8436 shellparam.optoff = -1;
8441 * Free the list of positional parameters.
8446 volatile struct shparam *param;
8450 if (param->malloc) {
8451 for (ap = param->p ; *ap ; ap++)
8460 * The shift builtin command.
8464 shiftcmd(argc, argv)
8473 n = number(argv[1]);
8474 if (n > shellparam.nparam)
8475 error("can't shift that many");
8477 shellparam.nparam -= n;
8478 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
8479 if (shellparam.malloc)
8483 while ((*ap2++ = *ap1++) != NULL);
8484 shellparam.optind = 1;
8485 shellparam.optoff = -1;
8493 * The set command builtin.
8502 return showvarscmd(argc, argv);
8506 if (*argptr != NULL) {
8518 shellparam.optind = number(value);
8519 shellparam.optoff = -1;
8524 * The getopts builtin. Shellparam.optnext points to the next argument
8525 * to be processed. Shellparam.optptr points to the next character to
8526 * be processed in the current argument. If shellparam.optnext is NULL,
8527 * then it's the first time getopts has been called.
8531 getoptscmd(argc, argv)
8538 error("Usage: getopts optstring var [arg]");
8539 else if (argc == 3) {
8540 optbase = shellparam.p;
8541 if (shellparam.optind > shellparam.nparam + 1) {
8542 shellparam.optind = 1;
8543 shellparam.optoff = -1;
8548 if (shellparam.optind > argc - 2) {
8549 shellparam.optind = 1;
8550 shellparam.optoff = -1;
8554 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
8555 &shellparam.optoff);
8559 * Safe version of setvar, returns 1 on success 0 on failure.
8563 setvarsafe(name, val, flags)
8564 const char *name, *val;
8567 struct jmploc jmploc;
8568 struct jmploc *volatile savehandler = handler;
8574 if (setjmp(jmploc.loc))
8578 setvar(name, val, flags);
8580 handler = savehandler;
8585 getopts(optstr, optvar, optfirst, myoptind, optoff)
8597 char **optnext = optfirst + *myoptind - 1;
8599 if (*myoptind <= 1 || *optoff < 0 || !(*(optnext - 1)) ||
8600 strlen(*(optnext - 1)) < *optoff)
8603 p = *(optnext - 1) + *optoff;
8604 if (p == NULL || *p == '\0') {
8605 /* Current word is done, advance */
8606 if (optnext == NULL)
8609 if (p == NULL || *p != '-' || *++p == '\0') {
8611 *myoptind = optnext - optfirst + 1;
8617 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
8622 for (q = optstr; *q != c; ) {
8624 if (optstr[0] == ':') {
8627 err |= setvarsafe("OPTARG", s, 0);
8630 outfmt(&errout, "Illegal option -%c\n", c);
8631 (void) unsetvar("OPTARG");
8641 if (*p == '\0' && (p = *optnext) == NULL) {
8642 if (optstr[0] == ':') {
8645 err |= setvarsafe("OPTARG", s, 0);
8649 outfmt(&errout, "No arg for -%c option\n", c);
8650 (void) unsetvar("OPTARG");
8658 setvarsafe("OPTARG", p, 0);
8662 setvarsafe("OPTARG", "", 0);
8663 *myoptind = optnext - optfirst + 1;
8670 *optoff = p ? p - *(optnext - 1) : -1;
8671 fmtstr(s, sizeof(s), "%d", *myoptind);
8672 err |= setvarsafe("OPTIND", s, VNOFUNC);
8675 err |= setvarsafe(optvar, s, 0);
8687 * XXX - should get rid of. have all builtins use getopt(3). the
8688 * library getopt must have the BSD extension static variable "optreset"
8689 * otherwise it can't be used within the shell safely.
8691 * Standard option processing (a la getopt) for builtin routines. The
8692 * only argument that is passed to nextopt is the option string; the
8693 * other arguments are unnecessary. It return the character, or '\0' on
8699 const char *optstring;
8705 if ((p = optptr) == NULL || *p == '\0') {
8707 if (p == NULL || *p != '-' || *++p == '\0')
8710 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
8714 for (q = optstring ; *q != c ; ) {
8716 error("Illegal option -%c", c);
8721 if (*p == '\0' && (p = *argptr++) == NULL)
8722 error("No arg for -%c option", c);
8731 /* $NetBSD: output.c,v 1.23 2001/01/07 23:39:07 lukem Exp $ */
8734 * Shell output routines. We use our own output routines because:
8735 * When a builtin command is interrupted we have to discard
8736 * any pending output.
8737 * When a builtin command appears in back quotes, we want to
8738 * save the output of the command in a region obtained
8739 * via malloc, rather than doing a fork and reading the
8740 * output of the command via a pipe.
8741 * Our output routines may be smaller than the stdio routines.
8745 #define OUTBUFSIZ BUFSIZ
8746 #define MEM_OUT -3 /* output to dynamically allocated memory */
8749 #ifdef USE_GLIBC_STDIO
8750 struct output output = {NULL, NULL, 0, NULL, 0, 1, 0};
8751 struct output errout = {NULL, NULL, 0, NULL, 0, 2, 0};
8752 struct output memout = {NULL, NULL, 0, NULL, 0, MEM_OUT, 0};
8754 struct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0};
8755 struct output errout = {NULL, 0, NULL, 0, 2, 0};
8756 struct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0};
8758 struct output *out1 = &output;
8759 struct output *out2 = &errout;
8762 #ifndef USE_GLIBC_STDIO
8763 static void __outstr __P((const char *, size_t, struct output*));
8770 INCLUDE "memalloc.h"
8773 #ifdef USE_GLIBC_STDIO
8781 #ifdef USE_GLIBC_STDIO
8782 if (memout.stream != NULL)
8785 if (memout.buf != NULL) {
8794 #ifndef USE_GLIBC_STDIO
8796 __outstr(const char *p, size_t len, struct output *dest) {
8797 if (!dest->bufsize) {
8799 } else if (dest->buf == NULL) {
8800 if (len > dest->bufsize && dest->fd == MEM_OUT) {
8801 dest->bufsize = len;
8804 dest->buf = ckmalloc(dest->bufsize);
8805 dest->nextc = dest->buf;
8806 dest->nleft = dest->bufsize;
8808 } else if (dest->fd == MEM_OUT) {
8811 offset = dest->bufsize;
8813 if (dest->bufsize >= len) {
8814 dest->bufsize <<= 1;
8816 dest->bufsize += len;
8818 dest->buf = ckrealloc(dest->buf, dest->bufsize);
8819 dest->nleft = dest->bufsize - offset;
8820 dest->nextc = dest->buf + offset;
8826 if (len < dest->nleft) {
8828 memcpy(dest->nextc, p, len);
8833 if (xwrite(dest->fd, p, len) < len)
8834 dest->flags |= OUTPUT_ERR;
8842 struct output *file;
8844 #ifdef USE_GLIBC_STDIO
8846 fputs(p, file->stream);
8855 if ((file->nleft -= len) > 0) {
8856 memcpy(file->nextc, p, len);
8860 __outstr(p, len, file);
8865 #ifndef USE_GLIBC_STDIO
8871 struct output *dest;
8873 __outstr(&c, 1, dest);
8889 struct output *dest;
8891 #ifdef USE_GLIBC_STDIO
8893 fflush(dest->stream);
8898 len = dest->nextc - dest->buf;
8899 if (dest->buf == NULL || !len || dest->fd < 0)
8901 dest->nextc = dest->buf;
8902 dest->nleft = dest->bufsize;
8903 if (xwrite(dest->fd, dest->buf, len) < len)
8904 dest->flags |= OUTPUT_ERR;
8924 outfmt(struct output *file, const char *fmt, ...)
8933 struct output *file;
8937 file = va_arg(ap, struct output *);
8938 fmt = va_arg(ap, const char *);
8942 doformat(file, fmt, ap);
8949 out1fmt(const char *fmt, ...)
8960 fmt = va_arg(ap, const char *);
8964 doformat(out1, fmt, ap);
8970 fmtstr(char *outbuf, size_t length, const char *fmt, ...)
8983 outbuf = va_arg(ap, char *);
8984 length = va_arg(ap, size_t);
8985 fmt = va_arg(ap, const char *);
8990 vsnprintf(outbuf, length, fmt, ap);
8994 #ifndef USE_GLIBC_STDIO
8996 * Formatted output. This routine handles a subset of the printf formats:
8997 * - Formats supported: d, u, o, p, X, s, and c.
8998 * - The x format is also accepted but is treated like X.
8999 * - The l, ll and q modifiers are accepted.
9000 * - The - and # flags are accepted; # only works with the o format.
9001 * - Width and precision may be specified with any format except c.
9002 * - An * may be given for the width or precision.
9003 * - The obsolete practice of preceding the width with a zero to get
9004 * zero padding is not supported; use the precision field.
9005 * - A % may be printed by writing %% in the format string.
9011 #define HAVE_VASPRINTF 1
9015 static const char digit[] = "0123456789ABCDEF";
9020 doformat(dest, f, ap)
9021 struct output *dest;
9022 const char *f; /* format string */
9030 len = vasprintf(&t, f, ap);
9040 #else /* !HAVE_VASPRINTF */
9042 char temp[TEMPSIZE];
9063 while ((c = *f++) != '\0') {
9084 width = va_arg(ap, int);
9087 while (is_digit(*f)) {
9088 width = 10 * width + digit_val(*f++);
9093 prec = va_arg(ap, int);
9097 while (is_digit(*f)) {
9098 prec = 10 * prec + digit_val(*f++);
9109 } else if (*f == 'q') {
9117 l = va_arg(ap, quad_t);
9121 l = va_arg(ap, long);
9123 l = va_arg(ap, int);
9143 /* we don't implement 'x'; treat like 'X' */
9146 uns_number: /* an unsigned number */
9150 num = va_arg(ap, u_quad_t);
9154 num = va_arg(ap, unsigned long);
9156 num = va_arg(ap, unsigned int);
9157 number: /* process a number */
9158 p = temp + TEMPSIZE - 1;
9161 *--p = digit[num % base];
9164 len = (temp + TEMPSIZE - 1) - p;
9167 if (sharp && *f == 'o' && prec <= len)
9176 if (flushleft == 0) {
9192 p = va_arg(ap, char *);
9196 if (prec >= 0 && len > prec)
9199 if (flushleft == 0) {
9205 while (--prec != 0 && *p)
9211 c = va_arg(ap, int);
9220 #endif /* !HAVE_VASPRINTF */
9227 * Version of write which resumes after a signal is caught.
9231 xwrite(fd, buf, nbytes)
9243 i = write(fd, buf, n);
9249 } else if (i == 0) {
9252 } else if (errno != EINTR) {
9261 * Version of ioctl that retries after a signal is caught.
9262 * XXX unused function
9266 xioctl(fd, request, arg)
9268 unsigned long request;
9273 while ((i = ioctl(fd, request, arg)) == -1 && errno == EINTR);
9279 #ifdef USE_GLIBC_STDIO
9280 static void initstreams() {
9281 output.stream = stdout;
9282 errout.stream = stderr;
9289 memout.stream = open_memstream(&memout.buf, &memout.bufsize);
9297 error = fclose(memout.stream);
9298 memout.stream = NULL;
9302 /* $NetBSD: parser.c,v 1.46 2001/02/04 19:52:06 christos Exp $ */
9305 * Shell command parser.
9308 #define EOFMARKLEN 79
9313 struct heredoc *next; /* next here document in list */
9314 union node *here; /* redirection node */
9315 char *eofmark; /* string indicating end of input */
9316 int striptabs; /* if set, strip leading tabs */
9321 struct heredoc *heredoclist; /* list of here documents to read */
9322 static int parsebackquote; /* nonzero if we are inside backquotes */
9323 static int doprompt; /* if set, prompt the user */
9324 static int needprompt; /* true if interactive and at start of line */
9325 static int lasttoken; /* last token read */
9326 static int tokpushback; /* last token pushed back */
9327 static char *wordtext; /* text of last word returned by readtoken */
9328 static int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */
9329 /* 1 == check for aliases, 2 == also check for assignments */
9330 static int checkalias;
9331 struct nodelist *backquotelist;
9332 union node *redirnode;
9333 struct heredoc *heredoc;
9334 static int quoteflag; /* set if (part of) last token was quoted */
9335 static int startlinno; /* line # where last token started */
9338 static union node *list __P((int));
9339 static union node *andor __P((void));
9340 static union node *pipeline __P((void));
9341 static union node *command __P((void));
9342 static union node *simplecmd __P((void));
9343 static union node *makename __P((void));
9344 static void parsefname __P((void));
9345 static void parseheredoc __P((void));
9346 static int peektoken __P((void));
9347 static int readtoken __P((void));
9348 static int xxreadtoken __P((void));
9349 static int readtoken1 __P((int, char const *, char *, int));
9350 static int noexpand __P((char *));
9351 static void synexpect __P((int)) __attribute__((noreturn));
9352 static void synerror __P((const char *)) __attribute__((noreturn));
9353 static void setprompt __P((int));
9357 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9358 * valid parse tree indicating a blank line.)
9362 parsecmd(int interact)
9367 doprompt = interact;
9387 union node *n1, *n2, *n3;
9391 if (nlflag == 0 && tokendlist[peektoken()])
9397 if (tok == TBACKGND) {
9398 if (n2->type == NCMD || n2->type == NPIPE) {
9399 n2->ncmd.backgnd = 1;
9400 } else if (n2->type == NREDIR) {
9401 n2->type = NBACKGND;
9403 n3 = (union node *)stalloc(sizeof (struct nredir));
9404 n3->type = NBACKGND;
9406 n3->nredir.redirect = NULL;
9414 n3 = (union node *)stalloc(sizeof (struct nbinary));
9416 n3->nbinary.ch1 = n1;
9417 n3->nbinary.ch2 = n2;
9434 if (tokendlist[peektoken()])
9441 pungetc(); /* push back EOF on input */
9456 union node *n1, *n2, *n3;
9462 if ((t = readtoken()) == TAND) {
9464 } else if (t == TOR) {
9472 n3 = (union node *)stalloc(sizeof (struct nbinary));
9474 n3->nbinary.ch1 = n1;
9475 n3->nbinary.ch2 = n2;
9484 union node *n1, *n2, *pipenode;
9485 struct nodelist *lp, *prev;
9489 TRACE(("pipeline: entered\n"));
9490 if (readtoken() == TNOT) {
9496 if (readtoken() == TPIPE) {
9497 pipenode = (union node *)stalloc(sizeof (struct npipe));
9498 pipenode->type = NPIPE;
9499 pipenode->npipe.backgnd = 0;
9500 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9501 pipenode->npipe.cmdlist = lp;
9505 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9509 } while (readtoken() == TPIPE);
9515 n2 = (union node *)stalloc(sizeof (struct nnot));
9527 union node *n1, *n2;
9528 union node *ap, **app;
9529 union node *cp, **cpp;
9530 union node *redir, **rpp;
9537 switch (readtoken()) {
9539 n1 = (union node *)stalloc(sizeof (struct nif));
9541 n1->nif.test = list(0);
9542 if (readtoken() != TTHEN)
9544 n1->nif.ifpart = list(0);
9546 while (readtoken() == TELIF) {
9547 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
9548 n2 = n2->nif.elsepart;
9550 n2->nif.test = list(0);
9551 if (readtoken() != TTHEN)
9553 n2->nif.ifpart = list(0);
9555 if (lasttoken == TELSE)
9556 n2->nif.elsepart = list(0);
9558 n2->nif.elsepart = NULL;
9561 if (readtoken() != TFI)
9568 n1 = (union node *)stalloc(sizeof (struct nbinary));
9569 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
9570 n1->nbinary.ch1 = list(0);
9571 if ((got=readtoken()) != TDO) {
9572 TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
9575 n1->nbinary.ch2 = list(0);
9576 if (readtoken() != TDONE)
9582 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
9583 synerror("Bad for loop variable");
9584 n1 = (union node *)stalloc(sizeof (struct nfor));
9586 n1->nfor.var = wordtext;
9588 if (readtoken() == TIN) {
9590 while (readtoken() == TWORD) {
9591 n2 = (union node *)stalloc(sizeof (struct narg));
9593 n2->narg.text = wordtext;
9594 n2->narg.backquote = backquotelist;
9596 app = &n2->narg.next;
9600 if (lasttoken != TNL && lasttoken != TSEMI)
9603 static char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE,
9605 n2 = (union node *)stalloc(sizeof (struct narg));
9607 n2->narg.text = argvars;
9608 n2->narg.backquote = NULL;
9609 n2->narg.next = NULL;
9612 * Newline or semicolon here is optional (but note
9613 * that the original Bourne shell only allowed NL).
9615 if (lasttoken != TNL && lasttoken != TSEMI)
9619 if (readtoken() != TDO)
9621 n1->nfor.body = list(0);
9622 if (readtoken() != TDONE)
9627 n1 = (union node *)stalloc(sizeof (struct ncase));
9629 if (readtoken() != TWORD)
9631 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
9633 n2->narg.text = wordtext;
9634 n2->narg.backquote = backquotelist;
9635 n2->narg.next = NULL;
9638 } while (readtoken() == TNL);
9639 if (lasttoken != TIN)
9640 synerror("expecting \"in\"");
9641 cpp = &n1->ncase.cases;
9642 checkkwd = 2, readtoken();
9644 if (lasttoken == TLP)
9646 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
9648 app = &cp->nclist.pattern;
9650 *app = ap = (union node *)stalloc(sizeof (struct narg));
9652 ap->narg.text = wordtext;
9653 ap->narg.backquote = backquotelist;
9654 if (checkkwd = 2, readtoken() != TPIPE)
9656 app = &ap->narg.next;
9659 ap->narg.next = NULL;
9660 if (lasttoken != TRP)
9662 cp->nclist.body = list(0);
9665 if ((t = readtoken()) != TESAC) {
9667 synexpect(TENDCASE);
9669 checkkwd = 2, readtoken();
9671 cpp = &cp->nclist.next;
9672 } while(lasttoken != TESAC);
9677 n1 = (union node *)stalloc(sizeof (struct nredir));
9678 n1->type = NSUBSHELL;
9679 n1->nredir.n = list(0);
9680 n1->nredir.redirect = NULL;
9681 if (readtoken() != TRP)
9687 if (readtoken() != TEND)
9691 /* Handle an empty command like other simple commands. */
9700 * An empty command before a ; doesn't make much sense, and
9701 * should certainly be disallowed in the case of `if ;'.
9715 /* Now check for redirection which may follow command */
9716 while (readtoken() == TREDIR) {
9717 *rpp = n2 = redirnode;
9718 rpp = &n2->nfile.next;
9724 if (n1->type != NSUBSHELL) {
9725 n2 = (union node *)stalloc(sizeof (struct nredir));
9730 n1->nredir.redirect = redir;
9739 union node *args, **app;
9740 union node *n = NULL;
9741 union node *vars, **vpp;
9742 union node **rpp, *redir;
9753 switch (readtoken()) {
9756 n = (union node *)stalloc(sizeof (struct narg));
9758 n->narg.text = wordtext;
9759 n->narg.backquote = backquotelist;
9760 if (lasttoken == TWORD) {
9762 app = &n->narg.next;
9765 vpp = &n->narg.next;
9769 *rpp = n = redirnode;
9770 rpp = &n->nfile.next;
9771 parsefname(); /* read name of redirection file */
9775 args && app == &args->narg.next &&
9778 /* We have a function */
9779 if (readtoken() != TRP)
9782 if (! goodname(n->narg.text))
9783 synerror("Bad function name");
9787 n->narg.next = command();
9800 n = (union node *)stalloc(sizeof (struct ncmd));
9802 n->ncmd.backgnd = 0;
9803 n->ncmd.args = args;
9804 n->ncmd.assign = vars;
9805 n->ncmd.redirect = redir;
9813 n = (union node *)stalloc(sizeof (struct narg));
9815 n->narg.next = NULL;
9816 n->narg.text = wordtext;
9817 n->narg.backquote = backquotelist;
9821 static void fixredir(union node *n, const char *text, int err)
9823 TRACE(("Fix redir %s %d\n", text, err));
9825 n->ndup.vname = NULL;
9827 if (is_digit(text[0]) && text[1] == '\0')
9828 n->ndup.dupfd = digit_val(text[0]);
9829 else if (text[0] == '-' && text[1] == '\0')
9834 synerror("Bad fd number");
9836 n->ndup.vname = makename();
9843 union node *n = redirnode;
9845 if (readtoken() != TWORD)
9847 if (n->type == NHERE) {
9848 struct heredoc *here = heredoc;
9854 TRACE(("Here document %d\n", n->type));
9855 if (here->striptabs) {
9856 while (*wordtext == '\t')
9859 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
9860 synerror("Illegal eof marker for << redirection");
9861 rmescapes(wordtext);
9862 here->eofmark = wordtext;
9864 if (heredoclist == NULL)
9867 for (p = heredoclist ; p->next ; p = p->next);
9870 } else if (n->type == NTOFD || n->type == NFROMFD) {
9871 fixredir(n, wordtext, 0);
9873 n->nfile.fname = makename();
9879 * Input any here documents.
9884 struct heredoc *here;
9887 while (heredoclist) {
9889 heredoclist = here->next;
9894 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9895 here->eofmark, here->striptabs);
9896 n = (union node *)stalloc(sizeof (struct narg));
9897 n->narg.type = NARG;
9898 n->narg.next = NULL;
9899 n->narg.text = wordtext;
9900 n->narg.backquote = backquotelist;
9901 here->here->nhere.doc = n;
9917 int savecheckkwd = checkkwd;
9918 int savecheckalias = checkalias;
9921 int alreadyseen = tokpushback;
9926 checkalias = savecheckalias;
9932 if (checkkwd == 2) {
9941 * check for keywords
9943 if (t == TWORD && !quoteflag)
9945 const char *const *pp;
9947 if ((pp = findkwd(wordtext))) {
9948 lasttoken = t = pp - parsekwd + KWDOFFSET;
9949 TRACE(("keyword %s recognized\n", tokname[t]));
9959 } else if (checkalias == 2 && isassignment(wordtext)) {
9960 lasttoken = t = TASSIGN;
9961 } else if (checkalias) {
9962 if (!quoteflag && (ap = lookupalias(wordtext, 1)) != NULL) {
9964 pushstring(ap->val, strlen(ap->val), ap);
9966 checkkwd = savecheckkwd;
9974 TRACE(("token %s %s\n", tokname[t], t == TWORD || t == TASSIGN ? wordtext : ""));
9976 TRACE(("reread token %s %s\n", tokname[t], t == TWORD || t == TASSIGN ? wordtext : ""));
9983 * Read the next input token.
9984 * If the token is a word, we set backquotelist to the list of cmds in
9985 * backquotes. We set quoteflag to true if any part of the word was
9987 * If the token is TREDIR, then we set redirnode to a structure containing
9989 * In all cases, the variable startlinno is set to the number of the line
9990 * on which the token starts.
9992 * [Change comment: here documents and internal procedures]
9993 * [Readtoken shouldn't have any arguments. Perhaps we should make the
9994 * word parsing code into a separate routine. In this case, readtoken
9995 * doesn't need to have any internal procedures, but parseword does.
9996 * We could also make parseoperator in essence the main routine, and
9997 * have parseword (readtoken1?) handle both words and redirection.]
10000 #define RETURN(token) return lasttoken = token
10014 startlinno = plinno;
10015 for (;;) { /* until token or start of word found */
10018 case ' ': case '\t':
10022 while ((c = pgetc()) != '\n' && c != PEOF);
10026 if (pgetc() == '\n') {
10027 startlinno = ++plinno;
10038 needprompt = doprompt;
10043 if (pgetc() == '&')
10048 if (pgetc() == '|')
10053 if (pgetc() == ';')
10066 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10073 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10074 * is not NULL, read a here document. In the latter case, eofmark is the
10075 * word which marks the end of the document and striptabs is true if
10076 * leading tabs should be stripped from the document. The argument firstc
10077 * is the first character of the input token or document.
10079 * Because C does not have internal subroutines, I have simulated them
10080 * using goto's to implement the subroutine linkage. The following macros
10081 * will run code that appears at the end of readtoken1.
10084 #define CHECKEND() {goto checkend; checkend_return:;}
10085 #define PARSEREDIR() {goto parseredir; parseredir_return:;}
10086 #define PARSESUB() {goto parsesub; parsesub_return:;}
10087 #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10088 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10089 #define PARSEARITH() {goto parsearith; parsearith_return:;}
10092 readtoken1(firstc, syntax, eofmark, striptabs)
10094 char const *syntax;
10101 char line[EOFMARKLEN + 1];
10102 struct nodelist *bqlist;
10105 int varnest; /* levels of variables expansion */
10106 int arinest; /* levels of arithmetic expansion */
10107 int parenlevel; /* levels of parens in arithmetic */
10108 int dqvarnest; /* levels of variables expansion within double quotes */
10110 char const *prevsyntax; /* syntax before arithmetic */
10112 /* Avoid longjmp clobbering */
10118 (void) &parenlevel;
10121 (void) &prevsyntax;
10125 startlinno = plinno;
10127 if (syntax == DQSYNTAX)
10136 STARTSTACKSTR(out);
10137 loop: { /* for each line, until end of word */
10139 if (c == '\034' && doprompt
10140 && attyset() && ! equal(termval(), "emacs")) {
10142 if (syntax == BASESYNTAX)
10143 return readtoken();
10148 CHECKEND(); /* set c to PEOF if at end of here document */
10149 for (;;) { /* until end of line or end of word */
10150 CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */
10151 switch(syntax[c]) {
10152 case CNL: /* '\n' */
10153 if (syntax == BASESYNTAX)
10154 goto endword; /* exit outer loop */
10162 goto loop; /* continue outer loop */
10167 if ((eofmark == NULL || dblquote) &&
10169 USTPUTC(CTLESC, out);
10172 case CBACK: /* backslash */
10175 USTPUTC('\\', out);
10177 } else if (c == '\n') {
10183 if (dblquote && c != '\\' && c != '`' && c != '$'
10184 && (c != '"' || eofmark != NULL))
10185 USTPUTC('\\', out);
10186 if (SQSYNTAX[c] == CCTL)
10187 USTPUTC(CTLESC, out);
10188 else if (eofmark == NULL)
10189 USTPUTC(CTLQUOTEMARK, out);
10195 if (eofmark == NULL)
10196 USTPUTC(CTLQUOTEMARK, out);
10200 if (eofmark == NULL)
10201 USTPUTC(CTLQUOTEMARK, out);
10206 if (eofmark != NULL && arinest == 0 &&
10211 syntax = ARISYNTAX;
10213 } else if (eofmark == NULL &&
10215 syntax = BASESYNTAX;
10221 case CVAR: /* '$' */
10222 PARSESUB(); /* parse substitution */
10224 case CENDVAR: /* '}' */
10227 if (dqvarnest > 0) {
10230 USTPUTC(CTLENDVAR, out);
10235 #ifdef ASH_MATH_SUPPORT
10236 case CLP: /* '(' in arithmetic */
10240 case CRP: /* ')' in arithmetic */
10241 if (parenlevel > 0) {
10245 if (pgetc() == ')') {
10246 if (--arinest == 0) {
10247 USTPUTC(CTLENDARI, out);
10248 syntax = prevsyntax;
10249 if (syntax == DQSYNTAX)
10257 * unbalanced parens
10258 * (don't 2nd guess - no error)
10266 case CBQUOTE: /* '`' */
10270 goto endword; /* exit outer loop */
10275 goto endword; /* exit outer loop */
10284 if (syntax == ARISYNTAX)
10285 synerror("Missing '))'");
10286 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
10287 synerror("Unterminated quoted string");
10288 if (varnest != 0) {
10289 startlinno = plinno;
10290 synerror("Missing '}'");
10292 USTPUTC('\0', out);
10293 len = out - stackblock();
10294 out = stackblock();
10295 if (eofmark == NULL) {
10296 if ((c == '>' || c == '<')
10299 && (*out == '\0' || is_digit(*out))) {
10301 return lasttoken = TREDIR;
10306 quoteflag = quotef;
10307 backquotelist = bqlist;
10308 grabstackblock(len);
10310 return lasttoken = TWORD;
10311 /* end of readtoken routine */
10316 * Check to see whether we are at the end of the here document. When this
10317 * is called, c is set to the first character of the next input line. If
10318 * we are at the end of the here document, this routine sets the c to PEOF.
10327 while (c == '\t') {
10331 if (c == *eofmark) {
10332 if (pfgets(line, sizeof line) != NULL) {
10336 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10337 if (*p == '\n' && *q == '\0') {
10340 needprompt = doprompt;
10342 pushstring(line, strlen(line), NULL);
10347 goto checkend_return;
10352 * Parse a redirection operator. The variable "out" points to a string
10353 * specifying the fd to be redirected. The variable "c" contains the
10354 * first character of the redirection operator.
10361 np = (union node *)stalloc(sizeof (struct nfile));
10366 np->type = NAPPEND;
10375 } else { /* c == '<' */
10377 switch (c = pgetc()) {
10379 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10380 np = (union node *)stalloc(sizeof (struct nhere));
10384 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10385 heredoc->here = np;
10386 if ((c = pgetc()) == '-') {
10387 heredoc->striptabs = 1;
10389 heredoc->striptabs = 0;
10395 np->type = NFROMFD;
10399 np->type = NFROMTO;
10409 np->nfile.fd = digit_val(fd);
10411 goto parseredir_return;
10416 * Parse a substitution. At this point, we have read the dollar sign
10417 * and nothing else.
10425 static const char types[] = "}-+?=";
10430 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10434 } else if (c == '(') { /* $(command) or $((arith)) */
10435 if (pgetc() == '(') {
10442 USTPUTC(CTLVAR, out);
10443 typeloc = out - stackblock();
10444 USTPUTC(VSNORMAL, out);
10445 subtype = VSNORMAL;
10449 if ((c = pgetc()) == '}')
10452 subtype = VSLENGTH;
10457 if (c > PEOA && is_name(c)) {
10461 } while (c > PEOA && is_in_name(c));
10462 } else if (is_digit(c)) {
10466 } while (is_digit(c));
10468 else if (is_special(c)) {
10473 badsub: synerror("Bad substitution");
10477 if (subtype == 0) {
10484 p = strchr(types, c);
10487 subtype = p - types + VSNORMAL;
10493 subtype = c == '#' ? VSTRIMLEFT :
10506 if (dblquote || arinest)
10508 *(stackblock() + typeloc) = subtype | flags;
10509 if (subtype != VSNORMAL) {
10516 goto parsesub_return;
10521 * Called to parse command substitutions. Newstyle is set if the command
10522 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10523 * list of commands (passed by reference), and savelen is the number of
10524 * characters on the top of the stack which must be preserved.
10528 struct nodelist **nlpp;
10531 char *volatile str;
10532 struct jmploc jmploc;
10533 struct jmploc *volatile savehandler;
10537 (void) &saveprompt;
10540 savepbq = parsebackquote;
10541 if (setjmp(jmploc.loc)) {
10544 parsebackquote = 0;
10545 handler = savehandler;
10546 longjmp(handler->loc, 1);
10550 savelen = out - stackblock();
10552 str = ckmalloc(savelen);
10553 memcpy(str, stackblock(), savelen);
10555 savehandler = handler;
10559 /* We must read until the closing backquote, giving special
10560 treatment to some slashes, and then push the string and
10561 reread it as input, interpreting it normally. */
10568 STARTSTACKSTR(pout);
10574 switch (pc = pgetc()) {
10579 if ((pc = pgetc()) == '\n') {
10586 * If eating a newline, avoid putting
10587 * the newline into the new character
10588 * stream (via the STPUTC after the
10593 if (pc != '\\' && pc != '`' && pc != '$'
10594 && (!dblquote || pc != '"'))
10595 STPUTC('\\', pout);
10603 startlinno = plinno;
10604 synerror("EOF in backquote substitution");
10608 needprompt = doprompt;
10617 STPUTC('\0', pout);
10618 psavelen = pout - stackblock();
10619 if (psavelen > 0) {
10620 pstr = grabstackstr(pout);
10621 setinputstring(pstr);
10626 nlpp = &(*nlpp)->next;
10627 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10628 (*nlpp)->next = NULL;
10629 parsebackquote = oldstyle;
10632 saveprompt = doprompt;
10639 doprompt = saveprompt;
10641 if (readtoken() != TRP)
10648 * Start reading from old file again, ignoring any pushed back
10649 * tokens left from the backquote parsing
10654 while (stackblocksize() <= savelen)
10656 STARTSTACKSTR(out);
10658 memcpy(out, str, savelen);
10659 STADJUST(savelen, out);
10665 parsebackquote = savepbq;
10666 handler = savehandler;
10667 if (arinest || dblquote)
10668 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10670 USTPUTC(CTLBACKQ, out);
10672 goto parsebackq_oldreturn;
10674 goto parsebackq_newreturn;
10678 * Parse an arithmetic expansion (indicate start of one and set state)
10682 if (++arinest == 1) {
10683 prevsyntax = syntax;
10684 syntax = ARISYNTAX;
10685 USTPUTC(CTLARI, out);
10692 * we collapse embedded arithmetic expansion to
10693 * parenthesis, which should be equivalent
10697 goto parsearith_return;
10700 } /* end of readtoken */
10714 * Returns true if the text contains nothing to expand (no dollar signs
10726 while ((c = *p++) != '\0') {
10727 if (c == CTLQUOTEMARK)
10731 else if (BASESYNTAX[(int)c] == CCTL)
10739 * Return true if the argument is a legal variable name (a letter or
10740 * underscore followed by zero or more letters, underscores, and digits).
10744 goodname(char *name)
10752 if (! is_in_name(*p))
10760 * Called when an unexpected token is read during the parse. The argument
10761 * is the token that is expected, or -1 if more than one type of token can
10762 * occur at this point.
10772 fmtstr(msg, 64, "%s unexpected (expecting %s)",
10773 tokname[lasttoken], tokname[token]);
10775 fmtstr(msg, 64, "%s unexpected", tokname[lasttoken]);
10787 outfmt(&errout, "%s: %d: ", commandname, startlinno);
10788 outfmt(&errout, "Syntax error: %s\n", msg);
10789 error((char *)NULL);
10794 setprompt(int which)
10796 whichprompt = which;
10797 putprompt(getprompt(NULL));
10801 * called by editline -- any expansions to the prompt
10802 * should be added here.
10804 static const char *
10805 getprompt(void *unused)
10807 switch (whichprompt) {
10815 return "<internal prompt error>";
10820 isassignment(const char *word) {
10821 if (!is_name(*word)) {
10826 } while (is_in_name(*word));
10827 return *word == '=';
10830 static const char *const *
10831 findkwd(const char *s) {
10833 s, parsekwd, sizeof(parsekwd) / sizeof(const char *)
10836 /* $NetBSD: redir.c,v 1.22 2000/05/22 10:18:47 elric Exp $ */
10839 * Code for dealing with input/output redirection.
10842 #define EMPTY -2 /* marks an unused slot in redirtab */
10844 # define PIPESIZE 4096 /* amount of buffering in a pipe */
10846 # define PIPESIZE PIPE_BUF
10850 struct redirtab *redirlist;
10853 * We keep track of whether or not fd0 has been redirected. This is for
10854 * background commands, where we want to redirect fd0 to /dev/null only
10855 * if it hasn't already been redirected.
10857 static int fd0_redirected = 0;
10860 * We also keep track of where fileno2 goes.
10862 static int fileno2 = 2;
10864 static int openredirect __P((union node *));
10865 static void dupredirect __P((union node *, int, char[10 ]));
10866 static int openhere __P((union node *));
10867 static int noclobberopen __P((const char *));
10871 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
10872 * old file descriptors are stashed away so that the redirection can be
10873 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
10874 * standard output, and the standard error if it becomes a duplicate of
10875 * stdout, is saved in memory.
10879 redirect(redir, flags)
10884 struct redirtab *sv = NULL;
10889 char memory[10]; /* file descriptors to write to memory */
10891 for (i = 10 ; --i >= 0 ; )
10893 memory[1] = flags & REDIR_BACKQ;
10894 if (flags & REDIR_PUSH) {
10895 sv = ckmalloc(sizeof (struct redirtab));
10896 for (i = 0 ; i < 10 ; i++)
10897 sv->renamed[i] = EMPTY;
10898 sv->next = redirlist;
10901 for (n = redir ; n ; n = n->nfile.next) {
10904 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
10905 n->ndup.dupfd == fd)
10906 continue; /* redirect from/to same file descriptor */
10909 newfd = openredirect(n);
10910 if (((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) ||
10914 } else if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
10918 dupredirect(n, newfd, memory);
10928 error("%d: %s", fd, strerror(errno));
10934 if (flags & REDIR_PUSH) {
10935 sv->renamed[fd] = i;
10937 if (fd == fileno2) {
10941 } else if (fd != newfd) {
10947 dupredirect(n, newfd, memory);
10958 openredirect(redir)
10964 switch (redir->nfile.type) {
10966 fname = redir->nfile.expfname;
10967 if ((f = open(fname, O_RDONLY)) < 0)
10971 fname = redir->nfile.expfname;
10972 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
10976 /* Take care of noclobber mode. */
10978 fname = redir->nfile.expfname;
10979 if ((f = noclobberopen(fname)) < 0)
10984 fname = redir->nfile.expfname;
10986 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
10989 if ((f = creat(fname, 0666)) < 0)
10994 fname = redir->nfile.expfname;
10996 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
10999 if ((f = open(fname, O_WRONLY)) < 0
11000 && (f = creat(fname, 0666)) < 0)
11002 lseek(f, (off_t)0, 2);
11009 /* Fall through to eliminate warning. */
11016 f = openhere(redir);
11022 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
11024 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11029 dupredirect(redir, f, memory)
11034 int fd = redir->nfile.fd;
11037 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
11038 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
11039 if (memory[redir->ndup.dupfd])
11042 dup_as_newfd(redir->ndup.dupfd, fd);
11048 dup_as_newfd(f, fd);
11056 * Handle here documents. Normally we fork off a process to write the
11057 * data to a pipe. If the document is short, we can stuff the data in
11058 * the pipe without forking.
11069 error("Pipe call failed");
11070 if (redir->type == NHERE) {
11071 len = strlen(redir->nhere.doc->narg.text);
11072 if (len <= PIPESIZE) {
11073 xwrite(pip[1], redir->nhere.doc->narg.text, len);
11077 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
11079 signal(SIGINT, SIG_IGN);
11080 signal(SIGQUIT, SIG_IGN);
11081 signal(SIGHUP, SIG_IGN);
11083 signal(SIGTSTP, SIG_IGN);
11085 signal(SIGPIPE, SIG_DFL);
11086 if (redir->type == NHERE)
11087 xwrite(pip[1], redir->nhere.doc->narg.text, len);
11089 expandhere(redir->nhere.doc, pip[1]);
11100 * Undo the effects of the last redirection.
11105 struct redirtab *rp = redirlist;
11109 for (i = 0 ; i < 10 ; i++) {
11110 if (rp->renamed[i] != EMPTY) {
11114 if (rp->renamed[i] >= 0) {
11115 dup_as_newfd(rp->renamed[i], i);
11116 close(rp->renamed[i]);
11118 if (rp->renamed[i] == fileno2) {
11123 redirlist = rp->next;
11129 * Undo all redirections. Called on error or interrupt.
11147 /* Return true if fd 0 has already been redirected at least once. */
11149 fd0_redirected_p () {
11150 return fd0_redirected != 0;
11154 * Discard all saved file descriptors.
11159 struct redirtab *rp;
11162 for (rp = redirlist ; rp ; rp = rp->next) {
11163 for (i = 0 ; i < 10 ; i++) {
11164 if (rp->renamed[i] >= 0) {
11165 close(rp->renamed[i]);
11166 if (rp->renamed[i] == fileno2) {
11170 rp->renamed[i] = EMPTY;
11173 if (fileno2 != 2 && fileno2 >= 0) {
11182 * Copy a file descriptor to be >= to. Returns -1
11183 * if the source file descriptor is closed, EMPTY if there are no unused
11184 * file descriptors left.
11188 dup_as_newfd(from, to)
11194 newfd = fcntl(from, F_DUPFD, to);
11196 if (errno == EMFILE)
11199 error("%d: %s", from, strerror(errno));
11205 * Open a file in noclobber mode.
11206 * The code was copied from bash.
11209 noclobberopen(fname)
11213 struct stat finfo, finfo2;
11216 * If the file exists and is a regular file, return an error
11219 r = stat(fname, &finfo);
11220 if (r == 0 && S_ISREG(finfo.st_mode)) {
11226 * If the file was not present (r != 0), make sure we open it
11227 * exclusively so that if it is created before we open it, our open
11228 * will fail. Make sure that we do not truncate an existing file.
11229 * Note that we don't turn on O_EXCL unless the stat failed -- if the
11230 * file was not a regular file, we leave O_EXCL off.
11233 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
11234 fd = open(fname, O_WRONLY|O_CREAT, 0666);
11236 /* If the open failed, return the file descriptor right away. */
11241 * OK, the open succeeded, but the file may have been changed from a
11242 * non-regular file to a regular file between the stat and the open.
11243 * We are assuming that the O_EXCL open handles the case where FILENAME
11244 * did not exist and is symlinked to an existing file between the stat
11249 * If we can open it and fstat the file descriptor, and neither check
11250 * revealed that it was a regular file, and the file has not been
11251 * replaced, return the file descriptor.
11253 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
11254 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
11257 /* The file has been replaced. badness. */
11262 /* $NetBSD: setmode.c,v 1.28 2000/01/25 15:43:43 enami Exp $ */
11264 #ifdef __weak_alias
11265 __weak_alias(getmode,_getmode)
11266 __weak_alias(setmode,_setmode)
11270 #define S_ISTXT __S_ISVTX
11273 #define SET_LEN 6 /* initial # of bitcmd struct to malloc */
11274 #define SET_LEN_INCR 4 /* # of bitcmd structs to add as needed */
11276 typedef struct bitcmd {
11282 #define CMD2_CLR 0x01
11283 #define CMD2_SET 0x02
11284 #define CMD2_GBITS 0x04
11285 #define CMD2_OBITS 0x08
11286 #define CMD2_UBITS 0x10
11288 static BITCMD *addcmd __P((BITCMD *, int, int, int, u_int));
11289 static void compress_mode __P((BITCMD *));
11290 #ifdef SETMODE_DEBUG
11291 static void dumpmode __P((BITCMD *));
11295 * Given the old mode and an array of bitcmd structures, apply the operations
11296 * described in the bitcmd structures to the old mode, and return the new mode.
11297 * Note that there is no '=' command; a strict assignment is just a '-' (clear
11298 * bits) followed by a '+' (set bits).
11301 getmode(bbox, omode)
11306 mode_t clrval, newmode, value;
11308 _DIAGASSERT(bbox != NULL);
11310 set = (const BITCMD *)bbox;
11312 for (value = 0;; set++)
11315 * When copying the user, group or other bits around, we "know"
11316 * where the bits are in the mode so that we can do shifts to
11317 * copy them around. If we don't use shifts, it gets real
11318 * grundgy with lots of single bit checks and bit sets.
11321 value = (newmode & S_IRWXU) >> 6;
11325 value = (newmode & S_IRWXG) >> 3;
11329 value = newmode & S_IRWXO;
11330 common: if (set->cmd2 & CMD2_CLR) {
11332 (set->cmd2 & CMD2_SET) ? S_IRWXO : value;
11333 if (set->cmd2 & CMD2_UBITS)
11334 newmode &= ~((clrval<<6) & set->bits);
11335 if (set->cmd2 & CMD2_GBITS)
11336 newmode &= ~((clrval<<3) & set->bits);
11337 if (set->cmd2 & CMD2_OBITS)
11338 newmode &= ~(clrval & set->bits);
11340 if (set->cmd2 & CMD2_SET) {
11341 if (set->cmd2 & CMD2_UBITS)
11342 newmode |= (value<<6) & set->bits;
11343 if (set->cmd2 & CMD2_GBITS)
11344 newmode |= (value<<3) & set->bits;
11345 if (set->cmd2 & CMD2_OBITS)
11346 newmode |= value & set->bits;
11351 newmode |= set->bits;
11355 newmode &= ~set->bits;
11359 if (omode & (S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH))
11360 newmode |= set->bits;
11365 #ifdef SETMODE_DEBUG
11366 (void)printf("getmode:%04o -> %04o\n", omode, newmode);
11372 #define ADDCMD(a, b, c, d) do { \
11373 if (set >= endset) { \
11375 setlen += SET_LEN_INCR; \
11376 newset = realloc(saveset, sizeof(BITCMD) * setlen); \
11377 if (newset == NULL) { \
11381 set = newset + (set - saveset); \
11382 saveset = newset; \
11383 endset = newset + (setlen - 2); \
11385 set = addcmd(set, (a), (b), (c), (d)); \
11386 } while (/*CONSTCOND*/0)
11388 #define STANDARD_BITS (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
11396 BITCMD *set, *saveset, *endset;
11397 sigset_t mysigset, sigoset;
11399 int equalopdone = 0; /* pacify gcc */
11400 int permXbits, setlen;
11406 * Get a copy of the mask for the permissions that are mask relative.
11407 * Flip the bits, we want what's not set. Since it's possible that
11408 * the caller is opening files inside a signal handler, protect them
11411 sigfillset(&mysigset);
11412 (void)sigprocmask(SIG_BLOCK, &mysigset, &sigoset);
11413 (void)umask(mask = umask(0));
11415 (void)sigprocmask(SIG_SETMASK, &sigoset, NULL);
11417 setlen = SET_LEN + 2;
11419 if ((set = malloc((u_int)(sizeof(BITCMD) * setlen))) == NULL)
11422 endset = set + (setlen - 2);
11425 * If an absolute number, get it and return; disallow non-octal digits
11428 if (isdigit((unsigned char)*p)) {
11429 perm = (mode_t)strtol(p, &ep, 8);
11430 if (*ep || perm & ~(STANDARD_BITS|S_ISTXT)) {
11434 ADDCMD('=', (STANDARD_BITS|S_ISTXT), perm, mask);
11440 * Build list of structures to set/clear/copy bits as described by
11441 * each clause of the symbolic mode.
11444 /* First, find out which bits might be modified. */
11445 for (who = 0;; ++p) {
11448 who |= STANDARD_BITS;
11451 who |= S_ISUID|S_IRWXU;
11454 who |= S_ISGID|S_IRWXG;
11464 getop: if ((op = *p++) != '+' && op != '-' && op != '=') {
11472 for (perm = 0, permXbits = 0;; ++p) {
11475 perm |= S_IRUSR|S_IRGRP|S_IROTH;
11479 * If specific bits where requested and
11480 * only "other" bits ignore set-id.
11482 if (who == 0 || (who & ~S_IRWXO))
11483 perm |= S_ISUID|S_ISGID;
11487 * If specific bits where requested and
11488 * only "other" bits ignore set-id.
11490 if (who == 0 || (who & ~S_IRWXO)) {
11496 perm |= S_IWUSR|S_IWGRP|S_IWOTH;
11499 permXbits = S_IXUSR|S_IXGRP|S_IXOTH;
11502 perm |= S_IXUSR|S_IXGRP|S_IXOTH;
11508 * When ever we hit 'u', 'g', or 'o', we have
11509 * to flush out any partial mode that we have,
11510 * and then do the copying of the mode bits.
11513 ADDCMD(op, who, perm, mask);
11518 if (op == '+' && permXbits) {
11519 ADDCMD('X', who, permXbits, mask);
11522 ADDCMD(*p, who, op, mask);
11527 * Add any permissions that we haven't already
11530 if (perm || (op == '=' && !equalopdone)) {
11533 ADDCMD(op, who, perm, mask);
11537 ADDCMD('X', who, permXbits, mask);
11551 #ifdef SETMODE_DEBUG
11552 (void)printf("Before compress_mode()\n");
11555 compress_mode(saveset);
11556 #ifdef SETMODE_DEBUG
11557 (void)printf("After compress_mode()\n");
11564 addcmd(set, op, who, oparg, mask)
11571 _DIAGASSERT(set != NULL);
11576 set->bits = who ? who : STANDARD_BITS;
11585 set->bits = (who ? who : mask) & oparg;
11593 set->cmd2 = ((who & S_IRUSR) ? CMD2_UBITS : 0) |
11594 ((who & S_IRGRP) ? CMD2_GBITS : 0) |
11595 ((who & S_IROTH) ? CMD2_OBITS : 0);
11596 set->bits = (mode_t)~0;
11598 set->cmd2 = CMD2_UBITS | CMD2_GBITS | CMD2_OBITS;
11603 set->cmd2 |= CMD2_SET;
11604 else if (oparg == '-')
11605 set->cmd2 |= CMD2_CLR;
11606 else if (oparg == '=')
11607 set->cmd2 |= CMD2_SET|CMD2_CLR;
11613 #ifdef SETMODE_DEBUG
11619 _DIAGASSERT(set != NULL);
11621 for (; set->cmd; ++set)
11622 (void)printf("cmd: '%c' bits %04o%s%s%s%s%s%s\n",
11623 set->cmd, set->bits, set->cmd2 ? " cmd2:" : "",
11624 set->cmd2 & CMD2_CLR ? " CLR" : "",
11625 set->cmd2 & CMD2_SET ? " SET" : "",
11626 set->cmd2 & CMD2_UBITS ? " UBITS" : "",
11627 set->cmd2 & CMD2_GBITS ? " GBITS" : "",
11628 set->cmd2 & CMD2_OBITS ? " OBITS" : "");
11633 * Given an array of bitcmd structures, compress by compacting consecutive
11634 * '+', '-' and 'X' commands into at most 3 commands, one of each. The 'u',
11635 * 'g' and 'o' commands continue to be separate. They could probably be
11636 * compacted, but it's not worth the effort.
11643 int setbits, clrbits, Xbits, op;
11645 _DIAGASSERT(set != NULL);
11647 for (nset = set;;) {
11648 /* Copy over any 'u', 'g' and 'o' commands. */
11649 while ((op = nset->cmd) != '+' && op != '-' && op != 'X') {
11655 for (setbits = clrbits = Xbits = 0;; nset++) {
11656 if ((op = nset->cmd) == '-') {
11657 clrbits |= nset->bits;
11658 setbits &= ~nset->bits;
11659 Xbits &= ~nset->bits;
11660 } else if (op == '+') {
11661 setbits |= nset->bits;
11662 clrbits &= ~nset->bits;
11663 Xbits &= ~nset->bits;
11664 } else if (op == 'X')
11665 Xbits |= nset->bits & ~setbits;
11672 set->bits = clrbits;
11678 set->bits = setbits;
11689 /* $NetBSD: show.c,v 1.18 1999/10/08 21:10:44 pk Exp $ */
11693 static void shtree __P((union node *, int, char *, FILE*));
11694 static void shcmd __P((union node *, FILE *));
11695 static void sharg __P((union node *, FILE *));
11696 static void indent __P((int, char *, FILE *));
11697 static void trstring __P((char *));
11704 trputs("showtree called\n");
11705 shtree(n, 1, NULL, stdout);
11710 shtree(n, ind, pfx, fp)
11716 struct nodelist *lp;
11722 indent(ind, pfx, fp);
11733 shtree(n->nbinary.ch1, ind, NULL, fp);
11736 shtree(n->nbinary.ch2, ind, NULL, fp);
11744 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
11749 if (n->npipe.backgnd)
11755 fprintf(fp, "<node type %d>", n->type);
11775 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11781 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11784 switch (np->nfile.type) {
11785 case NTO: s = ">"; dftfd = 1; break;
11786 case NAPPEND: s = ">>"; dftfd = 1; break;
11787 case NTOFD: s = ">&"; dftfd = 1; break;
11788 case NTOOV: s = ">|"; dftfd = 1; break;
11789 case NFROM: s = "<"; dftfd = 0; break;
11790 case NFROMFD: s = "<&"; dftfd = 0; break;
11791 case NFROMTO: s = "<>"; dftfd = 0; break;
11792 default: s = "*error*"; dftfd = 0; break;
11794 if (np->nfile.fd != dftfd)
11795 fprintf(fp, "%d", np->nfile.fd);
11797 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11798 fprintf(fp, "%d", np->ndup.dupfd);
11800 sharg(np->nfile.fname, fp);
11814 struct nodelist *bqlist;
11817 if (arg->type != NARG) {
11818 printf("<node type %d>\n", arg->type);
11822 bqlist = arg->narg.backquote;
11823 for (p = arg->narg.text ; *p ; p++) {
11832 if (subtype == VSLENGTH)
11838 if (subtype & VSNUL)
11841 switch (subtype & VSTYPE) {
11860 case VSTRIMLEFTMAX:
11867 case VSTRIMRIGHTMAX:
11874 printf("<subtype %d>", subtype);
11881 case CTLBACKQ|CTLQUOTE:
11884 shtree(bqlist->n, -1, NULL, fp);
11896 indent(amount, pfx, fp)
11903 for (i = 0 ; i < amount ; i++) {
11904 if (pfx && i == amount - 1)
11922 static int debug = 1;
11924 static int debug = 0;
11932 if (tracefile == NULL)
11934 putc(c, tracefile);
11940 trace(const char *fmt, ...)
11948 fmt = va_arg(va, char *);
11950 if (tracefile != NULL) {
11951 (void) vfprintf(tracefile, fmt, va);
11952 if (strchr(fmt, '\n'))
11953 (void) fflush(tracefile);
11963 if (tracefile == NULL)
11965 fputs(s, tracefile);
11966 if (strchr(s, '\n'))
11978 if (tracefile == NULL)
11980 putc('"', tracefile);
11981 for (p = s ; *p ; p++) {
11983 case '\n': c = 'n'; goto backslash;
11984 case '\t': c = 't'; goto backslash;
11985 case '\r': c = 'r'; goto backslash;
11986 case '"': c = '"'; goto backslash;
11987 case '\\': c = '\\'; goto backslash;
11988 case CTLESC: c = 'e'; goto backslash;
11989 case CTLVAR: c = 'v'; goto backslash;
11990 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11991 case CTLBACKQ: c = 'q'; goto backslash;
11992 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
11993 backslash: putc('\\', tracefile);
11994 putc(c, tracefile);
11997 if (*p >= ' ' && *p <= '~')
11998 putc(*p, tracefile);
12000 putc('\\', tracefile);
12001 putc(*p >> 6 & 03, tracefile);
12002 putc(*p >> 3 & 07, tracefile);
12003 putc(*p & 07, tracefile);
12008 putc('"', tracefile);
12016 if (tracefile == NULL)
12021 putc(' ', tracefile);
12023 putc('\n', tracefile);
12038 #ifdef not_this_way
12041 if ((p = getenv("HOME")) == NULL) {
12042 if (geteuid() == 0)
12048 strcat(s, "/trace");
12051 scopy("./trace", s);
12052 #endif /* not_this_way */
12053 if ((tracefile = fopen(s, "a")) == NULL) {
12054 fprintf(stderr, "Can't open %s\n", s);
12058 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
12059 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
12061 fputs("\nTracing started.\n", tracefile);
12068 * This file was generated by the mksyntax program.
12071 /* syntax table used when not in quotes */
12072 static const char basesyntax[257] = {
12073 CEOF, CSPCL, CWORD, CCTL,
12074 CCTL, CCTL, CCTL, CCTL,
12075 CCTL, CCTL, CCTL, 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, CWORD,
12106 CWORD, CWORD, CWORD, CWORD,
12107 CWORD, CWORD, CWORD, CSPCL,
12108 CNL, CWORD, CWORD, CWORD,
12109 CWORD, CWORD, CWORD, CWORD,
12110 CWORD, CWORD, CWORD, CWORD,
12111 CWORD, CWORD, CWORD, CWORD,
12112 CWORD, CWORD, CWORD, CWORD,
12113 CWORD, CWORD, CSPCL, CWORD,
12114 CDQUOTE, CWORD, CVAR, CWORD,
12115 CSPCL, CSQUOTE, CSPCL, CSPCL,
12116 CWORD, CWORD, CWORD, CWORD,
12117 CWORD, CWORD, CWORD, CWORD,
12118 CWORD, CWORD, CWORD, CWORD,
12119 CWORD, CWORD, CWORD, CWORD,
12120 CWORD, CSPCL, CSPCL, CWORD,
12121 CSPCL, 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, CWORD, CWORD,
12127 CWORD, CWORD, CWORD, CWORD,
12128 CWORD, CWORD, CBACK, CWORD,
12129 CWORD, CWORD, CBQUOTE, CWORD,
12130 CWORD, CWORD, CWORD, CWORD,
12131 CWORD, CWORD, CWORD, CWORD,
12132 CWORD, CWORD, CWORD, CWORD,
12133 CWORD, CWORD, CWORD, CWORD,
12134 CWORD, CWORD, CWORD, CWORD,
12135 CWORD, CWORD, CWORD, CWORD,
12136 CWORD, CWORD, CSPCL, CENDVAR,
12140 /* syntax table used when in double quotes */
12141 static const char dqsyntax[257] = {
12142 CEOF, CIGN, CWORD, CCTL,
12143 CCTL, CCTL, CCTL, CCTL,
12144 CCTL, CCTL, CCTL, 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 CWORD, CWORD, CWORD, CWORD,
12176 CWORD, CWORD, CWORD, CWORD,
12177 CNL, CWORD, CWORD, CWORD,
12178 CWORD, CWORD, CWORD, CWORD,
12179 CWORD, CWORD, CWORD, CWORD,
12180 CWORD, CWORD, CWORD, CWORD,
12181 CWORD, CWORD, CWORD, CWORD,
12182 CWORD, CWORD, CWORD, CCTL,
12183 CENDQUOTE,CWORD, CVAR, CWORD,
12184 CWORD, CWORD, CWORD, CWORD,
12185 CCTL, CWORD, CWORD, CCTL,
12186 CWORD, CCTL, CWORD, CWORD,
12187 CWORD, CWORD, CWORD, CWORD,
12188 CWORD, CWORD, CWORD, CWORD,
12189 CCTL, CWORD, CWORD, CCTL,
12190 CWORD, CCTL, CWORD, CWORD,
12191 CWORD, CWORD, CWORD, CWORD,
12192 CWORD, CWORD, CWORD, CWORD,
12193 CWORD, CWORD, CWORD, CWORD,
12194 CWORD, CWORD, CWORD, CWORD,
12195 CWORD, CWORD, CWORD, CWORD,
12196 CWORD, CWORD, CWORD, CWORD,
12197 CWORD, CCTL, CBACK, CCTL,
12198 CWORD, CWORD, CBQUOTE, 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, CWORD,
12204 CWORD, CWORD, CWORD, CWORD,
12205 CWORD, CWORD, CWORD, CENDVAR,
12209 /* syntax table used when in single quotes */
12210 static const char sqsyntax[257] = {
12211 CEOF, CIGN, CWORD, CCTL,
12212 CCTL, CCTL, CCTL, CCTL,
12213 CCTL, CCTL, CCTL, 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 CWORD, CWORD, CWORD, CWORD,
12245 CWORD, CWORD, CWORD, CWORD,
12246 CNL, CWORD, CWORD, CWORD,
12247 CWORD, CWORD, CWORD, CWORD,
12248 CWORD, CWORD, CWORD, CWORD,
12249 CWORD, CWORD, CWORD, CWORD,
12250 CWORD, CWORD, CWORD, CWORD,
12251 CWORD, CWORD, CWORD, CCTL,
12252 CWORD, CWORD, CWORD, CWORD,
12253 CWORD, CENDQUOTE,CWORD, CWORD,
12254 CCTL, CWORD, CWORD, CCTL,
12255 CWORD, CCTL, CWORD, CWORD,
12256 CWORD, CWORD, CWORD, CWORD,
12257 CWORD, CWORD, CWORD, CWORD,
12258 CCTL, CWORD, CWORD, CCTL,
12259 CWORD, CCTL, CWORD, CWORD,
12260 CWORD, CWORD, CWORD, CWORD,
12261 CWORD, CWORD, CWORD, CWORD,
12262 CWORD, CWORD, CWORD, CWORD,
12263 CWORD, CWORD, CWORD, CWORD,
12264 CWORD, CWORD, CWORD, CWORD,
12265 CWORD, CWORD, CWORD, CWORD,
12266 CWORD, CCTL, CCTL, CCTL,
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 CWORD, CWORD, CWORD, CWORD,
12274 CWORD, CWORD, CWORD, CWORD,
12278 /* syntax table used when in arithmetic */
12279 static const char arisyntax[257] = {
12280 CEOF, CIGN, CWORD, CCTL,
12281 CCTL, CCTL, CCTL, CCTL,
12282 CCTL, CCTL, CCTL, 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 CWORD, CWORD, CWORD, CWORD,
12314 CWORD, CWORD, CWORD, CWORD,
12315 CNL, CWORD, CWORD, CWORD,
12316 CWORD, CWORD, CWORD, CWORD,
12317 CWORD, CWORD, CWORD, CWORD,
12318 CWORD, CWORD, CWORD, CWORD,
12319 CWORD, CWORD, CWORD, CWORD,
12320 CWORD, CWORD, CWORD, CWORD,
12321 CDQUOTE, CWORD, CVAR, CWORD,
12322 CWORD, CSQUOTE, CLP, CRP,
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, CWORD, CWORD,
12334 CWORD, CWORD, CWORD, CWORD,
12335 CWORD, CWORD, CBACK, CWORD,
12336 CWORD, CWORD, CBQUOTE, 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, CWORD,
12342 CWORD, CWORD, CWORD, CWORD,
12343 CWORD, CWORD, CWORD, CENDVAR,
12347 /* character classification table */
12348 static const char is_type[257] = {
12390 0, ISSPECL, ISSPECL, 0,
12392 ISSPECL, 0, 0, ISSPECL,
12393 0, 0, ISDIGIT, ISDIGIT,
12394 ISDIGIT, ISDIGIT, ISDIGIT, ISDIGIT,
12395 ISDIGIT, ISDIGIT, ISDIGIT, ISDIGIT,
12397 0, ISSPECL, ISSPECL, ISUPPER,
12398 ISUPPER, ISUPPER, ISUPPER, ISUPPER,
12399 ISUPPER, ISUPPER, ISUPPER, ISUPPER,
12400 ISUPPER, ISUPPER, ISUPPER, ISUPPER,
12401 ISUPPER, ISUPPER, ISUPPER, ISUPPER,
12402 ISUPPER, ISUPPER, ISUPPER, ISUPPER,
12403 ISUPPER, ISUPPER, ISUPPER, ISUPPER,
12405 0, ISUNDER, 0, ISLOWER,
12406 ISLOWER, ISLOWER, ISLOWER, ISLOWER,
12407 ISLOWER, ISLOWER, ISLOWER, ISLOWER,
12408 ISLOWER, ISLOWER, ISLOWER, ISLOWER,
12409 ISLOWER, ISLOWER, ISLOWER, ISLOWER,
12410 ISLOWER, ISLOWER, ISLOWER, ISLOWER,
12411 ISLOWER, ISLOWER, ISLOWER, ISLOWER,
12415 /* $NetBSD: trap.c,v 1.25 2001/02/04 19:52:07 christos Exp $ */
12418 * The trap builtin.
12422 trapcmd(argc, argv)
12431 for (signo = 0 ; signo < NSIG ; signo++) {
12432 if (trap[signo] != NULL) {
12435 p = single_quote(trap[signo]);
12436 out1fmt("trap -- %s %s\n", p,
12437 signal_names[signo] + (signo ? 3 : 0)
12450 if ((signo = decode_signal(*ap, 0)) < 0)
12451 error("%s: bad trap", *ap);
12454 if (action[0] == '-' && action[1] == '\0')
12457 action = savestr(action);
12460 ckfree(trap[signo]);
12461 trap[signo] = action;
12473 * Clear traps on a fork.
12480 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
12481 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
12485 if (tp != &trap[0])
12486 setsignal(tp - trap);
12495 * Set the signal handler for the specified signal. The routine figures
12496 * out what it should be set to.
12505 struct sigaction act;
12507 if ((t = trap[signo]) == NULL)
12509 else if (*t != '\0')
12513 if (rootshell && action == S_DFL) {
12516 if (iflag || minusc || sflag == 0)
12543 t = &sigmode[signo - 1];
12546 * current setting unknown
12548 if (sigaction(signo, 0, &act) == -1) {
12550 * Pretend it worked; maybe we should give a warning
12551 * here, but other shells don't. We don't alter
12552 * sigmode, so that we retry every time.
12556 if (act.sa_handler == SIG_IGN) {
12557 if (mflag && (signo == SIGTSTP ||
12558 signo == SIGTTIN || signo == SIGTTOU)) {
12559 *t = S_IGN; /* don't hard ignore these */
12563 *t = S_RESET; /* force to be set */
12566 if (*t == S_HARD_IGN || *t == action)
12570 act.sa_handler = onsig;
12573 act.sa_handler = SIG_IGN;
12576 act.sa_handler = SIG_DFL;
12580 sigemptyset(&act.sa_mask);
12581 sigaction(signo, &act, 0);
12592 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
12593 signal(signo, SIG_IGN);
12595 sigmode[signo - 1] = S_HARD_IGN;
12607 for (sm = sigmode ; sm < sigmode + NSIG - 1; sm++) {
12624 if (signo == SIGINT && trap[SIGINT] == NULL) {
12628 gotsig[signo - 1] = 1;
12635 * Called to execute a trap. Perhaps we should avoid entering new trap
12636 * handlers while we are executing a trap handler.
12645 for (i = 1 ; ; i++) {
12652 savestatus=exitstatus;
12653 evalstring(trap[i], 0);
12654 exitstatus=savestatus;
12663 * Controls whether the shell is interactive or not.
12671 static int is_interactive;
12673 if (on == is_interactive)
12676 setsignal(SIGQUIT);
12677 setsignal(SIGTERM);
12679 is_interactive = on;
12685 * Called to exit the shell.
12692 struct jmploc loc1, loc2;
12695 TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
12696 if (setjmp(loc1.loc)) {
12699 if (setjmp(loc2.loc)) {
12703 if ((p = trap[0]) != NULL && *p != '\0') {
12707 l1: handler = &loc2; /* probably unnecessary */
12716 static int decode_signal(const char *string, int minsig)
12720 if (is_number(string)) {
12721 signo = atoi(string);
12722 if (signo >= NSIG) {
12732 for (; signo < NSIG; signo++) {
12733 if (!strcasecmp(string, &(signal_names[signo])[3])) {
12737 if (!strcasecmp(string, signal_names[signo])) {
12744 /* $NetBSD: var.c,v 1.27 2001/02/04 19:52:07 christos Exp $ */
12746 #define VTABSIZE 39
12753 void (*func) __P((const char *));
12756 struct localvar *localvars;
12768 struct var voptind;
12770 static const char defpathvar[] =
12771 "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
12773 static const char defifsvar[] = "IFS= \t\n";
12775 static const char defifs[] = " \t\n";
12778 static const struct varinit varinit[] = {
12780 { &vatty, VSTRFIXED|VTEXTFIXED|VUNSET, "ATTY=",
12784 { &vifs, VSTRFIXED|VTEXTFIXED, defifsvar,
12786 { &vifs, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS=",
12789 { &vmail, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL=",
12791 { &vmpath, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH=",
12793 { &vpath, VSTRFIXED|VTEXTFIXED, defpathvar,
12796 * vps1 depends on uid
12798 { &vps2, VSTRFIXED|VTEXTFIXED, "PS2=> ",
12800 { &voptind, VSTRFIXED|VTEXTFIXED, "OPTIND=1",
12806 struct var *vartab[VTABSIZE];
12808 static struct var **hashvar __P((const char *));
12809 static void showvars __P((const char *, int, int));
12810 static struct var **findvar __P((struct var **, const char *));
12813 * Initialize the varable symbol tables and import the environment
12820 static char **environ;
12826 for (envp = environ ; *envp ; envp++) {
12827 if (strchr(*envp, '=')) {
12828 setvareq(*envp, VEXPORT|VTEXTFIXED);
12832 fmtstr(ppid, sizeof(ppid), "%d", (int) getppid());
12833 setvar("PPID", ppid, 0);
12839 * This routine initializes the builtin variables. It is called when the
12840 * shell is initialized and again when a shell procedure is spawned.
12845 const struct varinit *ip;
12849 for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
12850 if ((vp->flags & VEXPORT) == 0) {
12851 vpp = hashvar(ip->text);
12854 vp->text = strdup(ip->text);
12855 vp->flags = ip->flags;
12856 vp->func = ip->func;
12860 * PS1 depends on uid
12862 if ((vps1.flags & VEXPORT) == 0) {
12863 vpp = hashvar("PS1=");
12866 vps1.text = strdup(geteuid() ? "PS1=$ " : "PS1=# ");
12867 vps1.flags = VSTRFIXED|VTEXTFIXED;
12872 * Set the value of a variable. The flags argument is ored with the
12873 * flags of the variable. If val is NULL, the variable is unset.
12877 setvar(name, val, flags)
12878 const char *name, *val;
12894 if (! is_in_name(*p)) {
12895 if (*p == '\0' || *p == '=')
12901 namelen = p - name;
12903 error("%.*s: bad variable name", namelen, name);
12904 len = namelen + 2; /* 2 is space for '=' and '\0' */
12908 len += vallen = strlen(val);
12911 nameeq = ckmalloc(len);
12912 memcpy(nameeq, name, namelen);
12913 nameeq[namelen] = '=';
12915 memcpy(nameeq + namelen + 1, val, vallen + 1);
12917 nameeq[namelen + 1] = '\0';
12919 setvareq(nameeq, flags);
12926 * Same as setvar except that the variable and value are passed in
12927 * the first argument as name=value. Since the first argument will
12928 * be actually stored in the table, it should not be a string that
12937 struct var *vp, **vpp;
12940 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
12941 if ((vp = *findvar(vpp, s))) {
12942 if (vp->flags & VREADONLY) {
12943 size_t len = strchr(s, '=') - s;
12944 error("%.*s: is read only", len, s);
12948 if (vp->func && (flags & VNOFUNC) == 0)
12949 (*vp->func)(strchr(s, '=') + 1);
12951 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12954 vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET);
12955 vp->flags |= flags;
12959 * We could roll this to a function, to handle it as
12960 * a regular variable function callback, but why bother?
12962 if (iflag && (vp == &vmpath || (vp == &vmail && !mpathset())))
12968 vp = ckmalloc(sizeof (*vp));
12979 * Process a linked list of variable assignments.
12984 struct strlist *mylist;
12986 struct strlist *lp;
12989 for (lp = mylist ; lp ; lp = lp->next) {
12990 setvareq(savestr(lp->text), 0);
12998 * Find the value of a variable. Returns NULL if not set.
13007 if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
13008 return strchr(v->text, '=') + 1;
13016 * Search the environment of a builtin command.
13023 struct strlist *sp;
13025 for (sp = cmdenviron ; sp ; sp = sp->next) {
13026 if (varequal(sp->text, name))
13027 return strchr(sp->text, '=') + 1;
13029 return lookupvar(name);
13035 * Generate a list of exported variables. This routine is used to construct
13036 * the third argument to execve when executing a program.
13048 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
13049 for (vp = *vpp ; vp ; vp = vp->next)
13050 if (vp->flags & VEXPORT)
13053 ep = env = stalloc((nenv + 1) * sizeof *env);
13054 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
13055 for (vp = *vpp ; vp ; vp = vp->next)
13056 if (vp->flags & VEXPORT)
13065 * Called when a shell procedure is invoked to clear out nonexported
13066 * variables. It is also necessary to reallocate variables of with
13067 * VSTACK set since these are currently allocated on the stack.
13071 static void shprocvar __P((void));
13081 struct var *vp, **prev;
13083 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
13084 for (prev = vpp ; (vp = *prev) != NULL ; ) {
13085 if ((vp->flags & VEXPORT) == 0) {
13087 if ((vp->flags & VTEXTFIXED) == 0)
13089 if ((vp->flags & VSTRFIXED) == 0)
13092 if (vp->flags & VSTACK) {
13093 vp->text = savestr(vp->text);
13094 vp->flags &=~ VSTACK;
13106 * Command to list all variables which are set. Currently this command
13107 * is invoked from the set command when the set command is called without
13112 showvarscmd(argc, argv)
13116 showvars(nullstr, VUNSET, VUNSET);
13123 * The export and readonly commands.
13127 exportcmd(argc, argv)
13134 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
13137 listsetvar(cmdenviron);
13138 pflag = (nextopt("p") == 'p');
13139 if (argc > 1 && !pflag) {
13140 while ((name = *argptr++) != NULL) {
13141 if ((p = strchr(name, '=')) != NULL) {
13144 if ((vp = *findvar(hashvar(name), name))) {
13149 setvar(name, p, flag);
13153 showvars(argv[0], flag, 0);
13160 * The "local" command.
13164 localcmd(argc, argv)
13170 if (! in_function())
13171 error("Not in a function");
13172 while ((name = *argptr++) != NULL) {
13180 * Make a variable a local variable. When a variable is made local, it's
13181 * value and flags are saved in a localvar structure. The saved values
13182 * will be restored when the shell function returns. We handle the name
13183 * "-" as a special case.
13190 struct localvar *lvp;
13195 lvp = ckmalloc(sizeof (struct localvar));
13196 if (name[0] == '-' && name[1] == '\0') {
13198 p = ckmalloc(sizeof optlist);
13199 lvp->text = memcpy(p, optlist, sizeof optlist);
13202 vpp = hashvar(name);
13203 vp = *findvar(vpp, name);
13205 if (strchr(name, '='))
13206 setvareq(savestr(name), VSTRFIXED);
13208 setvar(name, NULL, VSTRFIXED);
13209 vp = *vpp; /* the new variable */
13211 lvp->flags = VUNSET;
13213 lvp->text = vp->text;
13214 lvp->flags = vp->flags;
13215 vp->flags |= VSTRFIXED|VTEXTFIXED;
13216 if (strchr(name, '='))
13217 setvareq(savestr(name), 0);
13221 lvp->next = localvars;
13228 * Called after a function returns.
13233 struct localvar *lvp;
13236 while ((lvp = localvars) != NULL) {
13237 localvars = lvp->next;
13239 if (vp == NULL) { /* $- saved */
13240 memcpy(optlist, lvp->text, sizeof optlist);
13242 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
13243 (void)unsetvar(vp->text);
13245 if ((vp->flags & VTEXTFIXED) == 0)
13247 vp->flags = lvp->flags;
13248 vp->text = lvp->text;
13256 setvarcmd(argc, argv)
13261 return unsetcmd(argc, argv);
13262 else if (argc == 3)
13263 setvar(argv[1], argv[2], 0);
13265 error("List assignment not implemented");
13271 * The unset builtin command. We unset the function before we unset the
13272 * variable to allow a function to be unset when there is a readonly variable
13273 * with the same name.
13277 unsetcmd(argc, argv)
13287 while ((i = nextopt("vf")) != '\0') {
13293 if (flg_func == 0 && flg_var == 0)
13296 for (ap = argptr; *ap ; ap++) {
13300 ret |= unsetvar(*ap);
13307 * Unset the specified variable.
13317 vpp = findvar(hashvar(s), s);
13320 if (vp->flags & VREADONLY)
13323 if (*(strchr(vp->text, '=') + 1) != '\0')
13324 setvar(s, nullstr, 0);
13325 vp->flags &= ~VEXPORT;
13326 vp->flags |= VUNSET;
13327 if ((vp->flags & VSTRFIXED) == 0) {
13328 if ((vp->flags & VTEXTFIXED) == 0)
13343 * Find the appropriate entry in the hash table from the name.
13346 static struct var **
13350 unsigned int hashval;
13352 hashval = ((unsigned char) *p) << 4;
13353 while (*p && *p != '=')
13354 hashval += (unsigned char) *p++;
13355 return &vartab[hashval % VTABSIZE];
13361 * Returns true if the two strings specify the same varable. The first
13362 * variable name is terminated by '='; the second may be terminated by
13363 * either '=' or '\0'.
13370 while (*p == *q++) {
13374 if (*p == '=' && *(q - 1) == '\0')
13380 showvars(const char *myprefix, int mask, int xor)
13384 const char *sep = myprefix == nullstr ? myprefix : spcstr;
13386 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
13387 for (vp = *vpp ; vp ; vp = vp->next) {
13388 if ((vp->flags & mask) ^ xor) {
13392 p = strchr(vp->text, '=') + 1;
13393 len = p - vp->text;
13394 p = single_quote(p);
13397 "%s%s%.*s%s\n", myprefix, sep, len,
13406 static struct var **
13407 findvar(struct var **vpp, const char *name)
13409 for (; *vpp; vpp = &(*vpp)->next) {
13410 if (varequal((*vpp)->text, name)) {
13418 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
13419 * This file contains code for the times builtin.
13420 * $Id: ash.c,v 1.2 2001/06/28 07:46:40 andersen Exp $
13422 static int timescmd (int argc, char **argv)
13425 long int clk_tck = sysconf(_SC_CLK_TCK);
13428 printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
13429 (int) (buf.tms_utime / clk_tck / 60),
13430 ((double) buf.tms_utime) / clk_tck,
13431 (int) (buf.tms_stime / clk_tck / 60),
13432 ((double) buf.tms_stime) / clk_tck,
13433 (int) (buf.tms_cutime / clk_tck / 60),
13434 ((double) buf.tms_cutime) / clk_tck,
13435 (int) (buf.tms_cstime / clk_tck / 60),
13436 ((double) buf.tms_cstime) / clk_tck);
13442 * Copyright (c) 1989, 1991, 1993, 1994
13443 * The Regents of the University of California. All rights reserved.
13445 * This code is derived from software contributed to Berkeley by
13446 * Kenneth Almquist.
13448 * Redistribution and use in source and binary forms, with or without
13449 * modification, are permitted provided that the following conditions
13451 * 1. Redistributions of source code must retain the above copyright
13452 * notice, this list of conditions and the following disclaimer.
13453 * 2. Redistributions in binary form must reproduce the above copyright
13454 * notice, this list of conditions and the following disclaimer in the
13455 * documentation and/or other materials provided with the distribution.
13457 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
13458 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
13460 * 4. Neither the name of the University nor the names of its contributors
13461 * may be used to endorse or promote products derived from this software
13462 * without specific prior written permission.
13464 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13465 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13466 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13467 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13468 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13469 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13470 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13471 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13472 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13473 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF