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 busybox.
30 * Original copyright notice is retained at the end of this file.
36 #undef ASH_MATH_SUPPORT
58 #include <sys/cdefs.h>
59 #include <sys/ioctl.h>
60 #include <sys/param.h>
61 #include <sys/resource.h>
63 #include <sys/times.h>
64 #include <sys/types.h>
68 #if !defined(FNMATCH_BROKEN)
71 #if !defined(GLOB_BROKEN)
77 #undef CEOF /* syntax.h redefines this */
85 #define _DIAGASSERT(x)
89 #define S_DFL 1 /* default signal handling (SIG_DFL) */
90 #define S_CATCH 2 /* signal is caught */
91 #define S_IGN 3 /* signal is ignored (SIG_IGN) */
92 #define S_HARD_IGN 4 /* signal is ignored permenantly */
93 #define S_RESET 5 /* temporary - to reset a hard ignored sig */
97 struct alias *atab[ATABSIZE];
99 static void setalias __P((char *, char *));
100 static struct alias **hashalias __P((const char *));
101 static struct alias *freealias __P((struct alias *));
102 static struct alias **__lookupalias __P((const char *));
103 static char *trap[NSIG]; /* trap handler commands */
104 static char sigmode[NSIG - 1]; /* current value of signal */
105 static char gotsig[NSIG - 1]; /* indicates specified signal received */
106 static int pendingsigs; /* indicates some signal received */
113 struct alias *ap, **app;
115 app = __lookupalias(name);
119 if (!(ap->flag & ALIASINUSE)) {
122 ap->val = savestr(val);
123 ap->flag &= ~ALIASDEAD;
126 ap = ckmalloc(sizeof (struct alias));
127 ap->name = savestr(name);
128 ap->val = savestr(val);
142 app = __lookupalias(name);
146 *app = freealias(*app);
155 static void rmaliases __P((void));
164 struct alias *ap, **app;
168 for (i = 0; i < ATABSIZE; i++) {
170 for (ap = *app; ap; ap = *app) {
171 *app = freealias(*app);
181 lookupalias(name, check)
185 struct alias *ap = *__lookupalias(name);
187 if (check && ap && (ap->flag & ALIASINUSE))
208 for (i = 0; i < ATABSIZE; i++)
209 for (ap = atab[i]; ap; ap = ap->next) {
214 while ((n = *++argv) != NULL) {
215 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
216 if ((ap = *__lookupalias(n)) == NULL) {
217 outfmt(out2, "%s: %s not found\n", "alias", n);
232 unaliascmd(argc, argv)
238 while ((i = nextopt("a")) != '\0') {
244 for (i = 0; *argptr; argptr++) {
245 if (unalias(*argptr)) {
246 outfmt(out2, "%s: %s not found\n", "unalias", *argptr);
254 static struct alias **
258 unsigned int hashval;
263 return &atab[hashval % ATABSIZE];
266 static struct alias *
267 freealias(struct alias *ap) {
270 if (ap->flag & ALIASINUSE) {
271 ap->flag |= ALIASDEAD;
283 printalias(const struct alias *ap) {
286 p = single_quote(ap->val);
287 out1fmt("alias %s=%s\n", ap->name, p);
291 static struct alias **
292 __lookupalias(const char *name) {
293 struct alias **app = hashalias(name);
295 for (; *app; app = &(*app)->next) {
296 if (equal(name, (*app)->name)) {
304 #ifdef ASH_MATH_SUPPORT
305 /* The generated file arith.c has been snipped. If you want this
306 * stuff back in, feel free to add it to your own copy. */
310 * This file was generated by the mkbuiltins program.
313 static int bgcmd __P((int, char **));
314 static int breakcmd __P((int, char **));
315 static int cdcmd __P((int, char **));
316 static int commandcmd __P((int, char **));
317 static int dotcmd __P((int, char **));
318 static int evalcmd __P((int, char **));
319 static int execcmd __P((int, char **));
320 static int exitcmd __P((int, char **));
321 static int exportcmd __P((int, char **));
322 static int histcmd __P((int, char **));
323 static int fgcmd __P((int, char **));
324 static int hashcmd __P((int, char **));
325 static int jobscmd __P((int, char **));
326 static int killcmd __P((int, char **));
327 static int localcmd __P((int, char **));
328 static int pwdcmd __P((int, char **));
329 static int readcmd __P((int, char **));
330 static int returncmd __P((int, char **));
331 static int setcmd __P((int, char **));
332 static int setvarcmd __P((int, char **));
333 static int shiftcmd __P((int, char **));
334 static int trapcmd __P((int, char **));
335 static int umaskcmd __P((int, char **));
336 static int unaliascmd __P((int, char **));
337 static int unsetcmd __P((int, char **));
338 static int waitcmd __P((int, char **));
339 static int aliascmd __P((int, char **));
340 static int ulimitcmd __P((int, char **));
341 static int timescmd __P((int, char **));
342 #ifdef ASH_MATH_SUPPORT
343 static int expcmd __P((int, char **));
346 static int typecmd __P((int, char **));
349 static int getoptscmd __P((int, char **));
351 #ifndef BB_TRUE_FALSE
352 static int true_main __P((int, char **));
353 static int false_main __P((int, char **));
356 static struct builtincmd *DOTCMD;
357 static struct builtincmd *BLTINCMD;
358 static struct builtincmd *COMMANDCMD;
359 static struct builtincmd *EXECCMD;
360 static struct builtincmd *EVALCMD;
362 /* It is CRUCIAL that this listing be kept in ascii order, otherwise
363 * the binary search in find_builtin() will stop working. If you value
364 * your kneecaps, you'll be sure to *make sure* that any changes made
365 * to this array result in the listing remaining in ascii order. You
368 static const struct builtincmd builtincmds[] = {
370 { ":", true_main, 1 },
371 { "alias", aliascmd, 6 },
373 { "break", breakcmd, 1 },
374 { "builtin", bltincmd, 1 },
376 { "chdir", cdcmd, 0 },
377 { "command", commandcmd, 2 },
378 { "continue", breakcmd, 1 },
379 { "eval", evalcmd, 1 },
380 { "exec", execcmd, 1 },
381 { "exit", exitcmd, 1 },
382 #ifdef ASH_MATH_SUPPORT
383 { "exp", expcmd, 0 },
385 { "export", exportcmd, 5 },
386 { "false", false_main, 2 },
387 { "fc", histcmd, 2 },
390 { "getopts", getoptscmd, 2 },
392 { "hash", hashcmd, 0 },
393 { "jobs", jobscmd, 2 },
394 { "kill", killcmd, 2 },
395 #ifdef ASH_MATH_SUPPORT
396 { "let", expcmd, 0 },
398 { "local", localcmd, 4 },
399 { "pwd", pwdcmd, 0 },
400 { "read", readcmd, 2 },
401 { "readonly", exportcmd, 5 },
402 { "return", returncmd, 1 },
403 { "set", setcmd, 1 },
404 { "setvar", setvarcmd, 0 },
405 { "shift", shiftcmd, 1 },
406 { "times", timescmd, 1 },
407 { "trap", trapcmd, 1 },
408 { "true", true_main, 2 },
410 { "type", typecmd, 0 },
412 { "ulimit", ulimitcmd, 0 },
413 { "umask", umaskcmd, 2 },
414 { "unalias", unaliascmd, 2 },
415 { "unset", unsetcmd, 1 },
416 { "wait", waitcmd, 2 },
418 #define NUMBUILTINS (sizeof (builtincmds) / sizeof (struct builtincmd) )
421 /* $NetBSD: cd.c,v 1.27 1999/07/09 03:05:49 christos Exp $ */
423 static int docd __P((char *, int));
424 static char *getcomponent __P((void));
425 static void updatepwd __P((char *));
426 static void getpwd __P((void));
428 static char *curdir = nullstr; /* current working directory */
429 static char *cdcomppath;
450 if ((dest = *argptr) == NULL && (dest = bltinlookup("HOME")) == NULL)
451 error("HOME not set");
454 if (dest[0] == '-' && dest[1] == '\0') {
455 dest = bltinlookup("OLDPWD");
456 if (!dest || !*dest) {
465 if (*dest == '/' || (path = bltinlookup("CDPATH")) == NULL)
467 while ((p = padvance(&path, dest)) != NULL) {
468 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
473 if (p[0] == '.' && p[1] == '/' && p[2] != '\0')
475 print = strcmp(p, dest);
477 if (docd(p, print) >= 0)
482 error("can't cd to %s", dest);
488 * Actually do the chdir. In an interactive shell, print the
489 * directory name if "print" is nonzero.
504 TRACE(("docd(\"%s\", %d) called\n", dest, print));
507 * Check each component of the path. If we find a symlink or
508 * something we can't stat, clear curdir to force a getcwd()
509 * next time we get the value of the current directory.
512 cdcomppath = sstrdup(dest);
519 while ((q = getcomponent()) != NULL) {
520 if (q[0] == '\0' || (q[0] == '.' && q[1] == '\0'))
528 if (equal(component, ".."))
531 if ((lstat(stackblock(), &statb) < 0)
532 || (S_ISLNK(statb.st_mode))) {
540 if (chdir(dest) < 0) {
544 updatepwd(badstat ? NULL : dest);
547 out1fmt(snlfmt, curdir);
553 * Get the next component of the path name pointed to by cdcomppath.
554 * This routine overwrites the string pointed to by cdcomppath.
562 if ((p = cdcomppath) == NULL)
565 while (*p != '/' && *p != '\0')
579 * Update curdir (the name of the current directory) in response to a
580 * cd command. We also call hashcd to let the routines in exec.c know
581 * that the current directory has changed.
592 hashcd(); /* update command hash table */
595 * If our argument is NULL, we don't know the current directory
596 * any more because we traversed a symbolic link or something
597 * we couldn't stat().
599 if (dir == NULL || curdir == nullstr) {
604 cdcomppath = sstrdup(dir);
613 while ((p = getcomponent()) != NULL) {
614 if (equal(p, "..")) {
615 while (new > stackblock() && (STUNPUTC(new), *new) != '/');
616 } else if (*p != '\0' && ! equal(p, ".")) {
622 if (new == stackblock())
625 setpwd(stackblock(), 1);
635 out1fmt(snlfmt, curdir);
645 * Find out what the current directory is. If we already know the current
646 * directory, this routine returns immediately.
654 * Things are a bit complicated here; we could have just used
655 * getcwd, but traditionally getcwd is implemented using popen
656 * to /bin/pwd. This creates a problem for us, since we cannot
657 * keep track of the job if it is being ran behind our backs.
658 * So we re-implement getcwd(), and we suppress interrupts
659 * throughout the process. This is not completely safe, since
660 * the user can still break out of it by killing the pwd program.
661 * We still try to use getcwd for systems that we know have a
662 * c implementation of getcwd, that does not open a pipe to
665 #if defined(__NetBSD__) || defined(__SVR4) || defined(__GLIBC__)
667 if (getcwd(buf, sizeof(buf)) == NULL) {
668 char *pwd = getenv("PWD");
669 struct stat stdot, stpwd;
671 if (pwd && *pwd == '/' && stat(".", &stdot) != -1 &&
672 stat(pwd, &stpwd) != -1 &&
673 stdot.st_dev == stpwd.st_dev &&
674 stdot.st_ino == stpwd.st_ino) {
675 curdir = savestr(pwd);
678 error("getcwd() failed: %s", strerror(errno));
680 curdir = savestr(buf);
690 error("Pipe call failed");
691 jp = makejob((union node *)NULL, 1);
692 if (forkshell(jp, (union node *)NULL, FORK_NOJOB) == 0) {
693 (void) close(pip[0]);
696 dup_as_newfd(pip[1], 1);
699 (void) execl("/bin/pwd", "pwd", (char *)0);
700 error("Cannot exec /bin/pwd");
702 (void) close(pip[1]);
705 while ((i = read(pip[0], p, buf + MAXPWD - p)) > 0
706 || (i == -1 && errno == EINTR)) {
710 (void) close(pip[0]);
712 status = waitforjob(jp);
715 if (i < 0 || p == buf || p[-1] != '\n')
716 error("pwd command failed");
719 curdir = savestr(buf);
724 setpwd(const char *val, int setold)
727 setvar("OLDPWD", curdir, VEXPORT);
730 if (curdir != nullstr) {
737 curdir = savestr(val);
740 setvar("PWD", curdir, VEXPORT);
743 /* $NetBSD: error.c,v 1.23 2000/07/03 03:26:19 matt Exp $ */
746 * Errors and exceptions.
750 * Code to handle exceptions in C.
753 struct jmploc *handler;
754 static int exception;
755 volatile int suppressint;
756 volatile int intpending;
759 static void exverror __P((int, const char *, va_list))
760 __attribute__((__noreturn__));
763 * Called to raise an exception. Since C doesn't include exceptions, we
764 * just do a longjmp to the exception handler. The type of exception is
765 * stored in the global variable "exception".
777 longjmp(handler->loc, 1);
782 * Called from trap.c when a SIGINT is received. (If the user specifies
783 * that SIGINT is to be trapped or ignored using the trap builtin, then
784 * this routine is not called.) Suppressint is nonzero when interrupts
785 * are held using the INTOFF macro. The call to _exit is necessary because
786 * there is a short period after a fork before the signal handlers are
787 * set to the appropriate value for the child. (The test for iflag is
788 * just defensive programming.)
800 sigemptyset(&mysigset);
801 sigprocmask(SIG_SETMASK, &mysigset, NULL);
802 if (rootshell && iflag)
805 signal(SIGINT, SIG_DFL);
813 * Exverror is called to raise the error exception. If the first argument
814 * is not NULL then error prints an error message using printf style
815 * formatting. It then raises the error exception.
818 exverror(cond, msg, ap)
828 TRACE(("exverror(%d, \"%s\") pid=%d\n", cond, msg, getpid()));
830 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
834 outfmt(&errout, "%s: ", commandname);
835 doformat(&errout, msg, ap);
839 outcslow('\n', &errout);
850 error(const char *msg, ...)
865 msg = va_arg(ap, const char *);
867 exverror(EXERROR, msg, ap);
875 exerror(int cond, const char *msg, ...)
891 cond = va_arg(ap, int);
892 msg = va_arg(ap, const char *);
894 exverror(cond, msg, ap);
902 * Table of error messages.
906 short errcode; /* error number */
907 short action; /* operation which encountered the error */
908 const char *msg; /* text describing the error */
912 #define ALL (E_OPEN|E_CREAT|E_EXEC)
914 static const struct errname errormsg[] = {
915 { EINTR, ALL, "interrupted" },
916 { EACCES, ALL, "permission denied" },
917 { EIO, ALL, "I/O error" },
918 { ENOENT, E_OPEN, "no such file" },
919 { ENOENT, E_CREAT,"directory nonexistent" },
920 { ENOENT, E_EXEC, "not found" },
921 { ENOTDIR, E_OPEN, "no such file" },
922 { ENOTDIR, E_CREAT,"directory nonexistent" },
923 { ENOTDIR, E_EXEC, "not found" },
924 { EISDIR, ALL, "is a directory" },
925 { EEXIST, E_CREAT,"file exists" },
927 { EMFILE, ALL, "too many open files" },
929 { ENFILE, ALL, "file table overflow" },
930 { ENOSPC, ALL, "file system full" },
932 { EDQUOT, ALL, "disk quota exceeded" },
935 { ENOSR, ALL, "no streams resources" },
937 { ENXIO, ALL, "no such device or address" },
938 { EROFS, ALL, "read-only file system" },
939 { ETXTBSY, ALL, "text busy" },
941 { EAGAIN, E_EXEC, "not enough memory" },
943 { ENOMEM, ALL, "not enough memory" },
945 { ENOLINK, ALL, "remote access failed" },
948 { EMULTIHOP, ALL, "remote access failed" },
951 { ECOMM, ALL, "remote access failed" },
954 { ESTALE, ALL, "remote access failed" },
957 { ETIMEDOUT, ALL, "remote access failed" },
960 { ELOOP, ALL, "symbolic link loop" },
962 { E2BIG, E_EXEC, "argument list too long" },
964 { ELIBACC, E_EXEC, "shared library missing" },
971 * Return a string describing an error. The returned string may be a
972 * pointer to a static buffer that will be overwritten on the next call.
973 * Action describes the operation that got the error.
981 struct errname const *ep;
984 for (ep = errormsg ; ep->errcode ; ep++) {
985 if (ep->errcode == e && (ep->action & action) != 0)
988 fmtstr(buf, sizeof buf, "error %d", e);
996 if (--suppressint == 0 && intpending) {
1001 /* $NetBSD: eval.c,v 1.57 2001/02/04 19:52:06 christos Exp $ */
1004 /* flags in argument to evaltree */
1005 #define EV_EXIT 01 /* exit after evaluating tree */
1006 #define EV_TESTED 02 /* exit status is checked; ignore -e flag */
1007 #define EV_BACKCMD 04 /* command executing within back quotes */
1009 static int evalskip; /* set if we are skipping commands */
1010 static int skipcount; /* number of levels to skip */
1011 static int loopnest; /* current loop nesting level */
1012 static int funcnest; /* depth of function calls */
1015 static char *commandname;
1016 struct strlist *cmdenviron;
1017 static int exitstatus; /* exit status of last command */
1018 static int oexitstatus; /* saved exit status */
1021 static void evalloop __P((union node *, int));
1022 static void evalfor __P((union node *, int));
1023 static void evalcase __P((union node *, int));
1024 static void evalsubshell __P((union node *, int));
1025 static void expredir __P((union node *));
1026 static void evalpipe __P((union node *));
1028 static void evalcommand __P((union node *, int, struct backcmd *));
1030 static void evalcommand __P((union node *, int));
1032 static void prehash __P((union node *));
1033 static void eprintlist __P((struct strlist *));
1037 * Called to reset things after an exception.
1057 * The eval commmand.
1072 STARTSTACKSTR(concat);
1076 STPUTC(*p++, concat);
1077 if ((p = *ap++) == NULL)
1079 STPUTC(' ', concat);
1081 STPUTC('\0', concat);
1082 p = grabstackstr(concat);
1084 evalstring(p, EV_TESTED);
1091 * Execute a command or commands contained in a string.
1100 struct stackmark smark;
1102 setstackmark(&smark);
1104 while ((n = parsecmd(0)) != NEOF) {
1106 popstackmark(&smark);
1109 popstackmark(&smark);
1115 * Evaluate a parse tree. The value is left in the global variable
1126 TRACE(("evaltree(NULL) called\n"));
1129 TRACE(("evaltree(0x%lx: %d) called\n", (long)n, n->type));
1132 evaltree(n->nbinary.ch1, flags & EV_TESTED);
1135 evaltree(n->nbinary.ch2, flags);
1138 evaltree(n->nbinary.ch1, EV_TESTED);
1139 if (evalskip || exitstatus != 0)
1141 evaltree(n->nbinary.ch2, flags);
1144 evaltree(n->nbinary.ch1, EV_TESTED);
1145 if (evalskip || exitstatus == 0)
1147 evaltree(n->nbinary.ch2, flags);
1150 expredir(n->nredir.redirect);
1151 redirect(n->nredir.redirect, REDIR_PUSH);
1152 evaltree(n->nredir.n, flags);
1156 evalsubshell(n, flags);
1159 evalsubshell(n, flags);
1162 evaltree(n->nif.test, EV_TESTED);
1165 if (exitstatus == 0)
1166 evaltree(n->nif.ifpart, flags);
1167 else if (n->nif.elsepart)
1168 evaltree(n->nif.elsepart, flags);
1184 struct builtincmd *bcmd;
1186 (bcmd = find_builtin(n->narg.text)) &&
1187 bcmd->flags & BUILTIN_SPECIAL
1189 outfmt(out2, "%s is a special built-in\n", n->narg.text);
1193 defun(n->narg.text, n->narg.next);
1198 evaltree(n->nnot.com, EV_TESTED);
1199 exitstatus = !exitstatus;
1208 evalcommand(n, flags, (struct backcmd *)NULL);
1210 evalcommand(n, flags);
1216 out1fmt("Node type = %d\n", n->type);
1217 #ifndef USE_GLIBC_STDIO
1228 (checkexit && eflag && exitstatus && !(flags & EV_TESTED))
1230 exitshell(exitstatus);
1244 evaltree(n->nbinary.ch1, EV_TESTED);
1246 skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
1250 if (evalskip == SKIPBREAK && --skipcount <= 0)
1254 if (n->type == NWHILE) {
1255 if (exitstatus != 0)
1258 if (exitstatus == 0)
1261 evaltree(n->nbinary.ch2, flags & EV_TESTED);
1262 status = exitstatus;
1267 exitstatus = status;
1277 struct arglist arglist;
1280 struct stackmark smark;
1282 setstackmark(&smark);
1283 arglist.lastp = &arglist.list;
1284 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
1285 oexitstatus = exitstatus;
1286 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
1290 *arglist.lastp = NULL;
1294 for (sp = arglist.list ; sp ; sp = sp->next) {
1295 setvar(n->nfor.var, sp->text, 0);
1296 evaltree(n->nfor.body, flags & EV_TESTED);
1298 if (evalskip == SKIPCONT && --skipcount <= 0) {
1302 if (evalskip == SKIPBREAK && --skipcount <= 0)
1309 popstackmark(&smark);
1321 struct arglist arglist;
1322 struct stackmark smark;
1324 setstackmark(&smark);
1325 arglist.lastp = &arglist.list;
1326 oexitstatus = exitstatus;
1327 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
1328 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
1329 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
1330 if (casematch(patp, arglist.list->text)) {
1331 if (evalskip == 0) {
1332 evaltree(cp->nclist.body, flags);
1339 popstackmark(&smark);
1345 * Kick off a subshell to evaluate a tree.
1349 evalsubshell(n, flags)
1354 int backgnd = (n->type == NBACKGND);
1356 expredir(n->nredir.redirect);
1358 if (forkshell(jp, n, backgnd) == 0) {
1360 flags &=~ EV_TESTED;
1361 redirect(n->nredir.redirect, 0);
1362 evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */
1366 exitstatus = waitforjob(jp);
1374 * Compute the names of the files in a redirection list.
1383 for (redir = n ; redir ; redir = redir->nfile.next) {
1385 fn.lastp = &fn.list;
1386 oexitstatus = exitstatus;
1387 switch (redir->type) {
1393 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
1394 redir->nfile.expfname = fn.list->text;
1398 if (redir->ndup.vname) {
1399 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
1400 fixredir(redir, fn.list->text, 1);
1410 * Evaluate a pipeline. All the processes in the pipeline are children
1411 * of the process creating the pipeline. (This differs from some versions
1412 * of the shell, which make the last process in a pipeline the parent
1421 struct nodelist *lp;
1426 TRACE(("evalpipe(0x%lx) called\n", (long)n));
1428 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
1431 jp = makejob(n, pipelen);
1433 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
1437 if (pipe(pip) < 0) {
1439 error("Pipe call failed");
1442 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
1446 dup_as_newfd(prevfd, 0);
1458 dup_as_newfd(pip[1], 1);
1462 evaltree(lp->n, EV_EXIT);
1470 if (n->npipe.backgnd == 0) {
1472 exitstatus = waitforjob(jp);
1473 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
1481 * Execute a command inside back quotes. If it's a builtin command, we
1482 * want to save its output in a block obtained from malloc. Otherwise
1483 * we fork off a subprocess and get the output of the command via a pipe.
1484 * Should be called with interrupts off.
1488 evalbackcmd(n, result)
1490 struct backcmd *result;
1494 struct stackmark smark; /* unnecessary */
1496 setstackmark(&smark);
1507 * For now we disable executing builtins in the same
1508 * context as the shell, because we are not keeping
1509 * enough state to recover from changes that are
1510 * supposed only to affect subshells. eg. echo "`cd /`"
1512 if (n->type == NCMD) {
1513 exitstatus = oexitstatus;
1514 evalcommand(n, EV_BACKCMD, result);
1520 error("Pipe call failed");
1522 if (forkshell(jp, n, FORK_NOJOB) == 0) {
1527 dup_as_newfd(pip[1], 1);
1531 evaltree(n, EV_EXIT);
1534 result->fd = pip[0];
1538 popstackmark(&smark);
1539 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
1540 result->fd, result->buf, result->nleft, result->jp));
1546 * Execute a simple command.
1551 evalcommand(cmd, flags, backcmd)
1554 struct backcmd *backcmd;
1556 evalcommand(cmd, flags)
1561 struct stackmark smark;
1563 struct arglist arglist;
1564 struct arglist varlist;
1573 struct cmdentry cmdentry;
1575 char *volatile savecmdname;
1576 volatile struct shparam saveparam;
1577 struct localvar *volatile savelocalvars;
1581 const struct builtincmd *firstbltin;
1582 struct jmploc *volatile savehandler;
1583 struct jmploc jmploc;
1585 /* Avoid longjmp clobbering */
1592 /* First expand the arguments. */
1593 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
1594 setstackmark(&smark);
1595 arglist.lastp = &arglist.list;
1596 varlist.lastp = &varlist.list;
1598 oexitstatus = exitstatus;
1601 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
1602 expandarg(argp, &varlist, EXP_VARTILDE);
1605 argp = cmd->ncmd.args; argp && !arglist.list;
1606 argp = argp->narg.next
1608 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
1611 struct builtincmd *bcmd;
1613 bcmd = find_builtin(arglist.list->text);
1614 pseudovarflag = bcmd && bcmd->flags & BUILTIN_ASSIGN;
1615 for (; argp; argp = argp->narg.next) {
1616 if (pseudovarflag && isassignment(argp->narg.text)) {
1617 expandarg(argp, &arglist, EXP_VARTILDE);
1620 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
1623 *arglist.lastp = NULL;
1624 *varlist.lastp = NULL;
1625 expredir(cmd->ncmd.redirect);
1627 for (sp = arglist.list ; sp ; sp = sp->next)
1629 argv = stalloc(sizeof (char *) * (argc + 1));
1631 for (sp = arglist.list ; sp ; sp = sp->next) {
1632 TRACE(("evalcommand arg: %s\n", sp->text));
1637 if (iflag && funcnest == 0 && argc > 0)
1641 /* Print the command if xflag is set. */
1646 outcslow('+', &errout);
1648 eprintlist(varlist.list);
1649 eprintlist(arglist.list);
1651 outc('\n', &errout);
1654 outcslow('\n', &errout);
1658 /* Now locate the command. */
1660 cmdentry.cmdtype = CMDBUILTIN;
1661 firstbltin = cmdentry.u.cmd = BLTINCMD;
1663 const char *oldpath;
1664 int findflag = DO_ERR;
1668 * Modify the command lookup path, if a PATH= assignment
1671 for (sp = varlist.list ; sp ; sp = sp->next)
1672 if (varequal(sp->text, defpathvar)) {
1673 path = sp->text + 5;
1674 findflag |= DO_BRUTE;
1677 oldfindflag = findflag;
1680 find_command(argv[0], &cmdentry, findflag, path);
1681 if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */
1688 /* implement bltin and command here */
1689 if (cmdentry.cmdtype != CMDBUILTIN) {
1693 firstbltin = cmdentry.u.cmd;
1695 if (cmdentry.u.cmd == BLTINCMD) {
1697 struct builtincmd *bcmd;
1702 if (!(bcmd = find_builtin(*argv))) {
1703 outfmt(&errout, "%s: not found\n", *argv);
1710 cmdentry.u.cmd = bcmd;
1711 if (bcmd != BLTINCMD)
1715 if (cmdentry.u.cmd == COMMANDCMD) {
1720 if (*argv[0] == '-') {
1721 if (!equal(argv[0], "-p")) {
1731 findflag |= DO_BRUTE;
1734 findflag = oldfindflag;
1736 findflag |= DO_NOFUN;
1744 /* Fork off a child process if necessary. */
1745 if (cmd->ncmd.backgnd
1746 || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0)
1748 || ((flags & EV_BACKCMD) != 0
1749 && (cmdentry.cmdtype != CMDBUILTIN
1750 || cmdentry.u.bcmd == DOTCMD
1751 || cmdentry.u.bcmd == EVALCMD))
1754 jp = makejob(cmd, 1);
1755 mode = cmd->ncmd.backgnd;
1757 if (flags & EV_BACKCMD) {
1760 error("Pipe call failed");
1763 if (forkshell(jp, cmd, mode) != 0)
1764 goto parent; /* at end of routine */
1766 if (flags & EV_BACKCMD) {
1771 dup_as_newfd(pip[1], 1);
1779 /* This is the child process if a fork occurred. */
1780 /* Execute the command. */
1781 if (cmdentry.cmdtype == CMDFUNCTION) {
1783 trputs("Shell function: "); trargs(argv);
1785 exitstatus = oexitstatus;
1786 redirect(cmd->ncmd.redirect, REDIR_PUSH);
1787 saveparam = shellparam;
1788 shellparam.malloc = 0;
1789 shellparam.nparam = argc - 1;
1790 shellparam.p = argv + 1;
1792 savelocalvars = localvars;
1795 if (setjmp(jmploc.loc)) {
1796 if (exception == EXSHELLPROC) {
1797 freeparam((volatile struct shparam *)
1800 saveparam.optind = shellparam.optind;
1801 saveparam.optoff = shellparam.optoff;
1802 freeparam(&shellparam);
1803 shellparam = saveparam;
1806 localvars = savelocalvars;
1807 handler = savehandler;
1808 longjmp(handler->loc, 1);
1810 savehandler = handler;
1812 for (sp = varlist.list ; sp ; sp = sp->next)
1815 evaltree(cmdentry.u.func, flags & EV_TESTED);
1819 localvars = savelocalvars;
1820 saveparam.optind = shellparam.optind;
1821 saveparam.optoff = shellparam.optoff;
1822 freeparam(&shellparam);
1823 shellparam = saveparam;
1824 handler = savehandler;
1827 if (evalskip == SKIPFUNC) {
1831 if (flags & EV_EXIT)
1832 exitshell(exitstatus);
1833 } else if (cmdentry.cmdtype == CMDBUILTIN) {
1835 trputs("builtin command: "); trargs(argv);
1837 mode = (cmdentry.u.cmd == EXECCMD)? 0 : REDIR_PUSH;
1839 if (flags == EV_BACKCMD) {
1840 #ifdef USE_GLIBC_STDIO
1844 memout.nextc = memout.buf;
1845 memout.bufsize = 64;
1847 mode |= REDIR_BACKQ;
1850 redirect(cmd->ncmd.redirect, mode);
1851 savecmdname = commandname;
1852 if (firstbltin->flags & BUILTIN_SPECIAL) {
1853 listsetvar(varlist.list);
1855 cmdenviron = varlist.list;
1858 if (setjmp(jmploc.loc)) {
1860 exitstatus = (e == EXINT)? SIGINT+128 : 2;
1863 savehandler = handler;
1865 commandname = argv[0];
1867 optptr = NULL; /* initialize nextopt */
1868 exitstatus = (*cmdentry.u.cmd->builtinfunc)(argc, argv);
1871 exitstatus |= outerr(out1);
1876 if (e != EXSHELLPROC) {
1877 commandname = savecmdname;
1878 if (flags & EV_EXIT)
1879 exitshell(exitstatus);
1881 handler = savehandler;
1883 if ((e != EXERROR && e != EXEXEC)
1884 || cmdentry.u.cmd == BLTINCMD
1885 || cmdentry.u.cmd == DOTCMD
1886 || cmdentry.u.cmd == EVALCMD
1887 || cmdentry.u.cmd == EXECCMD)
1891 if (cmdentry.u.cmd != EXECCMD)
1894 if (flags == EV_BACKCMD) {
1896 #ifdef USE_GLIBC_STDIO
1897 if (__closememout()) {
1899 "__closememout() failed: %s",
1904 backcmd->buf = memout.buf;
1905 #ifdef USE_GLIBC_STDIO
1906 backcmd->nleft = memout.bufsize;
1908 backcmd->nleft = memout.nextc - memout.buf;
1916 trputs("normal command: "); trargs(argv);
1918 redirect(cmd->ncmd.redirect, 0);
1920 for (sp = varlist.list ; sp ; sp = sp->next)
1921 setvareq(sp->text, VEXPORT|VSTACK);
1922 envp = environment();
1923 shellexec(argv, envp, path, cmdentry.u.index);
1927 parent: /* parent process gets here (if we forked) */
1928 if (mode == 0) { /* argument to fork */
1930 exitstatus = waitforjob(jp);
1933 } else if (mode == 2) {
1934 backcmd->fd = pip[0];
1942 setvar("_", lastarg, 0);
1943 popstackmark(&smark);
1949 * Search for a command. This is called before we fork so that the
1950 * location of the command will be available in the parent as well as
1951 * the child. The check for "goodname" is an overly conservative
1952 * check that the name will not be subject to expansion.
1959 struct cmdentry entry;
1961 if (n->type == NCMD && n->ncmd.args)
1962 if (goodname(n->ncmd.args->narg.text))
1963 find_command(n->ncmd.args->narg.text, &entry, 0,
1970 * Builtin commands. Builtin commands whose functions are closely
1971 * tied to evaluation are implemented here.
1975 * No command given, or a bltin command with no arguments. Set the
1976 * specified variables.
1980 bltincmd(argc, argv)
1985 * Preserve exitstatus of a previous possible redirection
1993 * Handle break and continue commands. Break, continue, and return are
1994 * all handled by setting the evalskip flag. The evaluation routines
1995 * above all check this flag, and if it is set they start skipping
1996 * commands rather than executing them. The variable skipcount is
1997 * the number of loops to break/continue, or the number of function
1998 * levels to return. (The latter is always 1.) It should probably
1999 * be an error to break out of more loops than exist, but it isn't
2000 * in the standard shell so we don't make it one here.
2004 breakcmd(argc, argv)
2008 int n = argc > 1 ? number(argv[1]) : 1;
2013 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
2021 * The return command.
2025 returncmd(argc, argv)
2029 int ret = argc > 1 ? number(argv[1]) : oexitstatus;
2032 evalskip = SKIPFUNC;
2037 /* Do what ksh does; skip the rest of the file */
2038 evalskip = SKIPFILE;
2045 #ifndef BB_TRUE_FALSE
2047 false_main(argc, argv)
2056 true_main(argc, argv)
2072 iflag = 0; /* exit on error */
2075 for (sp = cmdenviron; sp ; sp = sp->next)
2076 setvareq(sp->text, VEXPORT|VSTACK);
2077 shellexec(argv + 1, environment(), pathval(), 0);
2083 eprintlist(struct strlist *sp)
2085 for (; sp; sp = sp->next) {
2086 outfmt(&errout, " %s",sp->text);
2089 /* $NetBSD: exec.c,v 1.32 2001/02/04 19:52:06 christos Exp $ */
2092 * When commands are first encountered, they are entered in a hash table.
2093 * This ensures that a full path search will not have to be done for them
2094 * on each invocation.
2096 * We should investigate converting to a linear search, even though that
2097 * would make the command name "hash" a misnomer.
2099 #define CMDTABLESIZE 31 /* should be prime */
2100 #define ARB 1 /* actual size determined at run time */
2105 struct tblentry *next; /* next entry in hash chain */
2106 union param param; /* definition of builtin function */
2107 short cmdtype; /* index identifying command */
2108 char rehash; /* if set, cd done since entry created */
2109 char cmdname[ARB]; /* name of command */
2113 static struct tblentry *cmdtable[CMDTABLESIZE];
2114 static int builtinloc = -1; /* index in path of %builtin, or -1 */
2115 static int exerrno = 0; /* Last exec error */
2118 static void tryexec __P((char *, char **, char **));
2119 #if !defined(BSD) && !defined(linux)
2120 static void execinterp __P((char **, char **));
2122 static void printentry __P((struct tblentry *, int));
2123 static void clearcmdentry __P((int));
2124 static struct tblentry *cmdlookup __P((char *, int));
2125 static void delete_cmd_entry __P((void));
2127 static int describe_command __P((char *, int));
2129 static int path_change __P((const char *, int *));
2133 * Exec a program. Never returns. If you change this routine, you may
2134 * have to change the find_command routine as well.
2138 shellexec(argv, envp, path, idx)
2139 char **argv, **envp;
2146 if (strchr(argv[0], '/') != NULL) {
2147 tryexec(argv[0], argv, envp);
2151 while ((cmdname = padvance(&path, argv[0])) != NULL) {
2152 if (--idx < 0 && pathopt == NULL) {
2153 tryexec(cmdname, argv, envp);
2154 if (errno != ENOENT && errno != ENOTDIR)
2161 /* Map to POSIX errors */
2173 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
2179 tryexec(cmd, argv, envp)
2185 #if !defined(BSD) && !defined(linux)
2191 execve(cmd, argv, envp);
2192 } while (errno == EINTR);
2194 execve(cmd, argv, envp);
2200 setinputfile(cmd, 0);
2201 commandname = arg0 = savestr(argv[0]);
2202 #if !defined(BSD) && !defined(linux)
2204 pgetc(); pungetc(); /* fill up input buffer */
2206 if (parsenleft > 2 && p[0] == '#' && p[1] == '!') {
2208 execinterp(argv, envp);
2213 exraise(EXSHELLPROC);
2219 #if !defined(BSD) && !defined(linux)
2221 * Execute an interpreter introduced by "#!", for systems where this
2222 * feature has not been built into the kernel. If the interpreter is
2223 * the shell, return (effectively ignoring the "#!"). If the execution
2224 * of the interpreter fails, exit.
2226 * This code peeks inside the input buffer in order to avoid actually
2227 * reading any input. It would benefit from a rewrite.
2233 execinterp(argv, envp)
2234 char **argv, **envp;
2242 char *newargs[NEWARGS];
2248 inp = parsenextc + 2;
2251 while (--n >= 0 && (*inp == ' ' || *inp == '\t'))
2255 if ((c = *inp++) == '\n')
2257 if (ap == &newargs[NEWARGS])
2258 bad: error("Bad #! line");
2259 STARTSTACKSTR(outp);
2262 } while (--n >= 0 && (c = *inp++) != ' ' && c != '\t' && c != '\n');
2265 *ap++ = grabstackstr(outp);
2267 if (ap == newargs + 1) { /* if no args, maybe no exec is needed */
2270 if (equal(p, "sh") || equal(p, "ash")) {
2282 i = (char *)ap - (char *)newargs; /* size in bytes */
2284 error("Bad #! line");
2285 for (ap2 = argv ; *ap2++ != NULL ; );
2286 new = ckmalloc(i + ((char *)ap2 - (char *)argv));
2287 ap = newargs, ap2 = new;
2288 while ((i -= sizeof (char **)) >= 0)
2291 while (*ap2++ = *ap++);
2292 shellexec(new, envp, pathval(), 0);
2300 * Do a path search. The variable path (passed by reference) should be
2301 * set to the start of the path before the first call; padvance will update
2302 * this value as it proceeds. Successive calls to padvance will return
2303 * the possible path expansions in sequence. If an option (indicated by
2304 * a percent sign) appears in the path entry then the global variable
2305 * pathopt will be set to point to it; otherwise pathopt will be set to
2309 static const char *pathopt;
2312 padvance(path, name)
2324 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
2325 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2326 while (stackblocksize() < len)
2330 memcpy(q, start, p - start);
2338 while (*p && *p != ':') p++;
2344 return stalloc(len);
2349 /*** Command hashing code ***/
2357 struct tblentry **pp;
2358 struct tblentry *cmdp;
2361 struct cmdentry entry;
2365 while ((c = nextopt("rv")) != '\0') {
2369 } else if (c == 'v') {
2373 if (*argptr == NULL) {
2374 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
2375 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
2376 if (cmdp->cmdtype != CMDBUILTIN) {
2377 printentry(cmdp, verbose);
2384 while ((name = *argptr) != NULL) {
2385 if ((cmdp = cmdlookup(name, 0)) != NULL
2386 && (cmdp->cmdtype == CMDNORMAL
2387 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
2389 find_command(name, &entry, DO_ERR, pathval());
2390 if (entry.cmdtype == CMDUNKNOWN) c = 1;
2392 cmdp = cmdlookup(name, 0);
2393 if (cmdp) printentry(cmdp, verbose);
2403 printentry(cmdp, verbose)
2404 struct tblentry *cmdp;
2411 if (cmdp->cmdtype == CMDNORMAL) {
2412 idx = cmdp->param.index;
2415 name = padvance(&path, cmdp->cmdname);
2417 } while (--idx >= 0);
2419 } else if (cmdp->cmdtype == CMDBUILTIN) {
2420 out1fmt("builtin %s", cmdp->cmdname);
2421 } else if (cmdp->cmdtype == CMDFUNCTION) {
2422 out1fmt("function %s", cmdp->cmdname);
2425 name = commandtext(cmdp->param.func);
2426 out1fmt(" %s", name);
2432 error("internal error: cmdtype %d", cmdp->cmdtype);
2435 out1fmt(snlfmt, cmdp->rehash ? "*" : nullstr);
2441 * Resolve a command name. If you change this routine, you may have to
2442 * change the shellexec routine as well.
2446 find_command(name, entry, act, path)
2448 struct cmdentry *entry;
2452 struct tblentry *cmdp;
2462 struct builtincmd *bcmd;
2464 /* If name contains a slash, don't use the hash table */
2465 if (strchr(name, '/') != NULL) {
2467 while (stat(name, &statb) < 0) {
2472 if (errno != ENOENT && errno != ENOTDIR)
2474 entry->cmdtype = CMDUNKNOWN;
2475 entry->u.index = -1;
2478 entry->cmdtype = CMDNORMAL;
2479 entry->u.index = -1;
2482 entry->cmdtype = CMDNORMAL;
2488 if (act & DO_BRUTE) {
2489 firstchange = path_change(path, &bltin);
2495 /* If name is in the table, and not invalidated by cd, we're done */
2496 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0) {
2497 if (cmdp->cmdtype == CMDFUNCTION) {
2498 if (act & DO_NOFUN) {
2503 } else if (act & DO_BRUTE) {
2504 if ((cmdp->cmdtype == CMDNORMAL &&
2505 cmdp->param.index >= firstchange) ||
2506 (cmdp->cmdtype == CMDBUILTIN &&
2507 ((builtinloc < 0 && bltin >= 0) ?
2508 bltin : builtinloc) >= firstchange)) {
2509 /* need to recompute the entry */
2518 bcmd = find_builtin(name);
2519 regular = bcmd && bcmd->flags & BUILTIN_REGULAR;
2522 if (cmdp && (cmdp->cmdtype == CMDBUILTIN)) {
2525 } else if (act & DO_BRUTE) {
2526 if (firstchange == 0) {
2531 /* If %builtin not in path, check for builtin next */
2532 if (regular || (bltin < 0 && bcmd)) {
2535 entry->cmdtype = CMDBUILTIN;
2536 entry->u.cmd = bcmd;
2540 cmdp = cmdlookup(name, 1);
2541 cmdp->cmdtype = CMDBUILTIN;
2542 cmdp->param.cmd = bcmd;
2547 /* We have to search path. */
2548 prev = -1; /* where to start */
2549 if (cmdp && cmdp->rehash) { /* doing a rehash */
2550 if (cmdp->cmdtype == CMDBUILTIN)
2553 prev = cmdp->param.index;
2559 while ((fullname = padvance(&path, name)) != NULL) {
2560 stunalloc(fullname);
2562 if (idx >= firstchange) {
2566 if (prefix("builtin", pathopt)) {
2567 if ((bcmd = find_builtin(name))) {
2571 } else if (!(act & DO_NOFUN) &&
2572 prefix("func", pathopt)) {
2575 continue; /* ignore unimplemented options */
2578 /* if rehash, don't redo absolute path names */
2579 if (fullname[0] == '/' && idx <= prev &&
2580 idx < firstchange) {
2583 TRACE(("searchexec \"%s\": no change\n", name));
2586 while (stat(fullname, &statb) < 0) {
2591 if (errno != ENOENT && errno != ENOTDIR)
2595 e = EACCES; /* if we fail, this will be the error */
2596 if (!S_ISREG(statb.st_mode))
2598 if (pathopt) { /* this is a %func directory */
2599 stalloc(strlen(fullname) + 1);
2600 readcmdfile(fullname);
2601 if ((cmdp = cmdlookup(name, 0)) == NULL || cmdp->cmdtype != CMDFUNCTION)
2602 error("%s not defined in %s", name, fullname);
2603 stunalloc(fullname);
2607 if (statb.st_uid == geteuid()) {
2608 if ((statb.st_mode & 0100) == 0)
2610 } else if (statb.st_gid == getegid()) {
2611 if ((statb.st_mode & 010) == 0)
2614 if ((statb.st_mode & 01) == 0)
2618 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
2619 /* If we aren't called with DO_BRUTE and cmdp is set, it must
2620 be a function and we're being called with DO_NOFUN */
2622 entry->cmdtype = CMDNORMAL;
2623 entry->u.index = idx;
2627 cmdp = cmdlookup(name, 1);
2628 cmdp->cmdtype = CMDNORMAL;
2629 cmdp->param.index = idx;
2634 /* We failed. If there was an entry for this command, delete it */
2635 if (cmdp && updatetbl)
2638 outfmt(out2, "%s: %s\n", name, errmsg(e, E_EXEC));
2639 entry->cmdtype = CMDUNKNOWN;
2644 entry->cmdtype = cmdp->cmdtype;
2645 entry->u = cmdp->param;
2651 * Search the table of builtin commands.
2658 struct builtincmd *bp;
2660 bp = bsearch( &name, builtincmds, NUMBUILTINS, sizeof(struct builtincmd),
2668 * Called when a cd is done. Marks all commands so the next time they
2669 * are executed they will be rehashed.
2674 struct tblentry **pp;
2675 struct tblentry *cmdp;
2677 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
2678 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
2679 if (cmdp->cmdtype == CMDNORMAL
2680 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
2689 * Called before PATH is changed. The argument is the new value of PATH;
2690 * pathval() still returns the old value at this point. Called with
2701 firstchange = path_change(newval, &bltin);
2702 if (builtinloc < 0 && bltin >= 0)
2703 builtinloc = bltin; /* zap builtins */
2704 clearcmdentry(firstchange);
2710 * Clear out command entries. The argument specifies the first entry in
2711 * PATH which has changed.
2715 clearcmdentry(firstchange)
2718 struct tblentry **tblp;
2719 struct tblentry **pp;
2720 struct tblentry *cmdp;
2723 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
2725 while ((cmdp = *pp) != NULL) {
2726 if ((cmdp->cmdtype == CMDNORMAL &&
2727 cmdp->param.index >= firstchange)
2728 || (cmdp->cmdtype == CMDBUILTIN &&
2729 builtinloc >= firstchange)) {
2742 * Delete all functions.
2746 static void deletefuncs __P((void));
2755 struct tblentry **tblp;
2756 struct tblentry **pp;
2757 struct tblentry *cmdp;
2760 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
2762 while ((cmdp = *pp) != NULL) {
2763 if (cmdp->cmdtype == CMDFUNCTION) {
2765 freefunc(cmdp->param.func);
2778 * Locate a command in the command hash table. If "add" is nonzero,
2779 * add the command to the table if it is not already present. The
2780 * variable "lastcmdentry" is set to point to the address of the link
2781 * pointing to the entry, so that delete_cmd_entry can delete the
2785 struct tblentry **lastcmdentry;
2788 static struct tblentry *
2789 cmdlookup(name, add)
2795 struct tblentry *cmdp;
2796 struct tblentry **pp;
2803 pp = &cmdtable[hashval % CMDTABLESIZE];
2804 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
2805 if (equal(cmdp->cmdname, name))
2809 if (add && cmdp == NULL) {
2811 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
2812 + strlen(name) + 1);
2814 cmdp->cmdtype = CMDUNKNOWN;
2816 strcpy(cmdp->cmdname, name);
2824 * Delete the command entry returned on the last lookup.
2828 delete_cmd_entry() {
2829 struct tblentry *cmdp;
2832 cmdp = *lastcmdentry;
2833 *lastcmdentry = cmdp->next;
2842 getcmdentry(name, entry)
2844 struct cmdentry *entry;
2846 struct tblentry *cmdp = cmdlookup(name, 0);
2849 entry->u = cmdp->param;
2850 entry->cmdtype = cmdp->cmdtype;
2852 entry->cmdtype = CMDUNKNOWN;
2860 * Add a new command entry, replacing any existing command entry for
2865 addcmdentry(name, entry)
2867 struct cmdentry *entry;
2869 struct tblentry *cmdp;
2872 cmdp = cmdlookup(name, 1);
2873 if (cmdp->cmdtype == CMDFUNCTION) {
2874 freefunc(cmdp->param.func);
2876 cmdp->cmdtype = entry->cmdtype;
2877 cmdp->param = entry->u;
2883 * Define a shell function.
2891 struct cmdentry entry;
2893 entry.cmdtype = CMDFUNCTION;
2894 entry.u.func = copyfunc(func);
2895 addcmdentry(name, &entry);
2900 * Delete a function if it exists.
2907 struct tblentry *cmdp;
2909 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) {
2910 freefunc(cmdp->param.func);
2917 * Locate and print what a word is...
2928 for (i = 1; i < argc; i++) {
2929 err |= describe_command(argv[i], 1);
2935 describe_command(command, verbose)
2939 struct cmdentry entry;
2940 struct tblentry *cmdp;
2941 const struct alias *ap;
2942 const char *path = pathval();
2948 /* First look at the keywords */
2949 if (findkwd(command)) {
2950 out1str(verbose ? " is a shell keyword" : command);
2954 /* Then look at the aliases */
2955 if ((ap = lookupalias(command, 0)) != NULL) {
2957 out1fmt(" is an alias for %s", ap->val);
2964 /* Then check if it is a tracked alias */
2965 if ((cmdp = cmdlookup(command, 0)) != NULL) {
2966 entry.cmdtype = cmdp->cmdtype;
2967 entry.u = cmdp->param;
2969 /* Finally use brute force */
2970 find_command(command, &entry, DO_ABS, path);
2973 switch (entry.cmdtype) {
2975 int j = entry.u.index;
2981 p = padvance(&path, command);
2988 cmdp ? " a tracked alias for" : nullstr, p
2998 out1str(" is a shell function");
3007 " is a %sshell builtin",
3008 entry.u.cmd->flags & BUILTIN_SPECIAL ?
3009 "special " : nullstr
3018 out1str(": not found\n");
3030 commandcmd(argc, argv)
3035 int default_path = 0;
3036 int verify_only = 0;
3037 int verbose_verify_only = 0;
3039 while ((c = nextopt("pvV")) != '\0')
3048 verbose_verify_only = 1;
3052 "command: nextopt returned character code 0%o\n", c);
3056 if (default_path + verify_only + verbose_verify_only > 1 ||
3059 "command [-p] command [arg ...]\n");
3061 "command {-v|-V} command\n");
3066 if (verify_only || verbose_verify_only) {
3067 return describe_command(*argptr, verbose_verify_only);
3075 path_change(newval, bltin)
3079 const char *old, *new;
3085 firstchange = 9999; /* assume no change */
3091 if ((*old == '\0' && *new == ':')
3092 || (*old == ':' && *new == '\0'))
3094 old = new; /* ignore subsequent differences */
3098 if (*new == '%' && *bltin < 0 && prefix("builtin", new + 1))
3105 if (builtinloc >= 0 && *bltin < 0)
3109 /* $NetBSD: expand.c,v 1.50 2001/02/04 19:52:06 christos Exp $ */
3112 * Routines to expand arguments to commands. We have to deal with
3113 * backquotes, shell variables, and file metacharacters.
3118 #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
3119 #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
3122 * Structure specifying which parts of the string should be searched
3123 * for IFS characters.
3127 struct ifsregion *next; /* next region in list */
3128 int begoff; /* offset of start of region */
3129 int endoff; /* offset of end of region */
3130 int nulonly; /* search for nul bytes only */
3134 static char *expdest; /* output of current string */
3135 struct nodelist *argbackq; /* list of back quote expressions */
3136 struct ifsregion ifsfirst; /* first struct in list of ifs regions */
3137 struct ifsregion *ifslastp; /* last struct in list */
3138 struct arglist exparg; /* holds expanded arg list */
3140 static void argstr __P((char *, int));
3141 static char *exptilde __P((char *, int));
3142 static void expbackq __P((union node *, int, int));
3143 static int subevalvar __P((char *, char *, int, int, int, int, int));
3144 static char *evalvar __P((char *, int));
3145 static int varisset __P((char *, int));
3146 static void strtodest __P((const char *, const char *, int));
3147 static void varvalue __P((char *, int, int));
3148 static void recordregion __P((int, int, int));
3149 static void removerecordregions __P((int));
3150 static void ifsbreakup __P((char *, struct arglist *));
3151 static void ifsfree __P((void));
3152 static void expandmeta __P((struct strlist *, int));
3153 #if defined(__GLIBC__) && !defined(FNMATCH_BROKEN)
3154 #define preglob(p) _rmescapes((p), RMESCAPE_ALLOC | RMESCAPE_GLOB)
3155 #if !defined(GLOB_BROKEN)
3156 static void addglob __P((const glob_t *));
3159 #if !(defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
3160 static void expmeta __P((char *, char *));
3162 static void addfname __P((char *));
3163 #if !(defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
3164 static struct strlist *expsort __P((struct strlist *));
3165 static struct strlist *msort __P((struct strlist *, int));
3167 #if defined(__GLIBC__) && !defined(FNMATCH_BROKEN)
3168 static int patmatch __P((char *, char *, int));
3169 static int patmatch2 __P((char *, char *, int));
3171 static int pmatch __P((char *, char *, int));
3172 #define patmatch2 patmatch
3174 static char *cvtnum __P((int, char *));
3176 extern int oexitstatus;
3179 * Expand shell variables and backquotes inside a here document.
3184 union node *arg; /* the document */
3185 int fd; /* where to write the expanded version */
3188 expandarg(arg, (struct arglist *)NULL, 0);
3189 xwrite(fd, stackblock(), expdest - stackblock());
3194 * Perform variable substitution and command substitution on an argument,
3195 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
3196 * perform splitting and file name expansion. When arglist is NULL, perform
3197 * here document expansion.
3201 expandarg(arg, arglist, flag)
3203 struct arglist *arglist;
3209 argbackq = arg->narg.backquote;
3210 STARTSTACKSTR(expdest);
3211 ifsfirst.next = NULL;
3213 argstr(arg->narg.text, flag);
3214 if (arglist == NULL) {
3215 return; /* here document expanded */
3217 STPUTC('\0', expdest);
3218 p = grabstackstr(expdest);
3219 exparg.lastp = &exparg.list;
3223 if (flag & EXP_FULL) {
3224 ifsbreakup(p, &exparg);
3225 *exparg.lastp = NULL;
3226 exparg.lastp = &exparg.list;
3227 expandmeta(exparg.list, flag);
3229 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
3231 sp = (struct strlist *)stalloc(sizeof (struct strlist));
3234 exparg.lastp = &sp->next;
3237 *exparg.lastp = NULL;
3239 *arglist->lastp = exparg.list;
3240 arglist->lastp = exparg.lastp;
3247 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
3248 * characters to allow for further processing. Otherwise treat
3249 * $@ like $* since no splitting will be performed.
3258 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
3261 if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
3262 p = exptilde(p, flag);
3266 case CTLENDVAR: /* ??? */
3269 /* "$@" syntax adherence hack */
3270 if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=')
3272 if ((flag & EXP_FULL) != 0)
3282 p = evalvar(p, flag);
3285 case CTLBACKQ|CTLQUOTE:
3286 expbackq(argbackq->n, c & CTLQUOTE, flag);
3287 argbackq = argbackq->next;
3289 #ifdef ASH_MATH_SUPPORT
3297 * sort of a hack - expand tildes in variable
3298 * assignments (after the first '=' and after ':'s).
3301 if (flag & EXP_VARTILDE && *p == '~') {
3308 p = exptilde(p, flag);
3324 char c, *startp = p;
3327 int quotes = flag & (EXP_FULL | EXP_CASE);
3329 while ((c = *p) != '\0') {
3336 if (flag & EXP_VARTILDE)
3346 if (*(startp+1) == '\0') {
3347 if ((home = lookupvar("HOME")) == NULL)
3350 if ((pw = getpwnam(startp+1)) == NULL)
3357 strtodest(home, SQSYNTAX, quotes);
3366 removerecordregions(endoff)
3369 if (ifslastp == NULL)
3372 if (ifsfirst.endoff > endoff) {
3373 while (ifsfirst.next != NULL) {
3374 struct ifsregion *ifsp;
3376 ifsp = ifsfirst.next->next;
3377 ckfree(ifsfirst.next);
3378 ifsfirst.next = ifsp;
3381 if (ifsfirst.begoff > endoff)
3384 ifslastp = &ifsfirst;
3385 ifsfirst.endoff = endoff;
3390 ifslastp = &ifsfirst;
3391 while (ifslastp->next && ifslastp->next->begoff < endoff)
3392 ifslastp=ifslastp->next;
3393 while (ifslastp->next != NULL) {
3394 struct ifsregion *ifsp;
3396 ifsp = ifslastp->next->next;
3397 ckfree(ifslastp->next);
3398 ifslastp->next = ifsp;
3401 if (ifslastp->endoff > endoff)
3402 ifslastp->endoff = endoff;
3406 #ifdef ASH_MATH_SUPPORT
3408 * Expand arithmetic expression. Backup to start of expression,
3409 * evaluate, place result in (backed up) result, adjust string position.
3418 int quotes = flag & (EXP_FULL | EXP_CASE);
3424 * This routine is slightly over-complicated for
3425 * efficiency. First we make sure there is
3426 * enough space for the result, which may be bigger
3427 * than the expression if we add exponentation. Next we
3428 * scan backwards looking for the start of arithmetic. If the
3429 * next previous character is a CTLESC character, then we
3430 * have to rescan starting from the beginning since CTLESC
3431 * characters have to be processed left to right.
3433 CHECKSTRSPACE(10, expdest);
3434 USTPUTC('\0', expdest);
3435 start = stackblock();
3437 while (*p != CTLARI && p >= start)
3440 error("missing CTLARI (shouldn't happen)");
3441 if (p > start && *(p-1) == CTLESC)
3442 for (p = start; *p != CTLARI; p++)
3451 removerecordregions(begoff);
3454 result = arith(p+2);
3455 fmtstr(p, 12, "%d", result);
3461 recordregion(begoff, p - 1 - start, 0);
3462 result = expdest - p + 1;
3463 STADJUST(-result, expdest);
3469 * Expand stuff in backwards quotes.
3473 expbackq(cmd, quoted, flag)
3478 volatile struct backcmd in;
3482 char *dest = expdest;
3483 volatile struct ifsregion saveifs;
3484 struct ifsregion *volatile savelastp;
3485 struct nodelist *volatile saveargbackq;
3487 int startloc = dest - stackblock();
3488 char const *syntax = quoted? DQSYNTAX : BASESYNTAX;
3489 volatile int saveherefd;
3490 int quotes = flag & (EXP_FULL | EXP_CASE);
3491 struct jmploc jmploc;
3492 struct jmploc *volatile savehandler;
3496 /* Avoid longjmp clobbering */
3507 savelastp = ifslastp;
3508 saveargbackq = argbackq;
3509 saveherefd = herefd;
3511 if ((ex = setjmp(jmploc.loc))) {
3514 savehandler = handler;
3517 p = grabstackstr(dest);
3518 evalbackcmd(cmd, (struct backcmd *) &in);
3519 ungrabstackstr(p, dest);
3523 ifslastp = savelastp;
3524 argbackq = saveargbackq;
3525 herefd = saveherefd;
3533 if (--in.nleft < 0) {
3536 while ((i = read(in.fd, buf, sizeof buf)) < 0 && errno == EINTR);
3537 TRACE(("expbackq: read returns %d\n", i));
3544 if (lastc != '\0') {
3545 if (quotes && syntax[(int)lastc] == CCTL)
3546 STPUTC(CTLESC, dest);
3547 STPUTC(lastc, dest);
3551 /* Eat all trailing newlines */
3552 for (; dest > stackblock() && dest[-1] == '\n';)
3561 exitstatus = waitforjob(in.jp);
3562 handler = savehandler;
3564 longjmp(handler->loc, 1);
3567 recordregion(startloc, dest - stackblock(), 0);
3568 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
3569 (dest - stackblock()) - startloc,
3570 (dest - stackblock()) - startloc,
3571 stackblock() + startloc));
3579 subevalvar(p, str, strloc, subtype, startloc, varflags, quotes)
3592 int saveherefd = herefd;
3593 struct nodelist *saveargbackq = argbackq;
3597 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
3598 STACKSTRNUL(expdest);
3599 herefd = saveherefd;
3600 argbackq = saveargbackq;
3601 startp = stackblock() + startloc;
3603 str = stackblock() + strloc;
3607 setvar(str, startp, 0);
3608 amount = startp - expdest;
3609 STADJUST(amount, expdest);
3616 if (*p != CTLENDVAR) {
3617 outfmt(&errout, snlfmt, startp);
3618 error((char *)NULL);
3620 error("%.*s: parameter %snot set", p - str - 1,
3621 str, (varflags & VSNUL) ? "null or "
3626 for (loc = startp; loc < str; loc++) {
3629 if (patmatch2(str, startp, quotes))
3632 if (quotes && *loc == CTLESC)
3638 for (loc = str - 1; loc >= startp;) {
3641 if (patmatch2(str, startp, quotes))
3645 if (quotes && loc > startp && *(loc - 1) == CTLESC) {
3646 for (q = startp; q < loc; q++)
3656 for (loc = str - 1; loc >= startp;) {
3657 if (patmatch2(str, loc, quotes))
3660 if (quotes && loc > startp && *(loc - 1) == CTLESC) {
3661 for (q = startp; q < loc; q++)
3670 case VSTRIMRIGHTMAX:
3671 for (loc = startp; loc < str - 1; loc++) {
3672 if (patmatch2(str, loc, quotes))
3674 if (quotes && *loc == CTLESC)
3687 amount = ((str - 1) - (loc - startp)) - expdest;
3688 STADJUST(amount, expdest);
3689 while (loc != str - 1)
3694 amount = loc - expdest;
3695 STADJUST(amount, expdest);
3696 STPUTC('\0', expdest);
3697 STADJUST(-1, expdest);
3703 * Expand a variable, and return a pointer to the next character in the
3723 int quotes = flag & (EXP_FULL | EXP_CASE);
3726 subtype = varflags & VSTYPE;
3731 p = strchr(p, '=') + 1;
3732 again: /* jump here after setting a variable with ${var=text} */
3734 set = varisset(var, varflags & VSNUL);
3737 val = lookupvar(var);
3738 if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
3745 startloc = expdest - stackblock();
3746 if (set && subtype != VSPLUS) {
3747 /* insert the value of the variable */
3749 varvalue(var, varflags & VSQUOTE, flag);
3750 if (subtype == VSLENGTH) {
3751 varlen = expdest - stackblock() - startloc;
3752 STADJUST(-varlen, expdest);
3755 if (subtype == VSLENGTH) {
3756 varlen = strlen(val);
3760 varflags & VSQUOTE ?
3761 DQSYNTAX : BASESYNTAX,
3768 if (subtype == VSPLUS)
3771 easy = ((varflags & VSQUOTE) == 0 ||
3772 (*var == '@' && shellparam.nparam != 1));
3777 expdest = cvtnum(varlen, expdest);
3784 recordregion(startloc, expdest - stackblock(),
3785 varflags & VSQUOTE);
3801 case VSTRIMRIGHTMAX:
3805 * Terminate the string and start recording the pattern
3808 STPUTC('\0', expdest);
3809 patloc = expdest - stackblock();
3810 if (subevalvar(p, NULL, patloc, subtype,
3811 startloc, varflags, quotes) == 0) {
3812 int amount = (expdest - stackblock() - patloc) + 1;
3813 STADJUST(-amount, expdest);
3815 /* Remove any recorded regions beyond start of variable */
3816 removerecordregions(startloc);
3822 if (subevalvar(p, var, 0, subtype, startloc,
3823 varflags, quotes)) {
3826 * Remove any recorded regions beyond
3829 removerecordregions(startloc);
3844 if (subtype != VSNORMAL) { /* skip to end of alternative */
3847 if ((c = *p++) == CTLESC)
3849 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
3851 argbackq = argbackq->next;
3852 } else if (c == CTLVAR) {
3853 if ((*p++ & VSTYPE) != VSNORMAL)
3855 } else if (c == CTLENDVAR) {
3867 * Test whether a specialized variable is set.
3871 varisset(name, nulok)
3876 return backgndpid != -1;
3877 else if (*name == '@' || *name == '*') {
3878 if (*shellparam.p == NULL)
3884 for (av = shellparam.p; *av; av++)
3889 } else if (is_digit(*name)) {
3891 int num = atoi(name);
3893 if (num > shellparam.nparam)
3899 ap = shellparam.p[num - 1];
3901 if (nulok && (ap == NULL || *ap == '\0'))
3910 * Put a string on the stack.
3914 strtodest(p, syntax, quotes)
3920 if (quotes && syntax[(int) *p] == CCTL)
3921 STPUTC(CTLESC, expdest);
3922 STPUTC(*p++, expdest);
3929 * Add the value of a specialized variable to the stack string.
3933 varvalue(name, quoted, flags)
3945 int allow_split = flags & EXP_FULL;
3946 int quotes = flags & (EXP_FULL | EXP_CASE);
3948 syntax = quoted ? DQSYNTAX : BASESYNTAX;
3957 num = shellparam.nparam;
3962 expdest = cvtnum(num, expdest);
3965 for (i = 0 ; i < NOPTS ; i++) {
3967 STPUTC(optlist[i].letter, expdest);
3971 if (allow_split && quoted) {
3972 sep = 1 << CHAR_BIT;
3977 sep = ifsset() ? ifsval()[0] : ' ';
3979 sepq = syntax[(int) sep] == CCTL;
3982 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
3983 strtodest(p, syntax, quotes);
3986 STPUTC(CTLESC, expdest);
3987 STPUTC(sep, expdest);
3992 strtodest(arg0, syntax, quotes);
3996 if (num > 0 && num <= shellparam.nparam) {
3997 strtodest(shellparam.p[num - 1], syntax, quotes);
4006 * Record the fact that we have to scan this region of the
4007 * string for IFS characters.
4011 recordregion(start, end, nulonly)
4016 struct ifsregion *ifsp;
4018 if (ifslastp == NULL) {
4022 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
4024 ifslastp->next = ifsp;
4028 ifslastp->begoff = start;
4029 ifslastp->endoff = end;
4030 ifslastp->nulonly = nulonly;
4036 * Break the argument string into pieces based upon IFS and add the
4037 * strings to the argument list. The regions of the string to be
4038 * searched for IFS characters have been stored by recordregion.
4041 ifsbreakup(string, arglist)
4043 struct arglist *arglist;
4045 struct ifsregion *ifsp;
4050 const char *ifs, *realifs;
4058 realifs = ifsset() ? ifsval() : defifs;
4059 if (ifslastp != NULL) {
4062 p = string + ifsp->begoff;
4063 nulonly = ifsp->nulonly;
4064 ifs = nulonly ? nullstr : realifs;
4066 while (p < string + ifsp->endoff) {
4070 if (strchr(ifs, *p)) {
4072 ifsspc = (strchr(defifs, *p) != NULL);
4073 /* Ignore IFS whitespace at start */
4074 if (q == start && ifsspc) {
4080 sp = (struct strlist *)stalloc(sizeof *sp);
4082 *arglist->lastp = sp;
4083 arglist->lastp = &sp->next;
4087 if (p >= string + ifsp->endoff) {
4093 if (strchr(ifs, *p) == NULL ) {
4096 } else if (strchr(defifs, *p) == NULL) {
4112 } while ((ifsp = ifsp->next) != NULL);
4113 if (!(*start || (!ifsspc && start > string && nulonly))) {
4118 sp = (struct strlist *)stalloc(sizeof *sp);
4120 *arglist->lastp = sp;
4121 arglist->lastp = &sp->next;
4127 while (ifsfirst.next != NULL) {
4128 struct ifsregion *ifsp;
4130 ifsp = ifsfirst.next->next;
4131 ckfree(ifsfirst.next);
4132 ifsfirst.next = ifsp;
4136 ifsfirst.next = NULL;
4142 * Expand shell metacharacters. At this point, the only control characters
4143 * should be escapes. The results are stored in the list exparg.
4146 #if defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)
4148 expandmeta(str, flag)
4149 struct strlist *str;
4154 /* TODO - EXP_REDIR */
4159 p = preglob(str->text);
4161 switch (glob(p, GLOB_NOMAGIC, 0, &pglob)) {
4163 if (!(pglob.gl_flags & GLOB_MAGCHAR))
4174 *exparg.lastp = str;
4175 rmescapes(str->text);
4176 exparg.lastp = &str->next;
4178 default: /* GLOB_NOSPACE */
4179 error("Out of space");
4187 * Add the result of glob(3) to the list.
4192 const glob_t *pglob;
4194 char **p = pglob->gl_pathv;
4202 #else /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
4203 static char *expdir;
4207 expandmeta(str, flag)
4208 struct strlist *str;
4212 struct strlist **savelastp;
4215 /* TODO - EXP_REDIR */
4221 for (;;) { /* fast check for meta chars */
4222 if ((c = *p++) == '\0')
4224 if (c == '*' || c == '?' || c == '[' || c == '!')
4227 savelastp = exparg.lastp;
4229 if (expdir == NULL) {
4230 int i = strlen(str->text);
4231 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
4234 expmeta(expdir, str->text);
4238 if (exparg.lastp == savelastp) {
4243 *exparg.lastp = str;
4244 rmescapes(str->text);
4245 exparg.lastp = &str->next;
4247 *exparg.lastp = NULL;
4248 *savelastp = sp = expsort(*savelastp);
4249 while (sp->next != NULL)
4251 exparg.lastp = &sp->next;
4259 * Do metacharacter (i.e. *, ?, [...]) expansion.
4263 expmeta(enddir, name)
4281 for (p = name ; ; p++) {
4282 if (*p == '*' || *p == '?')
4284 else if (*p == '[') {
4289 while (*q == CTLQUOTEMARK)
4293 if (*q == '/' || *q == '\0')
4300 } else if (*p == '!' && p[1] == '!' && (p == name || p[-1] == '/')) {
4302 } else if (*p == '\0')
4304 else if (*p == CTLQUOTEMARK)
4306 else if (*p == CTLESC)
4314 if (metaflag == 0) { /* we've reached the end of the file name */
4315 if (enddir != expdir)
4317 for (p = name ; ; p++) {
4318 if (*p == CTLQUOTEMARK)
4326 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
4331 if (start != name) {
4334 while (*p == CTLQUOTEMARK)
4341 if (enddir == expdir) {
4343 } else if (enddir == expdir + 1 && *expdir == '/') {
4349 if ((dirp = opendir(cp)) == NULL)
4351 if (enddir != expdir)
4353 if (*endname == 0) {
4361 while (*p == CTLQUOTEMARK)
4367 while (! int_pending() && (dp = readdir(dirp)) != NULL) {
4368 if (dp->d_name[0] == '.' && ! matchdot)
4370 if (patmatch(start, dp->d_name, 0)) {
4372 scopy(dp->d_name, enddir);
4375 for (p = enddir, cp = dp->d_name;
4376 (*p++ = *cp++) != '\0';)
4379 expmeta(p, endname);
4387 #endif /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
4391 * Add a file name to the list.
4402 sp = (struct strlist *)stalloc(sizeof *sp);
4405 exparg.lastp = &sp->next;
4409 #if !(defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
4411 * Sort the results of file name expansion. It calculates the number of
4412 * strings to sort and then calls msort (short for merge sort) to do the
4416 static struct strlist *
4418 struct strlist *str;
4424 for (sp = str ; sp ; sp = sp->next)
4426 return msort(str, len);
4430 static struct strlist *
4432 struct strlist *list;
4435 struct strlist *p, *q = NULL;
4436 struct strlist **lpp;
4444 for (n = half ; --n >= 0 ; ) {
4448 q->next = NULL; /* terminate first half of list */
4449 q = msort(list, half); /* sort first half of list */
4450 p = msort(p, len - half); /* sort second half */
4453 if (strcmp(p->text, q->text) < 0) {
4456 if ((p = *lpp) == NULL) {
4463 if ((q = *lpp) == NULL) {
4476 * Returns true if the pattern matches the string.
4479 #if defined(__GLIBC__) && !defined(FNMATCH_BROKEN)
4481 patmatch(pattern, string, squoted)
4484 int squoted; /* string might have quote chars */
4489 p = preglob(pattern);
4490 q = squoted ? _rmescapes(string, RMESCAPE_ALLOC) : string;
4492 return !fnmatch(p, q, 0);
4497 patmatch2(pattern, string, squoted)
4500 int squoted; /* string might have quote chars */
4506 p = grabstackstr(expdest);
4507 res = patmatch(pattern, string, squoted);
4508 ungrabstackstr(p, expdest);
4513 patmatch(pattern, string, squoted)
4516 int squoted; /* string might have quote chars */
4519 if (pattern[0] == '!' && pattern[1] == '!')
4520 return 1 - pmatch(pattern + 2, string);
4523 return pmatch(pattern, string, squoted);
4528 pmatch(pattern, string, squoted)
4543 if (squoted && *q == CTLESC)
4551 if (squoted && *q == CTLESC)
4558 while (c == CTLQUOTEMARK || c == '*')
4560 if (c != CTLESC && c != CTLQUOTEMARK &&
4561 c != '?' && c != '*' && c != '[') {
4563 if (squoted && *q == CTLESC &&
4568 if (squoted && *q == CTLESC)
4574 if (pmatch(p, q, squoted))
4576 if (squoted && *q == CTLESC)
4578 } while (*q++ != '\0');
4589 while (*endp == CTLQUOTEMARK)
4592 goto dft; /* no matching ] */
4593 if (*endp == CTLESC)
4605 if (squoted && chr == CTLESC)
4611 if (c == CTLQUOTEMARK)
4615 if (*p == '-' && p[1] != ']') {
4617 while (*p == CTLQUOTEMARK)
4621 if (chr >= c && chr <= *p)
4628 } while ((c = *p++) != ']');
4629 if (found == invert)
4634 if (squoted && *q == CTLESC)
4651 * Remove any CTLESC characters from a string.
4654 #if defined(__GLIBC__) && !defined(FNMATCH_BROKEN)
4656 _rmescapes(str, flag)
4661 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
4663 p = strpbrk(str, qchars);
4669 if (flag & RMESCAPE_ALLOC) {
4670 size_t len = p - str;
4671 q = r = stalloc(strlen(p) + len + 1);
4674 q = mempcpy(q, str, len);
4676 memcpy(q, str, len);
4682 if (*p == CTLQUOTEMARK) {
4688 if (flag & RMESCAPE_GLOB && *p != '/') {
4705 while (*p != CTLESC && *p != CTLQUOTEMARK) {
4711 if (*p == CTLQUOTEMARK) {
4726 * See if a pattern matches in a case statement.
4730 casematch(pattern, val)
4731 union node *pattern;
4734 struct stackmark smark;
4738 setstackmark(&smark);
4739 argbackq = pattern->narg.backquote;
4740 STARTSTACKSTR(expdest);
4742 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
4743 STPUTC('\0', expdest);
4744 p = grabstackstr(expdest);
4745 result = patmatch(p, val, 0);
4746 popstackmark(&smark);
4761 CHECKSTRSPACE(32, buf);
4762 len = sprintf(buf, "%d", num);
4766 /* $NetBSD: histedit.c,v 1.25 2001/02/04 19:52:06 christos Exp $ */
4769 * Editline and history functions (and glue).
4771 static int histcmd(argc, argv)
4775 error("not compiled with history support");
4781 * This file was generated by the mkinit program.
4784 extern void rmaliases __P((void));
4786 extern int loopnest; /* current loop nesting level */
4788 extern void deletefuncs __P((void));
4791 struct strpush *prev; /* preceding string on stack */
4794 struct alias *ap; /* if push was associated with an alias */
4795 char *string; /* remember the string since it may change */
4799 struct parsefile *prev; /* preceding file on stack */
4800 int linno; /* current line */
4801 int fd; /* file descriptor (or -1 if string) */
4802 int nleft; /* number of chars left in this line */
4803 int lleft; /* number of chars left in this buffer */
4804 char *nextc; /* next char in buffer */
4805 char *buf; /* input buffer */
4806 struct strpush *strpush; /* for pushing strings at this level */
4807 struct strpush basestrpush; /* so pushing one is fast */
4810 extern int parselleft; /* copy of parsefile->lleft */
4811 extern struct parsefile basepf; /* top level input file */
4812 extern char basebuf[BUFSIZ]; /* buffer for top level input file */
4814 extern short backgndpid; /* pid of last background process */
4817 extern int tokpushback; /* last token pushed back */
4818 extern int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */
4821 struct redirtab *next;
4825 extern struct redirtab *redirlist;
4827 extern char sigmode[NSIG - 1]; /* current value of signal */
4829 extern char **environ;
4834 * Initialization code.
4847 basepf.nextc = basepf.buf = basebuf;
4850 /* from output.c: */
4852 #ifdef USE_GLIBC_STDIO
4863 for (envp = environ ; *envp ; envp++) {
4864 if (strchr(*envp, '=')) {
4865 setvareq(*envp, VEXPORT|VTEXTFIXED);
4869 fmtstr(ppid, sizeof(ppid), "%d", (int) getppid());
4870 setvar("PPID", ppid, 0);
4877 * This routine is called when an error or an interrupt occurs in an
4878 * interactive shell and control is returned to the main command loop.
4893 if (exception != EXSHELLPROC)
4894 parselleft = parsenleft = 0; /* clear input buffer */
4898 /* from parser.c: */
4911 /* from output.c: */
4915 #ifdef USE_GLIBC_STDIO
4916 if (memout.stream != NULL)
4919 if (memout.buf != NULL) {
4929 * This routine is called to initialize the shell to run a shell procedure.
4958 /* from options.c: */
4962 for (i = 0; i < NOPTS; i++)
4978 for (sm = sigmode ; sm < sigmode + NSIG - 1; sm++) {
4989 /* $NetBSD: input.c,v 1.35 2001/02/04 19:52:06 christos Exp $ */
4992 * This file implements the input routines used by the parser.
4995 #ifdef BB_FEATURE_COMMAND_EDITING
4996 unsigned int shell_context;
4997 static const char * cmdedit_prompt;
4998 static inline void putprompt(const char *s) {
5002 static inline void putprompt(const char *s) {
5007 #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
5009 static int plinno = 1; /* input line number */
5010 static int parsenleft; /* copy of parsefile->nleft */
5011 static int parselleft; /* copy of parsefile->lleft */
5012 static char *parsenextc; /* copy of parsefile->nextc */
5013 struct parsefile basepf; /* top level input file */
5014 static char basebuf[BUFSIZ]; /* buffer for top level input file */
5015 struct parsefile *parsefile = &basepf; /* current input file */
5016 static int whichprompt; /* 1 == PS1, 2 == PS2 */
5018 static void pushfile __P((void));
5019 static int preadfd __P((void));
5027 basepf.nextc = basepf.buf = basebuf;
5031 if (exception != EXSHELLPROC)
5032 parselleft = parsenleft = 0; /* clear input buffer */
5039 * Read a line from the script.
5051 while (--nleft > 0) {
5068 * Read a character from the script, returning PEOF on end of file.
5069 * Nul characters in the input are silently discarded.
5075 return pgetc_macro();
5080 * Same as pgetc(), but ignores PEOA.
5089 } while (c == PEOA);
5098 char *buf = parsefile->buf;
5102 #ifdef BB_FEATURE_COMMAND_EDITING
5105 nr = read(parsefile->fd, buf, BUFSIZ - 1);
5108 cmdedit_read_input((char*)cmdedit_prompt, buf);
5110 } while (nr <=0 || shell_context);
5111 cmdedit_terminate();
5115 nr = read(parsefile->fd, buf, BUFSIZ - 1);
5121 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
5122 int flags = fcntl(0, F_GETFL, 0);
5123 if (flags >= 0 && flags & O_NONBLOCK) {
5124 flags &=~ O_NONBLOCK;
5125 if (fcntl(0, F_SETFL, flags) >= 0) {
5126 out2str("sh: turning off NDELAY mode\n");
5136 * Refill the input buffer and return the next input character:
5138 * 1) If a string was pushed back on the input, pop it;
5139 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
5140 * from a string so we can't refill the buffer, return EOF.
5141 * 3) If the is more stuff in this buffer, use it else call read to fill it.
5142 * 4) Process input up to the next newline, deleting nul characters.
5152 while (parsefile->strpush) {
5154 parsenleft == -1 && parsefile->strpush->ap &&
5155 parsenextc[-1] != ' ' && parsenextc[-1] != '\t'
5160 if (--parsenleft >= 0)
5161 return (*parsenextc++);
5163 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
5171 if (parselleft <= 0) {
5172 if ((parselleft = preadfd()) <= 0) {
5173 parselleft = parsenleft = EOF_NLEFT;
5180 /* delete nul characters */
5181 for (more = 1; more;) {
5189 parsenleft = q - parsenextc;
5190 more = 0; /* Stop processing here */
5196 if (--parselleft <= 0 && more) {
5197 parsenleft = q - parsenextc - 1;
5208 out2str(parsenextc);
5216 return *parsenextc++;
5220 * Undo the last call to pgetc. Only one character may be pushed back.
5221 * PEOF may be pushed back.
5231 * Push a string back onto the input at this current parsefile level.
5232 * We handle aliases this way.
5235 pushstring(s, len, ap)
5243 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
5244 if (parsefile->strpush) {
5245 sp = ckmalloc(sizeof (struct strpush));
5246 sp->prev = parsefile->strpush;
5247 parsefile->strpush = sp;
5249 sp = parsefile->strpush = &(parsefile->basestrpush);
5250 sp->prevstring = parsenextc;
5251 sp->prevnleft = parsenleft;
5252 sp->ap = (struct alias *)ap;
5254 ((struct alias *)ap)->flag |= ALIASINUSE;
5265 struct strpush *sp = parsefile->strpush;
5269 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
5274 if (sp->string != sp->ap->val) {
5277 sp->ap->flag &= ~ALIASINUSE;
5278 if (sp->ap->flag & ALIASDEAD) {
5279 unalias(sp->ap->name);
5282 parsenextc = sp->prevstring;
5283 parsenleft = sp->prevnleft;
5284 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
5285 parsefile->strpush = sp->prev;
5286 if (sp != &(parsefile->basestrpush))
5292 * Set the input to take input from a file. If push is set, push the
5293 * old input onto the stack first.
5297 setinputfile(fname, push)
5305 if ((fd = open(fname, O_RDONLY)) < 0)
5306 error("Can't open %s", fname);
5308 myfileno2 = dup_as_newfd(fd, 10);
5311 error("Out of file descriptors");
5314 setinputfd(fd, push);
5320 * Like setinputfile, but takes an open file descriptor. Call this with
5325 setinputfd(fd, push)
5328 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
5334 while (parsefile->strpush)
5338 if (parsefile->buf == NULL)
5339 parsefile->buf = ckmalloc(BUFSIZ);
5340 parselleft = parsenleft = 0;
5346 * Like setinputfile, but takes input from a string.
5350 setinputstring(string)
5355 parsenextc = string;
5356 parsenleft = strlen(string);
5357 parsefile->buf = NULL;
5365 * To handle the "." command, a stack of input files is used. Pushfile
5366 * adds a new entry to the stack and popfile restores the previous level.
5371 struct parsefile *pf;
5373 parsefile->nleft = parsenleft;
5374 parsefile->lleft = parselleft;
5375 parsefile->nextc = parsenextc;
5376 parsefile->linno = plinno;
5377 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
5378 pf->prev = parsefile;
5381 pf->basestrpush.prev = NULL;
5388 struct parsefile *pf = parsefile;
5397 parsefile = pf->prev;
5399 parsenleft = parsefile->nleft;
5400 parselleft = parsefile->lleft;
5401 parsenextc = parsefile->nextc;
5402 plinno = parsefile->linno;
5408 * Return to top level.
5413 while (parsefile != &basepf)
5420 * Close the file(s) that the shell is reading commands from. Called
5421 * after a fork is done.
5427 if (parsefile->fd > 0) {
5428 close(parsefile->fd);
5432 /* $NetBSD: jobs.c,v 1.36 2000/05/22 10:18:47 elric Exp $ */
5435 struct job *jobtab; /* array of jobs */
5436 static int njobs; /* size of array */
5437 short backgndpid = -1; /* pid of last background process */
5439 static int initialpgrp; /* pgrp of shell on invocation */
5440 short curjob; /* current job */
5442 static int intreceived;
5444 static void restartjob __P((struct job *));
5445 static void freejob __P((struct job *));
5446 static struct job *getjob __P((char *));
5447 static int dowait __P((int, struct job *));
5449 static int onsigchild __P((void));
5451 static int waitproc __P((int, int *));
5452 static void cmdtxt __P((union node *));
5453 static void cmdputs __P((const char *));
5454 static void waitonint(int);
5459 * Turn job control on and off.
5461 * Note: This code assumes that the third arg to ioctl is a character
5462 * pointer, which is true on Berkeley systems but not System V. Since
5463 * System V doesn't have job control yet, this isn't a problem now.
5468 static void setjobctl(int enable)
5470 #ifdef OLD_TTY_DRIVER
5474 if (enable == jobctl || rootshell == 0)
5477 do { /* while we are in the background */
5478 #ifdef OLD_TTY_DRIVER
5479 if (ioctl(fileno2, TIOCGPGRP, (char *)&initialpgrp) < 0) {
5481 initialpgrp = tcgetpgrp(fileno2);
5482 if (initialpgrp < 0) {
5484 out2str("sh: can't access tty; job cenabletrol turned off\n");
5488 if (initialpgrp == -1)
5489 initialpgrp = getpgrp();
5490 else if (initialpgrp != getpgrp()) {
5491 killpg(initialpgrp, SIGTTIN);
5495 #ifdef OLD_TTY_DRIVER
5496 if (ioctl(fileno2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) {
5497 out2str("sh: need new tty driver to run job cenabletrol; job cenabletrol turned off\n");
5505 setpgid(0, rootpid);
5506 #ifdef OLD_TTY_DRIVER
5507 ioctl(fileno2, TIOCSPGRP, (char *)&rootpid);
5509 tcsetpgrp(fileno2, rootpid);
5511 } else { /* turning job cenabletrol off */
5512 setpgid(0, initialpgrp);
5513 #ifdef OLD_TTY_DRIVER
5514 ioctl(fileno2, TIOCSPGRP, (char *)&initialpgrp);
5516 tcsetpgrp(fileno2, initialpgrp);
5540 /* This file was automatically created by ./mksignames.
5541 Do not edit. Edit support/mksignames.c instead. */
5543 /* A translation list so we can be polite to our users. */
5544 static char *signal_names[NSIG + 2] = {
5630 "Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
5631 "kill -l [exitstatus]"
5635 if (*argv[1] == '-') {
5636 signo = decode_signal(argv[1] + 1, 1);
5640 while ((c = nextopt("ls:")) != '\0')
5646 signo = decode_signal(optionarg, 1);
5649 "invalid signal number or name: %s",
5657 "nextopt returned character code 0%o", c);
5664 if (!list && signo < 0)
5667 if ((signo < 0 || !*argptr) ^ list) {
5674 for (i = 1; i < NSIG; i++) {
5675 out1fmt(snlfmt, signal_names[i] + 3);
5679 signo = atoi(*argptr);
5682 if (0 < signo && signo < NSIG)
5683 out1fmt(snlfmt, signal_names[signo] + 3);
5685 error("invalid signal number or exit status: %s",
5691 if (**argptr == '%') {
5692 jp = getjob(*argptr);
5693 if (jp->jobctl == 0)
5694 error("job %s not created under job control",
5696 pid = -jp->ps[0].pid;
5698 pid = atoi(*argptr);
5699 if (kill(pid, signo) != 0)
5700 error("%s: %s", *argptr, strerror(errno));
5701 } while (*++argptr);
5715 jp = getjob(argv[1]);
5716 if (jp->jobctl == 0)
5717 error("job not created under job control");
5718 pgrp = jp->ps[0].pid;
5719 #ifdef OLD_TTY_DRIVER
5720 ioctl(fileno2, TIOCSPGRP, (char *)&pgrp);
5722 tcsetpgrp(fileno2, pgrp);
5726 status = waitforjob(jp);
5740 jp = getjob(*++argv);
5741 if (jp->jobctl == 0)
5742 error("job not created under job control");
5744 } while (--argc > 1);
5753 struct procstat *ps;
5756 if (jp->state == JOBDONE)
5759 killpg(jp->ps[0].pid, SIGCONT);
5760 for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
5761 if (WIFSTOPPED(ps->status)) {
5782 * Print a list of jobs. If "change" is nonzero, only print jobs whose
5783 * statuses have changed since the last call to showjobs.
5785 * If the shell is interrupted in the process of creating a job, the
5786 * result may be a job structure containing zero processes. Such structures
5787 * will be freed here.
5798 struct procstat *ps;
5802 TRACE(("showjobs(%d) called\n", change));
5803 while (dowait(0, (struct job *)NULL) > 0);
5804 for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
5807 if (jp->nprocs == 0) {
5811 if (change && ! jp->changed)
5813 procno = jp->nprocs;
5814 for (ps = jp->ps ; ; ps++) { /* for each process */
5816 fmtstr(s, 64, "[%d] %ld ", jobno,
5819 fmtstr(s, 64, " %ld ",
5824 if (ps->status == -1) {
5825 /* don't print anything */
5826 } else if (WIFEXITED(ps->status)) {
5827 fmtstr(s, 64, "Exit %d",
5828 WEXITSTATUS(ps->status));
5831 if (WIFSTOPPED(ps->status))
5832 i = WSTOPSIG(ps->status);
5833 else /* WIFSIGNALED(ps->status) */
5835 i = WTERMSIG(ps->status);
5836 if ((i & 0x7F) < NSIG && sys_siglist[i & 0x7F])
5837 scopy(sys_siglist[i & 0x7F], s);
5839 fmtstr(s, 64, "Signal %d", i & 0x7F);
5840 if (WCOREDUMP(ps->status))
5841 strcat(s, " (core dumped)");
5846 "%*c%s\n", 30 - col >= 0 ? 30 - col : 0, ' ',
5853 if (jp->state == JOBDONE) {
5861 * Mark a job structure as unused.
5868 struct procstat *ps;
5872 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
5873 if (ps->cmd != nullstr)
5876 if (jp->ps != &jp->ps0)
5880 if (curjob == jp - jobtab + 1)
5899 job = getjob(*++argv);
5903 for (;;) { /* loop until process terminated or stopped */
5906 status = job->ps[job->nprocs - 1].status;
5912 if (WIFEXITED(status))
5913 retval = WEXITSTATUS(status);
5915 else if (WIFSTOPPED(status))
5916 retval = WSTOPSIG(status) + 128;
5919 /* XXX: limits number of signals */
5920 retval = WTERMSIG(status) + 128;
5925 for (jp = jobtab ; ; jp++) {
5926 if (jp >= jobtab + njobs) { /* no running procs */
5929 if (jp->used && jp->state == 0)
5933 if (dowait(2, 0) < 0 && errno == EINTR) {
5942 * Convert a job name to a job structure.
5957 if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0)
5958 error("No current job");
5959 return &jobtab[jobno - 1];
5961 error("No current job");
5963 } else if (name[0] == '%') {
5964 if (is_digit(name[1])) {
5965 jobno = number(name + 1);
5966 if (jobno > 0 && jobno <= njobs
5967 && jobtab[jobno - 1].used != 0)
5968 return &jobtab[jobno - 1];
5970 } else if (name[1] == '%' && name[2] == '\0') {
5974 struct job *found = NULL;
5975 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
5976 if (jp->used && jp->nprocs > 0
5977 && prefix(name + 1, jp->ps[0].cmd)) {
5979 error("%s: ambiguous", name);
5986 } else if (is_number(name)) {
5988 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
5989 if (jp->used && jp->nprocs > 0
5990 && jp->ps[jp->nprocs - 1].pid == pid)
5994 error("No such job: %s", name);
6001 * Return a new job structure,
6005 makejob(node, nprocs)
6012 for (i = njobs, jp = jobtab ; ; jp++) {
6016 jobtab = ckmalloc(4 * sizeof jobtab[0]);
6018 jp = ckmalloc((njobs + 4) * sizeof jobtab[0]);
6019 memcpy(jp, jobtab, njobs * sizeof jp[0]);
6020 /* Relocate `ps' pointers */
6021 for (i = 0; i < njobs; i++)
6022 if (jp[i].ps == &jobtab[i].ps0)
6023 jp[i].ps = &jp[i].ps0;
6027 jp = jobtab + njobs;
6028 for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0);
6041 jp->jobctl = jobctl;
6044 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
6049 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
6056 * Fork of a subshell. If we are doing job control, give the subshell its
6057 * own process group. Jp is a job structure that the job is to be added to.
6058 * N is the command that will be evaluated by the child. Both jp and n may
6059 * be NULL. The mode parameter can be one of the following:
6060 * FORK_FG - Fork off a foreground process.
6061 * FORK_BG - Fork off a background process.
6062 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
6063 * process group even if job control is on.
6065 * When job control is turned off, background processes have their standard
6066 * input redirected to /dev/null (except for the second and later processes
6071 forkshell(jp, n, mode)
6078 const char *devnull = _PATH_DEVNULL;
6079 const char *nullerr = "Can't open %s";
6081 TRACE(("forkshell(%%%d, 0x%lx, %d) called\n", jp - jobtab, (long)n,
6086 TRACE(("Fork failed, errno=%d\n", errno));
6088 error("Cannot fork");
6095 TRACE(("Child shell %d\n", getpid()));
6096 wasroot = rootshell;
6102 jobctl = 0; /* do job control only in root shell */
6103 if (wasroot && mode != FORK_NOJOB && mflag) {
6104 if (jp == NULL || jp->nprocs == 0)
6107 pgrp = jp->ps[0].pid;
6109 if (mode == FORK_FG) {
6110 /*** this causes superfluous TIOCSPGRPS ***/
6111 #ifdef OLD_TTY_DRIVER
6112 if (ioctl(fileno2, TIOCSPGRP, (char *)&pgrp) < 0)
6113 error("TIOCSPGRP failed, errno=%d", errno);
6115 if (tcsetpgrp(fileno2, pgrp) < 0)
6116 error("tcsetpgrp failed, errno=%d", errno);
6121 } else if (mode == FORK_BG) {
6124 if ((jp == NULL || jp->nprocs == 0) &&
6125 ! fd0_redirected_p ()) {
6127 if (open(devnull, O_RDONLY) != 0)
6128 error(nullerr, devnull);
6132 if (mode == FORK_BG) {
6135 if ((jp == NULL || jp->nprocs == 0) &&
6136 ! fd0_redirected_p ()) {
6138 if (open(devnull, O_RDONLY) != 0)
6139 error(nullerr, devnull);
6143 for (i = njobs, p = jobtab ; --i >= 0 ; p++)
6146 if (wasroot && iflag) {
6153 if (rootshell && mode != FORK_NOJOB && mflag) {
6154 if (jp == NULL || jp->nprocs == 0)
6157 pgrp = jp->ps[0].pid;
6160 if (mode == FORK_BG)
6161 backgndpid = pid; /* set $! */
6163 struct procstat *ps = &jp->ps[jp->nprocs++];
6167 if (iflag && rootshell && n)
6168 ps->cmd = commandtext(n);
6171 TRACE(("In parent shell: child = %d\n", pid));
6178 * Wait for job to finish.
6180 * Under job control we have the problem that while a child process is
6181 * running interrupts generated by the user are sent to the child but not
6182 * to the shell. This means that an infinite loop started by an inter-
6183 * active user may be hard to kill. With job control turned off, an
6184 * interactive user may place an interactive program inside a loop. If
6185 * the interactive program catches interrupts, the user doesn't want
6186 * these interrupts to also abort the loop. The approach we take here
6187 * is to have the shell ignore interrupt signals while waiting for a
6188 * forground process to terminate, and then send itself an interrupt
6189 * signal if the child process was terminated by an interrupt signal.
6190 * Unfortunately, some programs want to do a bit of cleanup and then
6191 * exit on interrupt; unless these processes terminate themselves by
6192 * sending a signal to themselves (instead of calling exit) they will
6193 * confuse this approach.
6201 int mypgrp = getpgrp();
6205 struct sigaction act, oact;
6214 sigaction(SIGINT, 0, &act);
6215 act.sa_handler = waitonint;
6216 sigaction(SIGINT, &act, &oact);
6218 TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
6219 while (jp->state == 0) {
6227 sigaction(SIGINT, &oact, 0);
6228 if (intreceived && trap[SIGINT]) kill(getpid(), SIGINT);
6232 #ifdef OLD_TTY_DRIVER
6233 if (ioctl(fileno2, TIOCSPGRP, (char *)&mypgrp) < 0)
6234 error("TIOCSPGRP failed, errno=%d\n", errno);
6236 if (tcsetpgrp(fileno2, mypgrp) < 0)
6237 error("tcsetpgrp failed, errno=%d\n", errno);
6240 if (jp->state == JOBSTOPPED)
6241 curjob = jp - jobtab + 1;
6243 status = jp->ps[jp->nprocs - 1].status;
6244 /* convert to 8 bits */
6245 if (WIFEXITED(status))
6246 st = WEXITSTATUS(status);
6248 else if (WIFSTOPPED(status))
6249 st = WSTOPSIG(status) + 128;
6252 st = WTERMSIG(status) + 128;
6256 * This is truly gross.
6257 * If we're doing job control, then we did a TIOCSPGRP which
6258 * caused us (the shell) to no longer be in the controlling
6259 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
6260 * intuit from the subprocess exit status whether a SIGINT
6261 * occured, and if so interrupt ourselves. Yuck. - mycroft
6263 if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
6267 if (! JOBS || jp->state == JOBDONE)
6276 * Wait for a process to terminate.
6286 struct procstat *sp;
6288 struct job *thisjob;
6294 TRACE(("dowait(%d) called\n", block));
6296 pid = waitproc(block, &status);
6297 TRACE(("wait returns %d, status=%d\n", pid, status));
6298 } while (!(block & 2) && pid == -1 && errno == EINTR);
6303 for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
6307 for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
6310 if (sp->pid == pid) {
6311 TRACE(("Changing status of proc %d from 0x%x to 0x%x\n", pid, sp->status, status));
6312 sp->status = status;
6315 if (sp->status == -1)
6317 else if (WIFSTOPPED(sp->status))
6320 if (stopped) { /* stopped or done */
6321 int state = done? JOBDONE : JOBSTOPPED;
6322 if (jp->state != state) {
6323 TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
6326 if (done && curjob == jp - jobtab + 1)
6327 curjob = 0; /* no current job */
6334 if (! rootshell || ! iflag || (job && thisjob == job)) {
6335 core = WCOREDUMP(status);
6337 if (WIFSTOPPED(status)) sig = WSTOPSIG(status);
6340 if (WIFEXITED(status)) sig = 0;
6341 else sig = WTERMSIG(status);
6343 if (sig != 0 && sig != SIGINT && sig != SIGPIPE) {
6345 outfmt(out2, "%d: ", pid);
6347 if (sig == SIGTSTP && rootshell && iflag)
6348 outfmt(out2, "%%%ld ",
6349 (long)(job - jobtab + 1));
6351 if (sig < NSIG && sys_siglist[sig])
6352 out2str(sys_siglist[sig]);
6354 outfmt(out2, "Signal %d", sig);
6356 out2str(" - core dumped");
6362 TRACE(("Not printing status: status=%d, sig=%d\n",
6366 TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell, job));
6368 thisjob->changed = 1;
6376 * Do a wait system call. If job control is compiled in, we accept
6377 * stopped processes. If block is zero, we return a value of zero
6378 * rather than blocking.
6380 * System V doesn't have a non-blocking wait system call. It does
6381 * have a SIGCLD signal that is sent to a process when one of it's
6382 * children dies. The obvious way to use SIGCLD would be to install
6383 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
6384 * was received, and have waitproc bump another counter when it got
6385 * the status of a process. Waitproc would then know that a wait
6386 * system call would not block if the two counters were different.
6387 * This approach doesn't work because if a process has children that
6388 * have not been waited for, System V will send it a SIGCLD when it
6389 * installs a signal handler for SIGCLD. What this means is that when
6390 * a child exits, the shell will be sent SIGCLD signals continuously
6391 * until is runs out of stack space, unless it does a wait call before
6392 * restoring the signal handler. The code below takes advantage of
6393 * this (mis)feature by installing a signal handler for SIGCLD and
6394 * then checking to see whether it was called. If there are any
6395 * children to be waited for, it will be.
6397 * If neither SYSV nor BSD is defined, we don't implement nonblocking
6398 * waits at all. In this case, the user will not be informed when
6399 * a background process until the next time she runs a real program
6400 * (as opposed to running a builtin command or just typing return),
6401 * and the jobs command may give out of date information.
6405 static int gotsigchild;
6407 static int onsigchild() {
6414 waitproc(block, status)
6428 return wait3(status, flags, (struct rusage *)NULL);
6435 save = signal(SIGCLD, onsigchild);
6436 signal(SIGCLD, save);
6437 if (gotsigchild == 0)
6440 return wait(status);
6444 return wait(status);
6450 * return 1 if there are stopped jobs, otherwise 0
6452 static int job_warning = 0;
6461 for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
6464 if (jp->state == JOBSTOPPED) {
6465 out2str("You have stopped jobs.\n");
6475 * Return a string identifying a command (to be printed by the
6479 static char *cmdnextc;
6480 static int cmdnleft;
6481 #define MAXCMDTEXT 200
6489 cmdnextc = name = ckmalloc(MAXCMDTEXT);
6490 cmdnleft = MAXCMDTEXT - 4;
6502 struct nodelist *lp;
6511 cmdtxt(n->nbinary.ch1);
6513 cmdtxt(n->nbinary.ch2);
6516 cmdtxt(n->nbinary.ch1);
6518 cmdtxt(n->nbinary.ch2);
6521 cmdtxt(n->nbinary.ch1);
6523 cmdtxt(n->nbinary.ch2);
6526 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
6534 cmdtxt(n->nredir.n);
6539 cmdtxt(n->nredir.n);
6543 cmdtxt(n->nif.test);
6545 cmdtxt(n->nif.ifpart);
6554 cmdtxt(n->nbinary.ch1);
6556 cmdtxt(n->nbinary.ch2);
6561 cmdputs(n->nfor.var);
6566 cmdputs(n->ncase.expr->narg.text);
6570 cmdputs(n->narg.text);
6574 for (np = n->ncmd.args ; np ; np = np->narg.next) {
6579 for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
6585 cmdputs(n->narg.text);
6588 p = ">"; i = 1; goto redir;
6590 p = ">>"; i = 1; goto redir;
6592 p = ">&"; i = 1; goto redir;
6594 p = ">|"; i = 1; goto redir;
6596 p = "<"; i = 0; goto redir;
6598 p = "<&"; i = 0; goto redir;
6600 p = "<>"; i = 0; goto redir;
6602 if (n->nfile.fd != i) {
6603 s[0] = n->nfile.fd + '0';
6608 if (n->type == NTOFD || n->type == NFROMFD) {
6609 s[0] = n->ndup.dupfd + '0';
6613 cmdtxt(n->nfile.fname);
6641 while ((c = *p++) != '\0') {
6644 else if (c == CTLVAR) {
6649 } else if (c == '=' && subtype != 0) {
6650 *q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL];
6652 } else if (c == CTLENDVAR) {
6654 } else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE)
6655 cmdnleft++; /* ignore it */
6658 if (--cmdnleft <= 0) {
6668 static void waitonint(int sig) {
6672 /* $NetBSD: mail.c,v 1.14 2000/07/03 03:26:19 matt Exp $ */
6675 * Routines to check for mail. (Perhaps make part of main.c?)
6679 #define MAXMBOXES 10
6682 static int nmboxes; /* number of mailboxes */
6683 static time_t mailtime[MAXMBOXES]; /* times of mailboxes */
6688 * Print appropriate message(s) if mail has arrived. If the argument is
6689 * nozero, then the value of MAIL has changed, so we just update the
6701 struct stackmark smark;
6708 setstackmark(&smark);
6709 mpath = mpathset()? mpathval() : mailval();
6710 for (i = 0 ; i < nmboxes ; i++) {
6711 p = padvance(&mpath, nullstr);
6716 for (q = p ; *q ; q++);
6721 q[-1] = '\0'; /* delete trailing '/' */
6722 #ifdef notdef /* this is what the System V shell claims to do (it lies) */
6723 if (stat(p, &statb) < 0)
6725 if (statb.st_mtime > mailtime[i] && ! silent) {
6728 pathopt? pathopt : "you have mail"
6731 mailtime[i] = statb.st_mtime;
6732 #else /* this is what it should do */
6733 if (stat(p, &statb) < 0)
6735 if (statb.st_size > mailtime[i] && ! silent) {
6738 pathopt? pathopt : "you have mail"
6741 mailtime[i] = statb.st_size;
6745 popstackmark(&smark);
6747 /* $NetBSD: main.c,v 1.40 2001/02/04 19:52:06 christos Exp $ */
6753 static int rootshell;
6755 short profile_buf[16384];
6759 static void read_profile __P((const char *));
6760 static char *find_dot_file __P((char *));
6761 int shell_main __P((int, char **));
6763 extern int oexitstatus;
6765 * Main routine. We initialize things, parse the arguments, execute
6766 * profiles if we're a login shell, and then call cmdloop to execute
6767 * commands. The setjmp call sets up the location to jump to when an
6768 * exception occurs. When an exception occurs the variable "state"
6769 * is used to figure out how far we had gotten.
6773 shell_main(argc, argv)
6777 struct jmploc jmploc;
6778 struct stackmark smark;
6782 DOTCMD = find_builtin(".");
6783 BLTINCMD = find_builtin("builtin");
6784 COMMANDCMD = find_builtin("command");
6785 EXECCMD = find_builtin("exec");
6786 EVALCMD = find_builtin("eval");
6789 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
6791 #if defined(linux) || defined(__GNU__)
6792 signal(SIGCHLD, SIG_DFL);
6795 if (setjmp(jmploc.loc)) {
6798 * When a shell procedure is executed, we raise the
6799 * exception EXSHELLPROC to clean up before executing
6800 * the shell procedure.
6802 switch (exception) {
6811 exitstatus = exerrno;
6822 if (exception != EXSHELLPROC) {
6823 if (state == 0 || iflag == 0 || ! rootshell)
6824 exitshell(exitstatus);
6827 if (exception == EXINT
6829 && (! attyset() || equal(termval(), "emacs"))
6837 popstackmark(&smark);
6838 FORCEINTON; /* enable interrupts */
6841 else if (state == 2)
6843 else if (state == 3)
6851 trputs("Shell args: "); trargs(argv);
6856 setstackmark(&smark);
6857 procargs(argc, argv);
6858 if (argv[0] && argv[0][0] == '-') {
6860 read_profile("/etc/profile");
6863 read_profile(".profile");
6868 if (getuid() == geteuid() && getgid() == getegid()) {
6870 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
6872 read_profile(shinit);
6879 if (sflag == 0 || minusc) {
6880 static int sigs[] = {
6881 SIGINT, SIGQUIT, SIGHUP,
6887 #define SIGSSIZE (sizeof(sigs)/sizeof(sigs[0]))
6890 for (i = 0; i < SIGSSIZE; i++)
6895 evalstring(minusc, 0);
6897 if (sflag || minusc == NULL) {
6898 state4: /* XXX ??? - why isn't this before the "if" statement */
6904 exitshell(exitstatus);
6910 * Read and execute commands. "Top" is nonzero for the top level command
6911 * loop; it turns on prompting if the shell is interactive.
6919 struct stackmark smark;
6923 TRACE(("cmdloop(%d) called\n", top));
6924 setstackmark(&smark);
6935 n = parsecmd(inter);
6936 /* showtree(n); DEBUG */
6938 if (!top || numeof >= 50)
6940 if (!stoppedjobs()) {
6943 out2str("\nUse \"exit\" to leave shell.\n");
6946 } else if (n != NULL && nflag == 0) {
6947 job_warning = (job_warning == 2) ? 1 : 0;
6951 popstackmark(&smark);
6952 setstackmark(&smark);
6953 if (evalskip == SKIPFILE) {
6958 popstackmark(&smark);
6964 * Read /etc/profile or .profile. Return on error.
6976 if ((fd = open(name, O_RDONLY)) >= 0)
6981 /* -q turns off -x and -v just when executing init files */
6984 xflag = 0, xflag_set = 1;
6986 vflag = 0, vflag_set = 1;
7001 * Read a file containing shell functions.
7011 if ((fd = open(name, O_RDONLY)) >= 0)
7014 error("Can't open %s", name);
7023 * Take commands from a file. To be compatable we should do a path
7024 * search for the file, which is necessary to find sub-commands.
7029 find_dot_file(mybasename)
7033 const char *path = pathval();
7036 /* don't try this for absolute or relative paths */
7037 if (strchr(mybasename, '/'))
7040 while ((fullname = padvance(&path, mybasename)) != NULL) {
7041 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
7043 * Don't bother freeing here, since it will
7044 * be freed by the caller.
7048 stunalloc(fullname);
7051 /* not found in the PATH */
7052 error("%s: not found", mybasename);
7064 for (sp = cmdenviron; sp ; sp = sp->next)
7065 setvareq(savestr(sp->text), VSTRFIXED|VTEXTFIXED);
7067 if (argc >= 2) { /* That's what SVR2 does */
7069 struct stackmark smark;
7071 setstackmark(&smark);
7072 fullname = find_dot_file(argv[1]);
7073 setinputfile(fullname, 1);
7074 commandname = fullname;
7077 popstackmark(&smark);
7091 exitstatus = number(argv[1]);
7093 exitstatus = oexitstatus;
7094 exitshell(exitstatus);
7097 /* $NetBSD: memalloc.c,v 1.23 2000/11/01 19:56:01 christos Exp $ */
7100 * Parse trees for commands are allocated in lifo order, so we use a stack
7101 * to make this more efficient, and also to avoid all sorts of exception
7102 * handling code to handle interrupts in the middle of a parse.
7104 * The size 504 was chosen because the Ultrix malloc handles that size
7108 #define MINSIZE 504 /* minimum size of a block */
7111 struct stack_block {
7112 struct stack_block *prev;
7113 char space[MINSIZE];
7116 struct stack_block stackbase;
7117 struct stack_block *stackp = &stackbase;
7118 struct stackmark *markp;
7119 static char *stacknxt = stackbase.space;
7120 static int stacknleft = MINSIZE;
7121 static int sstrnleft;
7122 static int herefd = -1;
7132 nbytes = ALIGN(nbytes);
7133 if (nbytes > stacknleft) {
7135 struct stack_block *sp;
7138 if (blocksize < MINSIZE)
7139 blocksize = MINSIZE;
7141 sp = ckmalloc(sizeof(struct stack_block) - MINSIZE + blocksize);
7143 stacknxt = sp->space;
7144 stacknleft = blocksize;
7150 stacknleft -= nbytes;
7160 if (p == NULL) { /*DEBUG */
7161 write(2, "stunalloc\n", 10);
7165 if (!(stacknxt >= (char *)p && (char *)p >= stackp->space)) {
7168 stacknleft += stacknxt - (char *)p;
7176 struct stackmark *mark;
7178 mark->stackp = stackp;
7179 mark->stacknxt = stacknxt;
7180 mark->stacknleft = stacknleft;
7181 mark->marknext = markp;
7188 struct stackmark *mark;
7190 struct stack_block *sp;
7193 markp = mark->marknext;
7194 while (stackp != mark->stackp) {
7199 stacknxt = mark->stacknxt;
7200 stacknleft = mark->stacknleft;
7206 * When the parser reads in a string, it wants to stick the string on the
7207 * stack and only adjust the stack pointer when it knows how big the
7208 * string is. Stackblock (defined in stack.h) returns a pointer to a block
7209 * of space on top of the stack and stackblocklen returns the length of
7210 * this block. Growstackblock will grow this space by at least one byte,
7211 * possibly moving it (like realloc). Grabstackblock actually allocates the
7212 * part of the block that has been used.
7218 int newlen = ALIGN(stacknleft * 2 + 100);
7219 char *oldspace = stacknxt;
7220 int oldlen = stacknleft;
7221 struct stack_block *sp;
7222 struct stack_block *oldstackp;
7224 if (stacknxt == stackp->space && stackp != &stackbase) {
7229 sp = ckrealloc((pointer)sp, sizeof(struct stack_block) - MINSIZE + newlen);
7232 stacknxt = sp->space;
7233 stacknleft = newlen;
7235 /* Stack marks pointing to the start of the old block
7236 * must be relocated to point to the new block
7238 struct stackmark *xmark;
7240 while (xmark != NULL && xmark->stackp == oldstackp) {
7241 xmark->stackp = stackp;
7242 xmark->stacknxt = stacknxt;
7243 xmark->stacknleft = stacknleft;
7244 xmark = xmark->marknext;
7249 p = stalloc(newlen);
7250 memcpy(p, oldspace, oldlen);
7251 stacknxt = p; /* free the space */
7252 stacknleft += newlen; /* we just allocated */
7270 * The following routines are somewhat easier to use that the above.
7271 * The user declares a variable of type STACKSTR, which may be declared
7272 * to be a register. The macro STARTSTACKSTR initializes things. Then
7273 * the user uses the macro STPUTC to add characters to the string. In
7274 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
7275 * grown as necessary. When the user is done, she can just leave the
7276 * string there and refer to it using stackblock(). Or she can allocate
7277 * the space for it using grabstackstr(). If it is necessary to allow
7278 * someone else to use the stack temporarily and then continue to grow
7279 * the string, the user should use grabstack to allocate the space, and
7280 * then call ungrabstr(p) to return to the previous mode of operation.
7282 * USTPUTC is like STPUTC except that it doesn't check for overflow.
7283 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
7284 * is space for at least one character.
7290 int len = stackblocksize();
7291 if (herefd >= 0 && len >= 1024) {
7292 xwrite(herefd, stackblock(), len);
7293 sstrnleft = len - 1;
7294 return stackblock();
7297 sstrnleft = stackblocksize() - len - 1;
7298 return stackblock() + len;
7303 * Called from CHECKSTRSPACE.
7307 makestrspace(size_t newlen) {
7308 int len = stackblocksize() - sstrnleft;
7311 sstrnleft = stackblocksize() - len;
7312 } while (sstrnleft < newlen);
7313 return stackblock() + len;
7319 ungrabstackstr(s, p)
7323 stacknleft += stacknxt - s;
7325 sstrnleft = stacknleft - (p - s);
7327 /* $NetBSD: miscbltin.c,v 1.30 2001/02/04 19:52:06 christos Exp $ */
7330 * Miscelaneous builtins.
7337 mode_t getmode(const void *, mode_t);
7338 static void *setmode(const char *);
7340 #if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
7341 typedef enum __rlimit_resource rlim_t;
7348 * The read builtin. The -e option causes backslashes to escape the
7349 * following character.
7351 * This uses unbuffered input, which may be avoidable in some cases.
7372 while ((i = nextopt("p:r")) != '\0') {
7378 if (prompt && isatty(0)) {
7382 if (*(ap = argptr) == NULL)
7384 if ((ifs = bltinlookup("IFS")) == NULL)
7391 if (read(0, &c, 1) != 1) {
7403 if (!rflag && c == '\\') {
7409 if (startword && *ifs == ' ' && strchr(ifs, c)) {
7413 if (backslash && c == '\\') {
7414 if (read(0, &c, 1) != 1) {
7419 } else if (ap[1] != NULL && strchr(ifs, c) != NULL) {
7421 setvar(*ap, stackblock(), 0);
7430 /* Remove trailing blanks */
7431 while (stackblock() <= --p && strchr(ifs, *p) != NULL)
7433 setvar(*ap, stackblock(), 0);
7434 while (*++ap != NULL)
7435 setvar(*ap, nullstr, 0);
7442 umaskcmd(argc, argv)
7449 int symbolic_mode = 0;
7451 while ((i = nextopt("S")) != '\0') {
7460 if ((ap = *argptr) == NULL) {
7461 if (symbolic_mode) {
7462 char u[4], g[4], o[4];
7465 if ((mask & S_IRUSR) == 0)
7467 if ((mask & S_IWUSR) == 0)
7469 if ((mask & S_IXUSR) == 0)
7474 if ((mask & S_IRGRP) == 0)
7476 if ((mask & S_IWGRP) == 0)
7478 if ((mask & S_IXGRP) == 0)
7483 if ((mask & S_IROTH) == 0)
7485 if ((mask & S_IWOTH) == 0)
7487 if ((mask & S_IXOTH) == 0)
7491 out1fmt("u=%s,g=%s,o=%s\n", u, g, o);
7493 out1fmt("%.4o\n", mask);
7496 if (isdigit((unsigned char)*ap)) {
7499 if (*ap >= '8' || *ap < '0')
7500 error("Illegal number: %s", argv[1]);
7501 mask = (mask << 3) + (*ap - '0');
7502 } while (*++ap != '\0');
7508 if ((set = setmode(ap)) != 0) {
7509 mask = getmode(set, ~mask & 0777);
7514 error("Illegal mode: %s", ap);
7516 umask(~mask & 0777);
7525 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
7526 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
7527 * ash by J.T. Conklin.
7535 int factor; /* multiply by to get rlim_{cur,max} values */
7539 static const struct limits limits[] = {
7541 { "time(seconds)", RLIMIT_CPU, 1, 't' },
7544 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
7547 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
7550 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
7553 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
7556 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
7558 #ifdef RLIMIT_MEMLOCK
7559 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
7562 { "process(processes)", RLIMIT_NPROC, 1, 'p' },
7564 #ifdef RLIMIT_NOFILE
7565 { "nofiles(descriptors)", RLIMIT_NOFILE, 1, 'n' },
7568 { "vmemory(kbytes)", RLIMIT_VMEM, 1024, 'v' },
7571 { "swap(kbytes)", RLIMIT_SWAP, 1024, 'w' },
7573 { (char *) 0, 0, 0, '\0' }
7577 ulimitcmd(argc, argv)
7583 enum { SOFT = 0x1, HARD = 0x2 }
7585 const struct limits *l;
7588 struct rlimit limit;
7591 while ((optc = nextopt("HSatfdsmcnpl")) != '\0')
7606 for (l = limits; l->name && l->option != what; l++)
7609 error("internal error (%c)", what);
7611 set = *argptr ? 1 : 0;
7615 if (all || argptr[1])
7616 error("too many arguments");
7617 if (strcmp(p, "unlimited") == 0)
7618 val = RLIM_INFINITY;
7622 while ((c = *p++) >= '0' && c <= '9')
7624 val = (val * 10) + (long)(c - '0');
7625 if (val < (rlim_t) 0)
7629 error("bad number");
7634 for (l = limits; l->name; l++) {
7635 getrlimit(l->cmd, &limit);
7637 val = limit.rlim_cur;
7638 else if (how & HARD)
7639 val = limit.rlim_max;
7641 out1fmt("%-20s ", l->name);
7642 if (val == RLIM_INFINITY)
7643 out1fmt("unlimited\n");
7648 out1fmt("%lld\n", (long long) val);
7650 out1fmt("%ld\n", (long) val);
7657 getrlimit(l->cmd, &limit);
7660 limit.rlim_max = val;
7662 limit.rlim_cur = val;
7663 if (setrlimit(l->cmd, &limit) < 0)
7664 error("error setting limit (%s)", strerror(errno));
7667 val = limit.rlim_cur;
7668 else if (how & HARD)
7669 val = limit.rlim_max;
7671 if (val == RLIM_INFINITY)
7672 out1fmt("unlimited\n");
7677 out1fmt("%lld\n", (long long) val);
7679 out1fmt("%ld\n", (long) val);
7685 /* $NetBSD: mystring.c,v 1.14 1999/07/09 03:05:50 christos Exp $ */
7690 * equal(s1, s2) Return true if strings are equal.
7691 * scopy(from, to) Copy a string.
7692 * scopyn(from, to, n) Like scopy, but checks for overflow.
7693 * number(s) Convert a string of digits to an integer.
7694 * is_number(s) Return true if s is a string of digits.
7697 static char nullstr[1]; /* zero length string */
7698 static const char spcstr[] = " ";
7699 static const char snlfmt[] = "%s\n";
7702 * equal - #defined in mystring.h
7706 * scopy - #defined in mystring.h
7712 * scopyn - copy a string from "from" to "to", truncating the string
7713 * if necessary. "To" is always nul terminated, even if
7714 * truncation is performed. "Size" is the size of "to".
7718 scopyn(from, to, size)
7724 while (--size > 0) {
7725 if ((*to++ = *from++) == '\0')
7734 * prefix -- see if pfx is a prefix of string.
7743 if (*pfx++ != *string++)
7751 * Convert a string of digits to an integer, printing an error message on
7761 error("Illegal number: %s", s);
7768 * Check for a valid number. This should be elsewhere.
7778 } while (*++p != '\0');
7784 * Produce a possibly single quoted string suitable as input to the shell.
7785 * The return string is allocated on the stack.
7789 single_quote(const char *s) {
7796 size_t len1, len1p, len2, len2p;
7798 len1 = strcspn(s, "'");
7799 len2 = strspn(s + len1, "'");
7801 len1p = len1 ? len1 + 2 : len1;
7813 CHECKSTRSPACE(len1p + len2p + 1, p);
7818 q = mempcpy(p + 1, s, len1);
7821 memcpy(p + 1, s, len1);
7838 *(char *) mempcpy(q + 1, s, len2) = '"';
7841 memcpy(q + 1, s, len2);
7847 STADJUST(len1p + len2p, p);
7852 return grabstackstr(p);
7856 * Like strdup but works with the ash stack.
7860 sstrdup(const char *p)
7862 size_t len = strlen(p) + 1;
7863 return memcpy(stalloc(len), p, len);
7867 * Wrapper around strcmp for qsort/bsearch/...
7870 pstrcmp(const void *a, const void *b)
7872 return strcmp(*(const char *const *) a, *(const char *const *) b);
7876 * Find a string is in a sorted array.
7878 static const char *const *
7879 findstring(const char *s, const char *const *array, size_t nmemb)
7881 return bsearch(&s, array, nmemb, sizeof(const char *), pstrcmp);
7884 * This file was generated by the mknodes program.
7887 /* $NetBSD: nodes.c.pat,v 1.8 1997/04/11 23:03:09 christos Exp $ */
7890 * Routine for dealing with parsed shell commands.
7894 static int funcblocksize; /* size of structures in function */
7895 static int funcstringsize; /* size of strings in node */
7896 pointer funcblock; /* block to allocate function from */
7897 static char *funcstring; /* block to allocate strings from */
7899 static const short nodesize[26] = {
7900 ALIGN(sizeof (struct nbinary)),
7901 ALIGN(sizeof (struct ncmd)),
7902 ALIGN(sizeof (struct npipe)),
7903 ALIGN(sizeof (struct nredir)),
7904 ALIGN(sizeof (struct nredir)),
7905 ALIGN(sizeof (struct nredir)),
7906 ALIGN(sizeof (struct nbinary)),
7907 ALIGN(sizeof (struct nbinary)),
7908 ALIGN(sizeof (struct nif)),
7909 ALIGN(sizeof (struct nbinary)),
7910 ALIGN(sizeof (struct nbinary)),
7911 ALIGN(sizeof (struct nfor)),
7912 ALIGN(sizeof (struct ncase)),
7913 ALIGN(sizeof (struct nclist)),
7914 ALIGN(sizeof (struct narg)),
7915 ALIGN(sizeof (struct narg)),
7916 ALIGN(sizeof (struct nfile)),
7917 ALIGN(sizeof (struct nfile)),
7918 ALIGN(sizeof (struct nfile)),
7919 ALIGN(sizeof (struct nfile)),
7920 ALIGN(sizeof (struct nfile)),
7921 ALIGN(sizeof (struct ndup)),
7922 ALIGN(sizeof (struct ndup)),
7923 ALIGN(sizeof (struct nhere)),
7924 ALIGN(sizeof (struct nhere)),
7925 ALIGN(sizeof (struct nnot)),
7929 static void calcsize __P((union node *));
7930 static void sizenodelist __P((struct nodelist *));
7931 static union node *copynode __P((union node *));
7932 static struct nodelist *copynodelist __P((struct nodelist *));
7933 static char *nodesavestr __P((char *));
7938 * Make a copy of a parse tree.
7950 funcblock = ckmalloc(funcblocksize + funcstringsize);
7951 funcstring = (char *) funcblock + funcblocksize;
7963 funcblocksize += nodesize[n->type];
7970 calcsize(n->nbinary.ch2);
7971 calcsize(n->nbinary.ch1);
7974 calcsize(n->ncmd.redirect);
7975 calcsize(n->ncmd.args);
7976 calcsize(n->ncmd.assign);
7979 sizenodelist(n->npipe.cmdlist);
7984 calcsize(n->nredir.redirect);
7985 calcsize(n->nredir.n);
7988 calcsize(n->nif.elsepart);
7989 calcsize(n->nif.ifpart);
7990 calcsize(n->nif.test);
7993 funcstringsize += strlen(n->nfor.var) + 1;
7994 calcsize(n->nfor.body);
7995 calcsize(n->nfor.args);
7998 calcsize(n->ncase.cases);
7999 calcsize(n->ncase.expr);
8002 calcsize(n->nclist.body);
8003 calcsize(n->nclist.pattern);
8004 calcsize(n->nclist.next);
8008 sizenodelist(n->narg.backquote);
8009 funcstringsize += strlen(n->narg.text) + 1;
8010 calcsize(n->narg.next);
8017 calcsize(n->nfile.fname);
8018 calcsize(n->nfile.next);
8022 calcsize(n->ndup.vname);
8023 calcsize(n->ndup.next);
8027 calcsize(n->nhere.doc);
8028 calcsize(n->nhere.next);
8031 calcsize(n->nnot.com);
8040 struct nodelist *lp;
8043 funcblocksize += ALIGN(sizeof(struct nodelist));
8060 funcblock = (char *) funcblock + nodesize[n->type];
8067 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8068 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8071 new->ncmd.redirect = copynode(n->ncmd.redirect);
8072 new->ncmd.args = copynode(n->ncmd.args);
8073 new->ncmd.assign = copynode(n->ncmd.assign);
8074 new->ncmd.backgnd = n->ncmd.backgnd;
8077 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8078 new->npipe.backgnd = n->npipe.backgnd;
8083 new->nredir.redirect = copynode(n->nredir.redirect);
8084 new->nredir.n = copynode(n->nredir.n);
8087 new->nif.elsepart = copynode(n->nif.elsepart);
8088 new->nif.ifpart = copynode(n->nif.ifpart);
8089 new->nif.test = copynode(n->nif.test);
8092 new->nfor.var = nodesavestr(n->nfor.var);
8093 new->nfor.body = copynode(n->nfor.body);
8094 new->nfor.args = copynode(n->nfor.args);
8097 new->ncase.cases = copynode(n->ncase.cases);
8098 new->ncase.expr = copynode(n->ncase.expr);
8101 new->nclist.body = copynode(n->nclist.body);
8102 new->nclist.pattern = copynode(n->nclist.pattern);
8103 new->nclist.next = copynode(n->nclist.next);
8107 new->narg.backquote = copynodelist(n->narg.backquote);
8108 new->narg.text = nodesavestr(n->narg.text);
8109 new->narg.next = copynode(n->narg.next);
8116 new->nfile.fname = copynode(n->nfile.fname);
8117 new->nfile.fd = n->nfile.fd;
8118 new->nfile.next = copynode(n->nfile.next);
8122 new->ndup.vname = copynode(n->ndup.vname);
8123 new->ndup.dupfd = n->ndup.dupfd;
8124 new->ndup.fd = n->ndup.fd;
8125 new->ndup.next = copynode(n->ndup.next);
8129 new->nhere.doc = copynode(n->nhere.doc);
8130 new->nhere.fd = n->nhere.fd;
8131 new->nhere.next = copynode(n->nhere.next);
8134 new->nnot.com = copynode(n->nnot.com);
8137 new->type = n->type;
8142 static struct nodelist *
8144 struct nodelist *lp;
8146 struct nodelist *start;
8147 struct nodelist **lpp;
8152 funcblock = (char *) funcblock + ALIGN(sizeof(struct nodelist));
8153 (*lpp)->n = copynode(lp->n);
8155 lpp = &(*lpp)->next;
8168 char *rtn = funcstring;
8170 funcstring = stpcpy(funcstring, s) + 1;
8173 register char *p = s;
8174 register char *q = funcstring;
8175 char *rtn = funcstring;
8177 while ((*q++ = *p++) != '\0')
8187 * Free a parse tree.
8197 /* $NetBSD: options.c,v 1.31 2001/02/26 13:06:43 wiz Exp $ */
8200 struct optent optlist[NOPTS] = {
8201 { "errexit", 'e', 0 },
8202 { "noglob", 'f', 0 },
8203 { "ignoreeof", 'I', 0 },
8204 { "interactive",'i', 0 },
8205 { "monitor", 'm', 0 },
8206 { "noexec", 'n', 0 },
8207 { "stdin", 's', 0 },
8208 { "xtrace", 'x', 0 },
8209 { "verbose", 'v', 0 },
8211 { "emacs", 'E', 0 },
8212 { "noclobber", 'C', 0 },
8213 { "allexport", 'a', 0 },
8214 { "notify", 'b', 0 },
8215 { "nounset", 'u', 0 },
8216 { "quietprofile", 'q', 0 },
8218 static char *arg0; /* value of $0 */
8219 struct shparam shellparam; /* current positional parameters */
8220 static char **argptr; /* argument list for builtin commands */
8221 static char *optionarg; /* set by nextopt (like getopt) */
8222 static char *optptr; /* used by nextopt */
8224 static char *minusc; /* argument to -c option */
8227 static void options __P((int));
8228 static void minus_o __P((char *, int));
8229 static void setoption __P((int, int));
8231 static int getopts __P((char *, char *, char **, int *, int *));
8236 * Process the shell command line arguments.
8240 procargs(argc, argv)
8249 for (i = 0; i < NOPTS; i++)
8252 if (*argptr == NULL && minusc == NULL)
8254 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8258 for (i = 0; i < NOPTS; i++)
8259 if (optlist[i].val == 2)
8262 if (sflag == 0 && minusc == NULL) {
8263 commandname = argv[0];
8265 setinputfile(arg0, 0);
8268 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8269 if (argptr && minusc && *argptr)
8272 shellparam.p = argptr;
8273 shellparam.optind = 1;
8274 shellparam.optoff = -1;
8275 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
8277 shellparam.nparam++;
8287 setinteractive(iflag);
8292 * Process shell options. The global variable argptr contains a pointer
8293 * to the argument list; we advance it past the options.
8306 while ((p = *argptr) != NULL) {
8308 if ((c = *p++) == '-') {
8310 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8312 /* "-" means turn off -x and -v */
8315 /* "--" means reset params */
8316 else if (*argptr == NULL)
8319 break; /* "-" or "--" terminates options */
8321 } else if (c == '+') {
8327 while ((c = *p++) != '\0') {
8328 if (c == 'c' && cmdline) {
8330 #ifdef NOHACK /* removing this code allows sh -ce 'foo' for compat */
8334 if (q == NULL || minusc != NULL)
8335 error("Bad -c option");
8340 } else if (c == 'o') {
8341 minus_o(*argptr, val);
8359 out1str("Current option settings\n");
8360 for (i = 0; i < NOPTS; i++)
8361 out1fmt("%-16s%s\n", optlist[i].name,
8362 optlist[i].val ? "on" : "off");
8364 for (i = 0; i < NOPTS; i++)
8365 if (equal(name, optlist[i].name)) {
8366 setoption(optlist[i].letter, val);
8369 error("Illegal option -o %s", name);
8375 setoption(flag, val)
8381 for (i = 0; i < NOPTS; i++)
8382 if (optlist[i].letter == flag) {
8383 optlist[i].val = val;
8385 /* #%$ hack for ksh semantics */
8388 else if (flag == 'E')
8393 error("Illegal option -%c", flag);
8403 for (i = 0; i < NOPTS; i++)
8412 * Set the shell parameters.
8423 for (nparam = 0 ; argv[nparam] ; nparam++);
8424 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
8426 *ap++ = savestr(*argv++);
8429 freeparam(&shellparam);
8430 shellparam.malloc = 1;
8431 shellparam.nparam = nparam;
8432 shellparam.p = newparam;
8433 shellparam.optind = 1;
8434 shellparam.optoff = -1;
8439 * Free the list of positional parameters.
8444 volatile struct shparam *param;
8448 if (param->malloc) {
8449 for (ap = param->p ; *ap ; ap++)
8458 * The shift builtin command.
8462 shiftcmd(argc, argv)
8471 n = number(argv[1]);
8472 if (n > shellparam.nparam)
8473 error("can't shift that many");
8475 shellparam.nparam -= n;
8476 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
8477 if (shellparam.malloc)
8481 while ((*ap2++ = *ap1++) != NULL);
8482 shellparam.optind = 1;
8483 shellparam.optoff = -1;
8491 * The set command builtin.
8500 return showvarscmd(argc, argv);
8504 if (*argptr != NULL) {
8516 shellparam.optind = number(value);
8517 shellparam.optoff = -1;
8522 * The getopts builtin. Shellparam.optnext points to the next argument
8523 * to be processed. Shellparam.optptr points to the next character to
8524 * be processed in the current argument. If shellparam.optnext is NULL,
8525 * then it's the first time getopts has been called.
8529 getoptscmd(argc, argv)
8536 error("Usage: getopts optstring var [arg]");
8537 else if (argc == 3) {
8538 optbase = shellparam.p;
8539 if (shellparam.optind > shellparam.nparam + 1) {
8540 shellparam.optind = 1;
8541 shellparam.optoff = -1;
8546 if (shellparam.optind > argc - 2) {
8547 shellparam.optind = 1;
8548 shellparam.optoff = -1;
8552 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
8553 &shellparam.optoff);
8557 * Safe version of setvar, returns 1 on success 0 on failure.
8561 setvarsafe(name, val, flags)
8562 const char *name, *val;
8565 struct jmploc jmploc;
8566 struct jmploc *volatile savehandler = handler;
8572 if (setjmp(jmploc.loc))
8576 setvar(name, val, flags);
8578 handler = savehandler;
8583 getopts(optstr, optvar, optfirst, myoptind, optoff)
8595 char **optnext = optfirst + *myoptind - 1;
8597 if (*myoptind <= 1 || *optoff < 0 || !(*(optnext - 1)) ||
8598 strlen(*(optnext - 1)) < *optoff)
8601 p = *(optnext - 1) + *optoff;
8602 if (p == NULL || *p == '\0') {
8603 /* Current word is done, advance */
8604 if (optnext == NULL)
8607 if (p == NULL || *p != '-' || *++p == '\0') {
8609 *myoptind = optnext - optfirst + 1;
8615 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
8620 for (q = optstr; *q != c; ) {
8622 if (optstr[0] == ':') {
8625 err |= setvarsafe("OPTARG", s, 0);
8628 outfmt(&errout, "Illegal option -%c\n", c);
8629 (void) unsetvar("OPTARG");
8639 if (*p == '\0' && (p = *optnext) == NULL) {
8640 if (optstr[0] == ':') {
8643 err |= setvarsafe("OPTARG", s, 0);
8647 outfmt(&errout, "No arg for -%c option\n", c);
8648 (void) unsetvar("OPTARG");
8656 setvarsafe("OPTARG", p, 0);
8660 setvarsafe("OPTARG", "", 0);
8661 *myoptind = optnext - optfirst + 1;
8668 *optoff = p ? p - *(optnext - 1) : -1;
8669 fmtstr(s, sizeof(s), "%d", *myoptind);
8670 err |= setvarsafe("OPTIND", s, VNOFUNC);
8673 err |= setvarsafe(optvar, s, 0);
8685 * XXX - should get rid of. have all builtins use getopt(3). the
8686 * library getopt must have the BSD extension static variable "optreset"
8687 * otherwise it can't be used within the shell safely.
8689 * Standard option processing (a la getopt) for builtin routines. The
8690 * only argument that is passed to nextopt is the option string; the
8691 * other arguments are unnecessary. It return the character, or '\0' on
8697 const char *optstring;
8703 if ((p = optptr) == NULL || *p == '\0') {
8705 if (p == NULL || *p != '-' || *++p == '\0')
8708 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
8712 for (q = optstring ; *q != c ; ) {
8714 error("Illegal option -%c", c);
8719 if (*p == '\0' && (p = *argptr++) == NULL)
8720 error("No arg for -%c option", c);
8729 /* $NetBSD: output.c,v 1.23 2001/01/07 23:39:07 lukem Exp $ */
8732 * Shell output routines. We use our own output routines because:
8733 * When a builtin command is interrupted we have to discard
8734 * any pending output.
8735 * When a builtin command appears in back quotes, we want to
8736 * save the output of the command in a region obtained
8737 * via malloc, rather than doing a fork and reading the
8738 * output of the command via a pipe.
8739 * Our output routines may be smaller than the stdio routines.
8743 #define OUTBUFSIZ BUFSIZ
8744 #define MEM_OUT -3 /* output to dynamically allocated memory */
8747 #ifdef USE_GLIBC_STDIO
8748 struct output output = {NULL, NULL, 0, NULL, 0, 1, 0};
8749 struct output errout = {NULL, NULL, 0, NULL, 0, 2, 0};
8750 struct output memout = {NULL, NULL, 0, NULL, 0, MEM_OUT, 0};
8752 struct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0};
8753 struct output errout = {NULL, 0, NULL, 0, 2, 0};
8754 struct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0};
8756 struct output *out1 = &output;
8757 struct output *out2 = &errout;
8760 #ifndef USE_GLIBC_STDIO
8761 static void __outstr __P((const char *, size_t, struct output*));
8768 INCLUDE "memalloc.h"
8771 #ifdef USE_GLIBC_STDIO
8779 #ifdef USE_GLIBC_STDIO
8780 if (memout.stream != NULL)
8783 if (memout.buf != NULL) {
8792 #ifndef USE_GLIBC_STDIO
8794 __outstr(const char *p, size_t len, struct output *dest) {
8795 if (!dest->bufsize) {
8797 } else if (dest->buf == NULL) {
8798 if (len > dest->bufsize && dest->fd == MEM_OUT) {
8799 dest->bufsize = len;
8802 dest->buf = ckmalloc(dest->bufsize);
8803 dest->nextc = dest->buf;
8804 dest->nleft = dest->bufsize;
8806 } else if (dest->fd == MEM_OUT) {
8809 offset = dest->bufsize;
8811 if (dest->bufsize >= len) {
8812 dest->bufsize <<= 1;
8814 dest->bufsize += len;
8816 dest->buf = ckrealloc(dest->buf, dest->bufsize);
8817 dest->nleft = dest->bufsize - offset;
8818 dest->nextc = dest->buf + offset;
8824 if (len < dest->nleft) {
8826 memcpy(dest->nextc, p, len);
8831 if (xwrite(dest->fd, p, len) < len)
8832 dest->flags |= OUTPUT_ERR;
8840 struct output *file;
8842 #ifdef USE_GLIBC_STDIO
8844 fputs(p, file->stream);
8853 if ((file->nleft -= len) > 0) {
8854 memcpy(file->nextc, p, len);
8858 __outstr(p, len, file);
8863 #ifndef USE_GLIBC_STDIO
8869 struct output *dest;
8871 __outstr(&c, 1, dest);
8887 struct output *dest;
8889 #ifdef USE_GLIBC_STDIO
8891 fflush(dest->stream);
8896 len = dest->nextc - dest->buf;
8897 if (dest->buf == NULL || !len || dest->fd < 0)
8899 dest->nextc = dest->buf;
8900 dest->nleft = dest->bufsize;
8901 if (xwrite(dest->fd, dest->buf, len) < len)
8902 dest->flags |= OUTPUT_ERR;
8922 outfmt(struct output *file, const char *fmt, ...)
8931 struct output *file;
8935 file = va_arg(ap, struct output *);
8936 fmt = va_arg(ap, const char *);
8940 doformat(file, fmt, ap);
8947 out1fmt(const char *fmt, ...)
8958 fmt = va_arg(ap, const char *);
8962 doformat(out1, fmt, ap);
8968 fmtstr(char *outbuf, size_t length, const char *fmt, ...)
8981 outbuf = va_arg(ap, char *);
8982 length = va_arg(ap, size_t);
8983 fmt = va_arg(ap, const char *);
8988 vsnprintf(outbuf, length, fmt, ap);
8992 #ifndef USE_GLIBC_STDIO
8994 * Formatted output. This routine handles a subset of the printf formats:
8995 * - Formats supported: d, u, o, p, X, s, and c.
8996 * - The x format is also accepted but is treated like X.
8997 * - The l, ll and q modifiers are accepted.
8998 * - The - and # flags are accepted; # only works with the o format.
8999 * - Width and precision may be specified with any format except c.
9000 * - An * may be given for the width or precision.
9001 * - The obsolete practice of preceding the width with a zero to get
9002 * zero padding is not supported; use the precision field.
9003 * - A % may be printed by writing %% in the format string.
9009 #define HAVE_VASPRINTF 1
9013 static const char digit[] = "0123456789ABCDEF";
9018 doformat(dest, f, ap)
9019 struct output *dest;
9020 const char *f; /* format string */
9028 len = vasprintf(&t, f, ap);
9038 #else /* !HAVE_VASPRINTF */
9040 char temp[TEMPSIZE];
9061 while ((c = *f++) != '\0') {
9082 width = va_arg(ap, int);
9085 while (is_digit(*f)) {
9086 width = 10 * width + digit_val(*f++);
9091 prec = va_arg(ap, int);
9095 while (is_digit(*f)) {
9096 prec = 10 * prec + digit_val(*f++);
9107 } else if (*f == 'q') {
9115 l = va_arg(ap, quad_t);
9119 l = va_arg(ap, long);
9121 l = va_arg(ap, int);
9141 /* we don't implement 'x'; treat like 'X' */
9144 uns_number: /* an unsigned number */
9148 num = va_arg(ap, u_quad_t);
9152 num = va_arg(ap, unsigned long);
9154 num = va_arg(ap, unsigned int);
9155 number: /* process a number */
9156 p = temp + TEMPSIZE - 1;
9159 *--p = digit[num % base];
9162 len = (temp + TEMPSIZE - 1) - p;
9165 if (sharp && *f == 'o' && prec <= len)
9174 if (flushleft == 0) {
9190 p = va_arg(ap, char *);
9194 if (prec >= 0 && len > prec)
9197 if (flushleft == 0) {
9203 while (--prec != 0 && *p)
9209 c = va_arg(ap, int);
9218 #endif /* !HAVE_VASPRINTF */
9225 * Version of write which resumes after a signal is caught.
9229 xwrite(fd, buf, nbytes)
9241 i = write(fd, buf, n);
9247 } else if (i == 0) {
9250 } else if (errno != EINTR) {
9259 * Version of ioctl that retries after a signal is caught.
9260 * XXX unused function
9264 xioctl(fd, request, arg)
9266 unsigned long request;
9271 while ((i = ioctl(fd, request, arg)) == -1 && errno == EINTR);
9277 #ifdef USE_GLIBC_STDIO
9278 static void initstreams() {
9279 output.stream = stdout;
9280 errout.stream = stderr;
9287 memout.stream = open_memstream(&memout.buf, &memout.bufsize);
9295 error = fclose(memout.stream);
9296 memout.stream = NULL;
9300 /* $NetBSD: parser.c,v 1.46 2001/02/04 19:52:06 christos Exp $ */
9303 * Shell command parser.
9306 #define EOFMARKLEN 79
9311 struct heredoc *next; /* next here document in list */
9312 union node *here; /* redirection node */
9313 char *eofmark; /* string indicating end of input */
9314 int striptabs; /* if set, strip leading tabs */
9319 struct heredoc *heredoclist; /* list of here documents to read */
9320 static int parsebackquote; /* nonzero if we are inside backquotes */
9321 static int doprompt; /* if set, prompt the user */
9322 static int needprompt; /* true if interactive and at start of line */
9323 static int lasttoken; /* last token read */
9324 static int tokpushback; /* last token pushed back */
9325 static char *wordtext; /* text of last word returned by readtoken */
9326 static int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */
9327 /* 1 == check for aliases, 2 == also check for assignments */
9328 static int checkalias;
9329 struct nodelist *backquotelist;
9330 union node *redirnode;
9331 struct heredoc *heredoc;
9332 static int quoteflag; /* set if (part of) last token was quoted */
9333 static int startlinno; /* line # where last token started */
9336 static union node *list __P((int));
9337 static union node *andor __P((void));
9338 static union node *pipeline __P((void));
9339 static union node *command __P((void));
9340 static union node *simplecmd __P((void));
9341 static union node *makename __P((void));
9342 static void parsefname __P((void));
9343 static void parseheredoc __P((void));
9344 static int peektoken __P((void));
9345 static int readtoken __P((void));
9346 static int xxreadtoken __P((void));
9347 static int readtoken1 __P((int, char const *, char *, int));
9348 static int noexpand __P((char *));
9349 static void synexpect __P((int)) __attribute__((noreturn));
9350 static void synerror __P((const char *)) __attribute__((noreturn));
9351 static void setprompt __P((int));
9355 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9356 * valid parse tree indicating a blank line.)
9360 parsecmd(int interact)
9365 doprompt = interact;
9385 union node *n1, *n2, *n3;
9389 if (nlflag == 0 && tokendlist[peektoken()])
9395 if (tok == TBACKGND) {
9396 if (n2->type == NCMD || n2->type == NPIPE) {
9397 n2->ncmd.backgnd = 1;
9398 } else if (n2->type == NREDIR) {
9399 n2->type = NBACKGND;
9401 n3 = (union node *)stalloc(sizeof (struct nredir));
9402 n3->type = NBACKGND;
9404 n3->nredir.redirect = NULL;
9412 n3 = (union node *)stalloc(sizeof (struct nbinary));
9414 n3->nbinary.ch1 = n1;
9415 n3->nbinary.ch2 = n2;
9432 if (tokendlist[peektoken()])
9439 pungetc(); /* push back EOF on input */
9454 union node *n1, *n2, *n3;
9460 if ((t = readtoken()) == TAND) {
9462 } else if (t == TOR) {
9470 n3 = (union node *)stalloc(sizeof (struct nbinary));
9472 n3->nbinary.ch1 = n1;
9473 n3->nbinary.ch2 = n2;
9482 union node *n1, *n2, *pipenode;
9483 struct nodelist *lp, *prev;
9487 TRACE(("pipeline: entered\n"));
9488 if (readtoken() == TNOT) {
9494 if (readtoken() == TPIPE) {
9495 pipenode = (union node *)stalloc(sizeof (struct npipe));
9496 pipenode->type = NPIPE;
9497 pipenode->npipe.backgnd = 0;
9498 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9499 pipenode->npipe.cmdlist = lp;
9503 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9507 } while (readtoken() == TPIPE);
9513 n2 = (union node *)stalloc(sizeof (struct nnot));
9525 union node *n1, *n2;
9526 union node *ap, **app;
9527 union node *cp, **cpp;
9528 union node *redir, **rpp;
9535 switch (readtoken()) {
9537 n1 = (union node *)stalloc(sizeof (struct nif));
9539 n1->nif.test = list(0);
9540 if (readtoken() != TTHEN)
9542 n1->nif.ifpart = list(0);
9544 while (readtoken() == TELIF) {
9545 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
9546 n2 = n2->nif.elsepart;
9548 n2->nif.test = list(0);
9549 if (readtoken() != TTHEN)
9551 n2->nif.ifpart = list(0);
9553 if (lasttoken == TELSE)
9554 n2->nif.elsepart = list(0);
9556 n2->nif.elsepart = NULL;
9559 if (readtoken() != TFI)
9566 n1 = (union node *)stalloc(sizeof (struct nbinary));
9567 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
9568 n1->nbinary.ch1 = list(0);
9569 if ((got=readtoken()) != TDO) {
9570 TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
9573 n1->nbinary.ch2 = list(0);
9574 if (readtoken() != TDONE)
9580 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
9581 synerror("Bad for loop variable");
9582 n1 = (union node *)stalloc(sizeof (struct nfor));
9584 n1->nfor.var = wordtext;
9586 if (readtoken() == TIN) {
9588 while (readtoken() == TWORD) {
9589 n2 = (union node *)stalloc(sizeof (struct narg));
9591 n2->narg.text = wordtext;
9592 n2->narg.backquote = backquotelist;
9594 app = &n2->narg.next;
9598 if (lasttoken != TNL && lasttoken != TSEMI)
9601 static char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE,
9603 n2 = (union node *)stalloc(sizeof (struct narg));
9605 n2->narg.text = argvars;
9606 n2->narg.backquote = NULL;
9607 n2->narg.next = NULL;
9610 * Newline or semicolon here is optional (but note
9611 * that the original Bourne shell only allowed NL).
9613 if (lasttoken != TNL && lasttoken != TSEMI)
9617 if (readtoken() != TDO)
9619 n1->nfor.body = list(0);
9620 if (readtoken() != TDONE)
9625 n1 = (union node *)stalloc(sizeof (struct ncase));
9627 if (readtoken() != TWORD)
9629 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
9631 n2->narg.text = wordtext;
9632 n2->narg.backquote = backquotelist;
9633 n2->narg.next = NULL;
9636 } while (readtoken() == TNL);
9637 if (lasttoken != TIN)
9638 synerror("expecting \"in\"");
9639 cpp = &n1->ncase.cases;
9640 checkkwd = 2, readtoken();
9642 if (lasttoken == TLP)
9644 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
9646 app = &cp->nclist.pattern;
9648 *app = ap = (union node *)stalloc(sizeof (struct narg));
9650 ap->narg.text = wordtext;
9651 ap->narg.backquote = backquotelist;
9652 if (checkkwd = 2, readtoken() != TPIPE)
9654 app = &ap->narg.next;
9657 ap->narg.next = NULL;
9658 if (lasttoken != TRP)
9660 cp->nclist.body = list(0);
9663 if ((t = readtoken()) != TESAC) {
9665 synexpect(TENDCASE);
9667 checkkwd = 2, readtoken();
9669 cpp = &cp->nclist.next;
9670 } while(lasttoken != TESAC);
9675 n1 = (union node *)stalloc(sizeof (struct nredir));
9676 n1->type = NSUBSHELL;
9677 n1->nredir.n = list(0);
9678 n1->nredir.redirect = NULL;
9679 if (readtoken() != TRP)
9685 if (readtoken() != TEND)
9689 /* Handle an empty command like other simple commands. */
9698 * An empty command before a ; doesn't make much sense, and
9699 * should certainly be disallowed in the case of `if ;'.
9713 /* Now check for redirection which may follow command */
9714 while (readtoken() == TREDIR) {
9715 *rpp = n2 = redirnode;
9716 rpp = &n2->nfile.next;
9722 if (n1->type != NSUBSHELL) {
9723 n2 = (union node *)stalloc(sizeof (struct nredir));
9728 n1->nredir.redirect = redir;
9737 union node *args, **app;
9738 union node *n = NULL;
9739 union node *vars, **vpp;
9740 union node **rpp, *redir;
9751 switch (readtoken()) {
9754 n = (union node *)stalloc(sizeof (struct narg));
9756 n->narg.text = wordtext;
9757 n->narg.backquote = backquotelist;
9758 if (lasttoken == TWORD) {
9760 app = &n->narg.next;
9763 vpp = &n->narg.next;
9767 *rpp = n = redirnode;
9768 rpp = &n->nfile.next;
9769 parsefname(); /* read name of redirection file */
9773 args && app == &args->narg.next &&
9776 /* We have a function */
9777 if (readtoken() != TRP)
9780 if (! goodname(n->narg.text))
9781 synerror("Bad function name");
9785 n->narg.next = command();
9798 n = (union node *)stalloc(sizeof (struct ncmd));
9800 n->ncmd.backgnd = 0;
9801 n->ncmd.args = args;
9802 n->ncmd.assign = vars;
9803 n->ncmd.redirect = redir;
9811 n = (union node *)stalloc(sizeof (struct narg));
9813 n->narg.next = NULL;
9814 n->narg.text = wordtext;
9815 n->narg.backquote = backquotelist;
9819 static void fixredir(union node *n, const char *text, int err)
9821 TRACE(("Fix redir %s %d\n", text, err));
9823 n->ndup.vname = NULL;
9825 if (is_digit(text[0]) && text[1] == '\0')
9826 n->ndup.dupfd = digit_val(text[0]);
9827 else if (text[0] == '-' && text[1] == '\0')
9832 synerror("Bad fd number");
9834 n->ndup.vname = makename();
9841 union node *n = redirnode;
9843 if (readtoken() != TWORD)
9845 if (n->type == NHERE) {
9846 struct heredoc *here = heredoc;
9852 TRACE(("Here document %d\n", n->type));
9853 if (here->striptabs) {
9854 while (*wordtext == '\t')
9857 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
9858 synerror("Illegal eof marker for << redirection");
9859 rmescapes(wordtext);
9860 here->eofmark = wordtext;
9862 if (heredoclist == NULL)
9865 for (p = heredoclist ; p->next ; p = p->next);
9868 } else if (n->type == NTOFD || n->type == NFROMFD) {
9869 fixredir(n, wordtext, 0);
9871 n->nfile.fname = makename();
9877 * Input any here documents.
9882 struct heredoc *here;
9885 while (heredoclist) {
9887 heredoclist = here->next;
9892 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9893 here->eofmark, here->striptabs);
9894 n = (union node *)stalloc(sizeof (struct narg));
9895 n->narg.type = NARG;
9896 n->narg.next = NULL;
9897 n->narg.text = wordtext;
9898 n->narg.backquote = backquotelist;
9899 here->here->nhere.doc = n;
9915 int savecheckkwd = checkkwd;
9916 int savecheckalias = checkalias;
9919 int alreadyseen = tokpushback;
9924 checkalias = savecheckalias;
9930 if (checkkwd == 2) {
9939 * check for keywords
9941 if (t == TWORD && !quoteflag)
9943 const char *const *pp;
9945 if ((pp = findkwd(wordtext))) {
9946 lasttoken = t = pp - parsekwd + KWDOFFSET;
9947 TRACE(("keyword %s recognized\n", tokname[t]));
9957 } else if (checkalias == 2 && isassignment(wordtext)) {
9958 lasttoken = t = TASSIGN;
9959 } else if (checkalias) {
9960 if (!quoteflag && (ap = lookupalias(wordtext, 1)) != NULL) {
9962 pushstring(ap->val, strlen(ap->val), ap);
9964 checkkwd = savecheckkwd;
9972 TRACE(("token %s %s\n", tokname[t], t == TWORD || t == TASSIGN ? wordtext : ""));
9974 TRACE(("reread token %s %s\n", tokname[t], t == TWORD || t == TASSIGN ? wordtext : ""));
9981 * Read the next input token.
9982 * If the token is a word, we set backquotelist to the list of cmds in
9983 * backquotes. We set quoteflag to true if any part of the word was
9985 * If the token is TREDIR, then we set redirnode to a structure containing
9987 * In all cases, the variable startlinno is set to the number of the line
9988 * on which the token starts.
9990 * [Change comment: here documents and internal procedures]
9991 * [Readtoken shouldn't have any arguments. Perhaps we should make the
9992 * word parsing code into a separate routine. In this case, readtoken
9993 * doesn't need to have any internal procedures, but parseword does.
9994 * We could also make parseoperator in essence the main routine, and
9995 * have parseword (readtoken1?) handle both words and redirection.]
9998 #define RETURN(token) return lasttoken = token
10012 startlinno = plinno;
10013 for (;;) { /* until token or start of word found */
10016 case ' ': case '\t':
10020 while ((c = pgetc()) != '\n' && c != PEOF);
10024 if (pgetc() == '\n') {
10025 startlinno = ++plinno;
10036 needprompt = doprompt;
10041 if (pgetc() == '&')
10046 if (pgetc() == '|')
10051 if (pgetc() == ';')
10064 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10071 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10072 * is not NULL, read a here document. In the latter case, eofmark is the
10073 * word which marks the end of the document and striptabs is true if
10074 * leading tabs should be stripped from the document. The argument firstc
10075 * is the first character of the input token or document.
10077 * Because C does not have internal subroutines, I have simulated them
10078 * using goto's to implement the subroutine linkage. The following macros
10079 * will run code that appears at the end of readtoken1.
10082 #define CHECKEND() {goto checkend; checkend_return:;}
10083 #define PARSEREDIR() {goto parseredir; parseredir_return:;}
10084 #define PARSESUB() {goto parsesub; parsesub_return:;}
10085 #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10086 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10087 #define PARSEARITH() {goto parsearith; parsearith_return:;}
10090 readtoken1(firstc, syntax, eofmark, striptabs)
10092 char const *syntax;
10099 char line[EOFMARKLEN + 1];
10100 struct nodelist *bqlist;
10103 int varnest; /* levels of variables expansion */
10104 int arinest; /* levels of arithmetic expansion */
10105 int parenlevel; /* levels of parens in arithmetic */
10106 int dqvarnest; /* levels of variables expansion within double quotes */
10108 char const *prevsyntax; /* syntax before arithmetic */
10110 /* Avoid longjmp clobbering */
10116 (void) &parenlevel;
10119 (void) &prevsyntax;
10123 startlinno = plinno;
10125 if (syntax == DQSYNTAX)
10134 STARTSTACKSTR(out);
10135 loop: { /* for each line, until end of word */
10137 if (c == '\034' && doprompt
10138 && attyset() && ! equal(termval(), "emacs")) {
10140 if (syntax == BASESYNTAX)
10141 return readtoken();
10146 CHECKEND(); /* set c to PEOF if at end of here document */
10147 for (;;) { /* until end of line or end of word */
10148 CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */
10149 switch(syntax[c]) {
10150 case CNL: /* '\n' */
10151 if (syntax == BASESYNTAX)
10152 goto endword; /* exit outer loop */
10160 goto loop; /* continue outer loop */
10165 if ((eofmark == NULL || dblquote) &&
10167 USTPUTC(CTLESC, out);
10170 case CBACK: /* backslash */
10173 USTPUTC('\\', out);
10175 } else if (c == '\n') {
10181 if (dblquote && c != '\\' && c != '`' && c != '$'
10182 && (c != '"' || eofmark != NULL))
10183 USTPUTC('\\', out);
10184 if (SQSYNTAX[c] == CCTL)
10185 USTPUTC(CTLESC, out);
10186 else if (eofmark == NULL)
10187 USTPUTC(CTLQUOTEMARK, out);
10193 if (eofmark == NULL)
10194 USTPUTC(CTLQUOTEMARK, out);
10198 if (eofmark == NULL)
10199 USTPUTC(CTLQUOTEMARK, out);
10204 if (eofmark != NULL && arinest == 0 &&
10209 syntax = ARISYNTAX;
10211 } else if (eofmark == NULL &&
10213 syntax = BASESYNTAX;
10219 case CVAR: /* '$' */
10220 PARSESUB(); /* parse substitution */
10222 case CENDVAR: /* '}' */
10225 if (dqvarnest > 0) {
10228 USTPUTC(CTLENDVAR, out);
10233 #ifdef ASH_MATH_SUPPORT
10234 case CLP: /* '(' in arithmetic */
10238 case CRP: /* ')' in arithmetic */
10239 if (parenlevel > 0) {
10243 if (pgetc() == ')') {
10244 if (--arinest == 0) {
10245 USTPUTC(CTLENDARI, out);
10246 syntax = prevsyntax;
10247 if (syntax == DQSYNTAX)
10255 * unbalanced parens
10256 * (don't 2nd guess - no error)
10264 case CBQUOTE: /* '`' */
10268 goto endword; /* exit outer loop */
10273 goto endword; /* exit outer loop */
10282 if (syntax == ARISYNTAX)
10283 synerror("Missing '))'");
10284 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
10285 synerror("Unterminated quoted string");
10286 if (varnest != 0) {
10287 startlinno = plinno;
10288 synerror("Missing '}'");
10290 USTPUTC('\0', out);
10291 len = out - stackblock();
10292 out = stackblock();
10293 if (eofmark == NULL) {
10294 if ((c == '>' || c == '<')
10297 && (*out == '\0' || is_digit(*out))) {
10299 return lasttoken = TREDIR;
10304 quoteflag = quotef;
10305 backquotelist = bqlist;
10306 grabstackblock(len);
10308 return lasttoken = TWORD;
10309 /* end of readtoken routine */
10314 * Check to see whether we are at the end of the here document. When this
10315 * is called, c is set to the first character of the next input line. If
10316 * we are at the end of the here document, this routine sets the c to PEOF.
10325 while (c == '\t') {
10329 if (c == *eofmark) {
10330 if (pfgets(line, sizeof line) != NULL) {
10334 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10335 if (*p == '\n' && *q == '\0') {
10338 needprompt = doprompt;
10340 pushstring(line, strlen(line), NULL);
10345 goto checkend_return;
10350 * Parse a redirection operator. The variable "out" points to a string
10351 * specifying the fd to be redirected. The variable "c" contains the
10352 * first character of the redirection operator.
10359 np = (union node *)stalloc(sizeof (struct nfile));
10364 np->type = NAPPEND;
10373 } else { /* c == '<' */
10375 switch (c = pgetc()) {
10377 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10378 np = (union node *)stalloc(sizeof (struct nhere));
10382 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10383 heredoc->here = np;
10384 if ((c = pgetc()) == '-') {
10385 heredoc->striptabs = 1;
10387 heredoc->striptabs = 0;
10393 np->type = NFROMFD;
10397 np->type = NFROMTO;
10407 np->nfile.fd = digit_val(fd);
10409 goto parseredir_return;
10414 * Parse a substitution. At this point, we have read the dollar sign
10415 * and nothing else.
10423 static const char types[] = "}-+?=";
10428 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10432 } else if (c == '(') { /* $(command) or $((arith)) */
10433 if (pgetc() == '(') {
10440 USTPUTC(CTLVAR, out);
10441 typeloc = out - stackblock();
10442 USTPUTC(VSNORMAL, out);
10443 subtype = VSNORMAL;
10447 if ((c = pgetc()) == '}')
10450 subtype = VSLENGTH;
10455 if (c > PEOA && is_name(c)) {
10459 } while (c > PEOA && is_in_name(c));
10460 } else if (is_digit(c)) {
10464 } while (is_digit(c));
10466 else if (is_special(c)) {
10471 badsub: synerror("Bad substitution");
10475 if (subtype == 0) {
10482 p = strchr(types, c);
10485 subtype = p - types + VSNORMAL;
10491 subtype = c == '#' ? VSTRIMLEFT :
10504 if (dblquote || arinest)
10506 *(stackblock() + typeloc) = subtype | flags;
10507 if (subtype != VSNORMAL) {
10514 goto parsesub_return;
10519 * Called to parse command substitutions. Newstyle is set if the command
10520 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10521 * list of commands (passed by reference), and savelen is the number of
10522 * characters on the top of the stack which must be preserved.
10526 struct nodelist **nlpp;
10529 char *volatile str;
10530 struct jmploc jmploc;
10531 struct jmploc *volatile savehandler;
10535 (void) &saveprompt;
10538 savepbq = parsebackquote;
10539 if (setjmp(jmploc.loc)) {
10542 parsebackquote = 0;
10543 handler = savehandler;
10544 longjmp(handler->loc, 1);
10548 savelen = out - stackblock();
10550 str = ckmalloc(savelen);
10551 memcpy(str, stackblock(), savelen);
10553 savehandler = handler;
10557 /* We must read until the closing backquote, giving special
10558 treatment to some slashes, and then push the string and
10559 reread it as input, interpreting it normally. */
10566 STARTSTACKSTR(pout);
10572 switch (pc = pgetc()) {
10577 if ((pc = pgetc()) == '\n') {
10584 * If eating a newline, avoid putting
10585 * the newline into the new character
10586 * stream (via the STPUTC after the
10591 if (pc != '\\' && pc != '`' && pc != '$'
10592 && (!dblquote || pc != '"'))
10593 STPUTC('\\', pout);
10601 startlinno = plinno;
10602 synerror("EOF in backquote substitution");
10606 needprompt = doprompt;
10615 STPUTC('\0', pout);
10616 psavelen = pout - stackblock();
10617 if (psavelen > 0) {
10618 pstr = grabstackstr(pout);
10619 setinputstring(pstr);
10624 nlpp = &(*nlpp)->next;
10625 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10626 (*nlpp)->next = NULL;
10627 parsebackquote = oldstyle;
10630 saveprompt = doprompt;
10637 doprompt = saveprompt;
10639 if (readtoken() != TRP)
10646 * Start reading from old file again, ignoring any pushed back
10647 * tokens left from the backquote parsing
10652 while (stackblocksize() <= savelen)
10654 STARTSTACKSTR(out);
10656 memcpy(out, str, savelen);
10657 STADJUST(savelen, out);
10663 parsebackquote = savepbq;
10664 handler = savehandler;
10665 if (arinest || dblquote)
10666 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10668 USTPUTC(CTLBACKQ, out);
10670 goto parsebackq_oldreturn;
10672 goto parsebackq_newreturn;
10676 * Parse an arithmetic expansion (indicate start of one and set state)
10680 if (++arinest == 1) {
10681 prevsyntax = syntax;
10682 syntax = ARISYNTAX;
10683 USTPUTC(CTLARI, out);
10690 * we collapse embedded arithmetic expansion to
10691 * parenthesis, which should be equivalent
10695 goto parsearith_return;
10698 } /* end of readtoken */
10712 * Returns true if the text contains nothing to expand (no dollar signs
10724 while ((c = *p++) != '\0') {
10725 if (c == CTLQUOTEMARK)
10729 else if (BASESYNTAX[(int)c] == CCTL)
10737 * Return true if the argument is a legal variable name (a letter or
10738 * underscore followed by zero or more letters, underscores, and digits).
10742 goodname(char *name)
10750 if (! is_in_name(*p))
10758 * Called when an unexpected token is read during the parse. The argument
10759 * is the token that is expected, or -1 if more than one type of token can
10760 * occur at this point.
10770 fmtstr(msg, 64, "%s unexpected (expecting %s)",
10771 tokname[lasttoken], tokname[token]);
10773 fmtstr(msg, 64, "%s unexpected", tokname[lasttoken]);
10785 outfmt(&errout, "%s: %d: ", commandname, startlinno);
10786 outfmt(&errout, "Syntax error: %s\n", msg);
10787 error((char *)NULL);
10792 setprompt(int which)
10794 whichprompt = which;
10795 putprompt(getprompt(NULL));
10799 * called by editline -- any expansions to the prompt
10800 * should be added here.
10802 static const char *
10803 getprompt(void *unused)
10805 switch (whichprompt) {
10813 return "<internal prompt error>";
10818 isassignment(const char *word) {
10819 if (!is_name(*word)) {
10824 } while (is_in_name(*word));
10825 return *word == '=';
10828 static const char *const *
10829 findkwd(const char *s) {
10831 s, parsekwd, sizeof(parsekwd) / sizeof(const char *)
10834 /* $NetBSD: redir.c,v 1.22 2000/05/22 10:18:47 elric Exp $ */
10837 * Code for dealing with input/output redirection.
10840 #define EMPTY -2 /* marks an unused slot in redirtab */
10842 # define PIPESIZE 4096 /* amount of buffering in a pipe */
10844 # define PIPESIZE PIPE_BUF
10848 struct redirtab *redirlist;
10851 * We keep track of whether or not fd0 has been redirected. This is for
10852 * background commands, where we want to redirect fd0 to /dev/null only
10853 * if it hasn't already been redirected.
10855 static int fd0_redirected = 0;
10858 * We also keep track of where fileno2 goes.
10860 static int fileno2 = 2;
10862 static int openredirect __P((union node *));
10863 static void dupredirect __P((union node *, int, char[10 ]));
10864 static int openhere __P((union node *));
10865 static int noclobberopen __P((const char *));
10869 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
10870 * old file descriptors are stashed away so that the redirection can be
10871 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
10872 * standard output, and the standard error if it becomes a duplicate of
10873 * stdout, is saved in memory.
10877 redirect(redir, flags)
10882 struct redirtab *sv = NULL;
10887 char memory[10]; /* file descriptors to write to memory */
10889 for (i = 10 ; --i >= 0 ; )
10891 memory[1] = flags & REDIR_BACKQ;
10892 if (flags & REDIR_PUSH) {
10893 sv = ckmalloc(sizeof (struct redirtab));
10894 for (i = 0 ; i < 10 ; i++)
10895 sv->renamed[i] = EMPTY;
10896 sv->next = redirlist;
10899 for (n = redir ; n ; n = n->nfile.next) {
10902 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
10903 n->ndup.dupfd == fd)
10904 continue; /* redirect from/to same file descriptor */
10907 newfd = openredirect(n);
10908 if (((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) ||
10912 } else if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
10916 dupredirect(n, newfd, memory);
10926 error("%d: %s", fd, strerror(errno));
10932 if (flags & REDIR_PUSH) {
10933 sv->renamed[fd] = i;
10935 if (fd == fileno2) {
10939 } else if (fd != newfd) {
10945 dupredirect(n, newfd, memory);
10956 openredirect(redir)
10962 switch (redir->nfile.type) {
10964 fname = redir->nfile.expfname;
10965 if ((f = open(fname, O_RDONLY)) < 0)
10969 fname = redir->nfile.expfname;
10970 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
10974 /* Take care of noclobber mode. */
10976 fname = redir->nfile.expfname;
10977 if ((f = noclobberopen(fname)) < 0)
10982 fname = redir->nfile.expfname;
10984 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
10987 if ((f = creat(fname, 0666)) < 0)
10992 fname = redir->nfile.expfname;
10994 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
10997 if ((f = open(fname, O_WRONLY)) < 0
10998 && (f = creat(fname, 0666)) < 0)
11000 lseek(f, (off_t)0, 2);
11007 /* Fall through to eliminate warning. */
11014 f = openhere(redir);
11020 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
11022 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11027 dupredirect(redir, f, memory)
11032 int fd = redir->nfile.fd;
11035 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
11036 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
11037 if (memory[redir->ndup.dupfd])
11040 dup_as_newfd(redir->ndup.dupfd, fd);
11046 dup_as_newfd(f, fd);
11054 * Handle here documents. Normally we fork off a process to write the
11055 * data to a pipe. If the document is short, we can stuff the data in
11056 * the pipe without forking.
11067 error("Pipe call failed");
11068 if (redir->type == NHERE) {
11069 len = strlen(redir->nhere.doc->narg.text);
11070 if (len <= PIPESIZE) {
11071 xwrite(pip[1], redir->nhere.doc->narg.text, len);
11075 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
11077 signal(SIGINT, SIG_IGN);
11078 signal(SIGQUIT, SIG_IGN);
11079 signal(SIGHUP, SIG_IGN);
11081 signal(SIGTSTP, SIG_IGN);
11083 signal(SIGPIPE, SIG_DFL);
11084 if (redir->type == NHERE)
11085 xwrite(pip[1], redir->nhere.doc->narg.text, len);
11087 expandhere(redir->nhere.doc, pip[1]);
11098 * Undo the effects of the last redirection.
11103 struct redirtab *rp = redirlist;
11107 for (i = 0 ; i < 10 ; i++) {
11108 if (rp->renamed[i] != EMPTY) {
11112 if (rp->renamed[i] >= 0) {
11113 dup_as_newfd(rp->renamed[i], i);
11114 close(rp->renamed[i]);
11116 if (rp->renamed[i] == fileno2) {
11121 redirlist = rp->next;
11127 * Undo all redirections. Called on error or interrupt.
11145 /* Return true if fd 0 has already been redirected at least once. */
11147 fd0_redirected_p () {
11148 return fd0_redirected != 0;
11152 * Discard all saved file descriptors.
11157 struct redirtab *rp;
11160 for (rp = redirlist ; rp ; rp = rp->next) {
11161 for (i = 0 ; i < 10 ; i++) {
11162 if (rp->renamed[i] >= 0) {
11163 close(rp->renamed[i]);
11164 if (rp->renamed[i] == fileno2) {
11168 rp->renamed[i] = EMPTY;
11171 if (fileno2 != 2 && fileno2 >= 0) {
11180 * Copy a file descriptor to be >= to. Returns -1
11181 * if the source file descriptor is closed, EMPTY if there are no unused
11182 * file descriptors left.
11186 dup_as_newfd(from, to)
11192 newfd = fcntl(from, F_DUPFD, to);
11194 if (errno == EMFILE)
11197 error("%d: %s", from, strerror(errno));
11203 * Open a file in noclobber mode.
11204 * The code was copied from bash.
11207 noclobberopen(fname)
11211 struct stat finfo, finfo2;
11214 * If the file exists and is a regular file, return an error
11217 r = stat(fname, &finfo);
11218 if (r == 0 && S_ISREG(finfo.st_mode)) {
11224 * If the file was not present (r != 0), make sure we open it
11225 * exclusively so that if it is created before we open it, our open
11226 * will fail. Make sure that we do not truncate an existing file.
11227 * Note that we don't turn on O_EXCL unless the stat failed -- if the
11228 * file was not a regular file, we leave O_EXCL off.
11231 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
11232 fd = open(fname, O_WRONLY|O_CREAT, 0666);
11234 /* If the open failed, return the file descriptor right away. */
11239 * OK, the open succeeded, but the file may have been changed from a
11240 * non-regular file to a regular file between the stat and the open.
11241 * We are assuming that the O_EXCL open handles the case where FILENAME
11242 * did not exist and is symlinked to an existing file between the stat
11247 * If we can open it and fstat the file descriptor, and neither check
11248 * revealed that it was a regular file, and the file has not been
11249 * replaced, return the file descriptor.
11251 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
11252 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
11255 /* The file has been replaced. badness. */
11260 /* $NetBSD: setmode.c,v 1.28 2000/01/25 15:43:43 enami Exp $ */
11262 #ifdef __weak_alias
11263 __weak_alias(getmode,_getmode)
11264 __weak_alias(setmode,_setmode)
11268 #define S_ISTXT __S_ISVTX
11271 #define SET_LEN 6 /* initial # of bitcmd struct to malloc */
11272 #define SET_LEN_INCR 4 /* # of bitcmd structs to add as needed */
11274 typedef struct bitcmd {
11280 #define CMD2_CLR 0x01
11281 #define CMD2_SET 0x02
11282 #define CMD2_GBITS 0x04
11283 #define CMD2_OBITS 0x08
11284 #define CMD2_UBITS 0x10
11286 static BITCMD *addcmd __P((BITCMD *, int, int, int, u_int));
11287 static void compress_mode __P((BITCMD *));
11288 #ifdef SETMODE_DEBUG
11289 static void dumpmode __P((BITCMD *));
11293 * Given the old mode and an array of bitcmd structures, apply the operations
11294 * described in the bitcmd structures to the old mode, and return the new mode.
11295 * Note that there is no '=' command; a strict assignment is just a '-' (clear
11296 * bits) followed by a '+' (set bits).
11299 getmode(bbox, omode)
11304 mode_t clrval, newmode, value;
11306 _DIAGASSERT(bbox != NULL);
11308 set = (const BITCMD *)bbox;
11310 for (value = 0;; set++)
11313 * When copying the user, group or other bits around, we "know"
11314 * where the bits are in the mode so that we can do shifts to
11315 * copy them around. If we don't use shifts, it gets real
11316 * grundgy with lots of single bit checks and bit sets.
11319 value = (newmode & S_IRWXU) >> 6;
11323 value = (newmode & S_IRWXG) >> 3;
11327 value = newmode & S_IRWXO;
11328 common: if (set->cmd2 & CMD2_CLR) {
11330 (set->cmd2 & CMD2_SET) ? S_IRWXO : value;
11331 if (set->cmd2 & CMD2_UBITS)
11332 newmode &= ~((clrval<<6) & set->bits);
11333 if (set->cmd2 & CMD2_GBITS)
11334 newmode &= ~((clrval<<3) & set->bits);
11335 if (set->cmd2 & CMD2_OBITS)
11336 newmode &= ~(clrval & set->bits);
11338 if (set->cmd2 & CMD2_SET) {
11339 if (set->cmd2 & CMD2_UBITS)
11340 newmode |= (value<<6) & set->bits;
11341 if (set->cmd2 & CMD2_GBITS)
11342 newmode |= (value<<3) & set->bits;
11343 if (set->cmd2 & CMD2_OBITS)
11344 newmode |= value & set->bits;
11349 newmode |= set->bits;
11353 newmode &= ~set->bits;
11357 if (omode & (S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH))
11358 newmode |= set->bits;
11363 #ifdef SETMODE_DEBUG
11364 (void)printf("getmode:%04o -> %04o\n", omode, newmode);
11370 #define ADDCMD(a, b, c, d) do { \
11371 if (set >= endset) { \
11373 setlen += SET_LEN_INCR; \
11374 newset = realloc(saveset, sizeof(BITCMD) * setlen); \
11375 if (newset == NULL) { \
11379 set = newset + (set - saveset); \
11380 saveset = newset; \
11381 endset = newset + (setlen - 2); \
11383 set = addcmd(set, (a), (b), (c), (d)); \
11384 } while (/*CONSTCOND*/0)
11386 #define STANDARD_BITS (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
11394 BITCMD *set, *saveset, *endset;
11395 sigset_t mysigset, sigoset;
11397 int equalopdone = 0; /* pacify gcc */
11398 int permXbits, setlen;
11404 * Get a copy of the mask for the permissions that are mask relative.
11405 * Flip the bits, we want what's not set. Since it's possible that
11406 * the caller is opening files inside a signal handler, protect them
11409 sigfillset(&mysigset);
11410 (void)sigprocmask(SIG_BLOCK, &mysigset, &sigoset);
11411 (void)umask(mask = umask(0));
11413 (void)sigprocmask(SIG_SETMASK, &sigoset, NULL);
11415 setlen = SET_LEN + 2;
11417 if ((set = malloc((u_int)(sizeof(BITCMD) * setlen))) == NULL)
11420 endset = set + (setlen - 2);
11423 * If an absolute number, get it and return; disallow non-octal digits
11426 if (isdigit((unsigned char)*p)) {
11427 perm = (mode_t)strtol(p, &ep, 8);
11428 if (*ep || perm & ~(STANDARD_BITS|S_ISTXT)) {
11432 ADDCMD('=', (STANDARD_BITS|S_ISTXT), perm, mask);
11438 * Build list of structures to set/clear/copy bits as described by
11439 * each clause of the symbolic mode.
11442 /* First, find out which bits might be modified. */
11443 for (who = 0;; ++p) {
11446 who |= STANDARD_BITS;
11449 who |= S_ISUID|S_IRWXU;
11452 who |= S_ISGID|S_IRWXG;
11462 getop: if ((op = *p++) != '+' && op != '-' && op != '=') {
11470 for (perm = 0, permXbits = 0;; ++p) {
11473 perm |= S_IRUSR|S_IRGRP|S_IROTH;
11477 * If specific bits where requested and
11478 * only "other" bits ignore set-id.
11480 if (who == 0 || (who & ~S_IRWXO))
11481 perm |= S_ISUID|S_ISGID;
11485 * If specific bits where requested and
11486 * only "other" bits ignore set-id.
11488 if (who == 0 || (who & ~S_IRWXO)) {
11494 perm |= S_IWUSR|S_IWGRP|S_IWOTH;
11497 permXbits = S_IXUSR|S_IXGRP|S_IXOTH;
11500 perm |= S_IXUSR|S_IXGRP|S_IXOTH;
11506 * When ever we hit 'u', 'g', or 'o', we have
11507 * to flush out any partial mode that we have,
11508 * and then do the copying of the mode bits.
11511 ADDCMD(op, who, perm, mask);
11516 if (op == '+' && permXbits) {
11517 ADDCMD('X', who, permXbits, mask);
11520 ADDCMD(*p, who, op, mask);
11525 * Add any permissions that we haven't already
11528 if (perm || (op == '=' && !equalopdone)) {
11531 ADDCMD(op, who, perm, mask);
11535 ADDCMD('X', who, permXbits, mask);
11549 #ifdef SETMODE_DEBUG
11550 (void)printf("Before compress_mode()\n");
11553 compress_mode(saveset);
11554 #ifdef SETMODE_DEBUG
11555 (void)printf("After compress_mode()\n");
11562 addcmd(set, op, who, oparg, mask)
11569 _DIAGASSERT(set != NULL);
11574 set->bits = who ? who : STANDARD_BITS;
11583 set->bits = (who ? who : mask) & oparg;
11591 set->cmd2 = ((who & S_IRUSR) ? CMD2_UBITS : 0) |
11592 ((who & S_IRGRP) ? CMD2_GBITS : 0) |
11593 ((who & S_IROTH) ? CMD2_OBITS : 0);
11594 set->bits = (mode_t)~0;
11596 set->cmd2 = CMD2_UBITS | CMD2_GBITS | CMD2_OBITS;
11601 set->cmd2 |= CMD2_SET;
11602 else if (oparg == '-')
11603 set->cmd2 |= CMD2_CLR;
11604 else if (oparg == '=')
11605 set->cmd2 |= CMD2_SET|CMD2_CLR;
11611 #ifdef SETMODE_DEBUG
11617 _DIAGASSERT(set != NULL);
11619 for (; set->cmd; ++set)
11620 (void)printf("cmd: '%c' bits %04o%s%s%s%s%s%s\n",
11621 set->cmd, set->bits, set->cmd2 ? " cmd2:" : "",
11622 set->cmd2 & CMD2_CLR ? " CLR" : "",
11623 set->cmd2 & CMD2_SET ? " SET" : "",
11624 set->cmd2 & CMD2_UBITS ? " UBITS" : "",
11625 set->cmd2 & CMD2_GBITS ? " GBITS" : "",
11626 set->cmd2 & CMD2_OBITS ? " OBITS" : "");
11631 * Given an array of bitcmd structures, compress by compacting consecutive
11632 * '+', '-' and 'X' commands into at most 3 commands, one of each. The 'u',
11633 * 'g' and 'o' commands continue to be separate. They could probably be
11634 * compacted, but it's not worth the effort.
11641 int setbits, clrbits, Xbits, op;
11643 _DIAGASSERT(set != NULL);
11645 for (nset = set;;) {
11646 /* Copy over any 'u', 'g' and 'o' commands. */
11647 while ((op = nset->cmd) != '+' && op != '-' && op != 'X') {
11653 for (setbits = clrbits = Xbits = 0;; nset++) {
11654 if ((op = nset->cmd) == '-') {
11655 clrbits |= nset->bits;
11656 setbits &= ~nset->bits;
11657 Xbits &= ~nset->bits;
11658 } else if (op == '+') {
11659 setbits |= nset->bits;
11660 clrbits &= ~nset->bits;
11661 Xbits &= ~nset->bits;
11662 } else if (op == 'X')
11663 Xbits |= nset->bits & ~setbits;
11670 set->bits = clrbits;
11676 set->bits = setbits;
11687 /* $NetBSD: show.c,v 1.18 1999/10/08 21:10:44 pk Exp $ */
11691 static void shtree __P((union node *, int, char *, FILE*));
11692 static void shcmd __P((union node *, FILE *));
11693 static void sharg __P((union node *, FILE *));
11694 static void indent __P((int, char *, FILE *));
11695 static void trstring __P((char *));
11702 trputs("showtree called\n");
11703 shtree(n, 1, NULL, stdout);
11708 shtree(n, ind, pfx, fp)
11714 struct nodelist *lp;
11720 indent(ind, pfx, fp);
11731 shtree(n->nbinary.ch1, ind, NULL, fp);
11734 shtree(n->nbinary.ch2, ind, NULL, fp);
11742 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
11747 if (n->npipe.backgnd)
11753 fprintf(fp, "<node type %d>", n->type);
11773 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11779 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11782 switch (np->nfile.type) {
11783 case NTO: s = ">"; dftfd = 1; break;
11784 case NAPPEND: s = ">>"; dftfd = 1; break;
11785 case NTOFD: s = ">&"; dftfd = 1; break;
11786 case NTOOV: s = ">|"; dftfd = 1; break;
11787 case NFROM: s = "<"; dftfd = 0; break;
11788 case NFROMFD: s = "<&"; dftfd = 0; break;
11789 case NFROMTO: s = "<>"; dftfd = 0; break;
11790 default: s = "*error*"; dftfd = 0; break;
11792 if (np->nfile.fd != dftfd)
11793 fprintf(fp, "%d", np->nfile.fd);
11795 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11796 fprintf(fp, "%d", np->ndup.dupfd);
11798 sharg(np->nfile.fname, fp);
11812 struct nodelist *bqlist;
11815 if (arg->type != NARG) {
11816 printf("<node type %d>\n", arg->type);
11820 bqlist = arg->narg.backquote;
11821 for (p = arg->narg.text ; *p ; p++) {
11830 if (subtype == VSLENGTH)
11836 if (subtype & VSNUL)
11839 switch (subtype & VSTYPE) {
11858 case VSTRIMLEFTMAX:
11865 case VSTRIMRIGHTMAX:
11872 printf("<subtype %d>", subtype);
11879 case CTLBACKQ|CTLQUOTE:
11882 shtree(bqlist->n, -1, NULL, fp);
11894 indent(amount, pfx, fp)
11901 for (i = 0 ; i < amount ; i++) {
11902 if (pfx && i == amount - 1)
11920 static int debug = 1;
11922 static int debug = 0;
11930 if (tracefile == NULL)
11932 putc(c, tracefile);
11938 trace(const char *fmt, ...)
11946 fmt = va_arg(va, char *);
11948 if (tracefile != NULL) {
11949 (void) vfprintf(tracefile, fmt, va);
11950 if (strchr(fmt, '\n'))
11951 (void) fflush(tracefile);
11961 if (tracefile == NULL)
11963 fputs(s, tracefile);
11964 if (strchr(s, '\n'))
11976 if (tracefile == NULL)
11978 putc('"', tracefile);
11979 for (p = s ; *p ; p++) {
11981 case '\n': c = 'n'; goto backslash;
11982 case '\t': c = 't'; goto backslash;
11983 case '\r': c = 'r'; goto backslash;
11984 case '"': c = '"'; goto backslash;
11985 case '\\': c = '\\'; goto backslash;
11986 case CTLESC: c = 'e'; goto backslash;
11987 case CTLVAR: c = 'v'; goto backslash;
11988 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11989 case CTLBACKQ: c = 'q'; goto backslash;
11990 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
11991 backslash: putc('\\', tracefile);
11992 putc(c, tracefile);
11995 if (*p >= ' ' && *p <= '~')
11996 putc(*p, tracefile);
11998 putc('\\', tracefile);
11999 putc(*p >> 6 & 03, tracefile);
12000 putc(*p >> 3 & 07, tracefile);
12001 putc(*p & 07, tracefile);
12006 putc('"', tracefile);
12014 if (tracefile == NULL)
12019 putc(' ', tracefile);
12021 putc('\n', tracefile);
12036 #ifdef not_this_way
12039 if ((p = getenv("HOME")) == NULL) {
12040 if (geteuid() == 0)
12046 strcat(s, "/trace");
12049 scopy("./trace", s);
12050 #endif /* not_this_way */
12051 if ((tracefile = fopen(s, "a")) == NULL) {
12052 fprintf(stderr, "Can't open %s\n", s);
12056 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
12057 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
12059 fputs("\nTracing started.\n", tracefile);
12066 * This file was generated by the mksyntax program.
12069 /* syntax table used when not in quotes */
12070 static const char basesyntax[257] = {
12071 CEOF, CSPCL, CWORD, CCTL,
12072 CCTL, CCTL, CCTL, CCTL,
12073 CCTL, CCTL, CCTL, CWORD,
12074 CWORD, CWORD, CWORD, CWORD,
12075 CWORD, CWORD, CWORD, CWORD,
12076 CWORD, CWORD, CWORD, CWORD,
12077 CWORD, CWORD, CWORD, CWORD,
12078 CWORD, CWORD, CWORD, CWORD,
12079 CWORD, CWORD, CWORD, CWORD,
12080 CWORD, CWORD, CWORD, CWORD,
12081 CWORD, CWORD, CWORD, CWORD,
12082 CWORD, CWORD, CWORD, CWORD,
12083 CWORD, CWORD, CWORD, CWORD,
12084 CWORD, CWORD, CWORD, CWORD,
12085 CWORD, CWORD, CWORD, CWORD,
12086 CWORD, CWORD, CWORD, CWORD,
12087 CWORD, CWORD, CWORD, CWORD,
12088 CWORD, CWORD, CWORD, CWORD,
12089 CWORD, CWORD, CWORD, CWORD,
12090 CWORD, CWORD, CWORD, CWORD,
12091 CWORD, CWORD, CWORD, CWORD,
12092 CWORD, CWORD, CWORD, CWORD,
12093 CWORD, CWORD, CWORD, CWORD,
12094 CWORD, CWORD, CWORD, CWORD,
12095 CWORD, CWORD, CWORD, CWORD,
12096 CWORD, CWORD, CWORD, CWORD,
12097 CWORD, CWORD, CWORD, CWORD,
12098 CWORD, CWORD, CWORD, CWORD,
12099 CWORD, CWORD, CWORD, CWORD,
12100 CWORD, CWORD, CWORD, CWORD,
12101 CWORD, CWORD, CWORD, CWORD,
12102 CWORD, CWORD, CWORD, CWORD,
12103 CWORD, CWORD, CWORD, CWORD,
12104 CWORD, CWORD, CWORD, CWORD,
12105 CWORD, CWORD, CWORD, CSPCL,
12106 CNL, CWORD, CWORD, CWORD,
12107 CWORD, CWORD, CWORD, CWORD,
12108 CWORD, CWORD, CWORD, CWORD,
12109 CWORD, CWORD, CWORD, CWORD,
12110 CWORD, CWORD, CWORD, CWORD,
12111 CWORD, CWORD, CSPCL, CWORD,
12112 CDQUOTE, CWORD, CVAR, CWORD,
12113 CSPCL, CSQUOTE, CSPCL, CSPCL,
12114 CWORD, CWORD, CWORD, CWORD,
12115 CWORD, CWORD, CWORD, CWORD,
12116 CWORD, CWORD, CWORD, CWORD,
12117 CWORD, CWORD, CWORD, CWORD,
12118 CWORD, CSPCL, CSPCL, CWORD,
12119 CSPCL, CWORD, CWORD, CWORD,
12120 CWORD, CWORD, CWORD, CWORD,
12121 CWORD, CWORD, CWORD, CWORD,
12122 CWORD, CWORD, CWORD, CWORD,
12123 CWORD, CWORD, CWORD, CWORD,
12124 CWORD, CWORD, CWORD, CWORD,
12125 CWORD, CWORD, CWORD, CWORD,
12126 CWORD, CWORD, CBACK, CWORD,
12127 CWORD, CWORD, CBQUOTE, CWORD,
12128 CWORD, CWORD, CWORD, CWORD,
12129 CWORD, CWORD, CWORD, CWORD,
12130 CWORD, CWORD, CWORD, CWORD,
12131 CWORD, CWORD, CWORD, CWORD,
12132 CWORD, CWORD, CWORD, CWORD,
12133 CWORD, CWORD, CWORD, CWORD,
12134 CWORD, CWORD, CSPCL, CENDVAR,
12138 /* syntax table used when in double quotes */
12139 static const char dqsyntax[257] = {
12140 CEOF, CIGN, CWORD, CCTL,
12141 CCTL, CCTL, CCTL, CCTL,
12142 CCTL, CCTL, CCTL, CWORD,
12143 CWORD, CWORD, CWORD, CWORD,
12144 CWORD, CWORD, CWORD, CWORD,
12145 CWORD, CWORD, CWORD, CWORD,
12146 CWORD, CWORD, CWORD, CWORD,
12147 CWORD, CWORD, CWORD, CWORD,
12148 CWORD, CWORD, CWORD, CWORD,
12149 CWORD, CWORD, CWORD, CWORD,
12150 CWORD, CWORD, CWORD, CWORD,
12151 CWORD, CWORD, CWORD, CWORD,
12152 CWORD, CWORD, CWORD, CWORD,
12153 CWORD, CWORD, CWORD, CWORD,
12154 CWORD, CWORD, CWORD, CWORD,
12155 CWORD, CWORD, CWORD, CWORD,
12156 CWORD, CWORD, CWORD, CWORD,
12157 CWORD, CWORD, CWORD, CWORD,
12158 CWORD, CWORD, CWORD, CWORD,
12159 CWORD, CWORD, CWORD, CWORD,
12160 CWORD, CWORD, CWORD, CWORD,
12161 CWORD, CWORD, CWORD, CWORD,
12162 CWORD, CWORD, CWORD, CWORD,
12163 CWORD, CWORD, CWORD, CWORD,
12164 CWORD, CWORD, CWORD, CWORD,
12165 CWORD, CWORD, CWORD, CWORD,
12166 CWORD, CWORD, CWORD, CWORD,
12167 CWORD, CWORD, CWORD, CWORD,
12168 CWORD, CWORD, CWORD, CWORD,
12169 CWORD, CWORD, CWORD, CWORD,
12170 CWORD, CWORD, CWORD, CWORD,
12171 CWORD, CWORD, CWORD, CWORD,
12172 CWORD, CWORD, CWORD, CWORD,
12173 CWORD, CWORD, CWORD, CWORD,
12174 CWORD, CWORD, CWORD, CWORD,
12175 CNL, CWORD, CWORD, CWORD,
12176 CWORD, CWORD, CWORD, CWORD,
12177 CWORD, CWORD, CWORD, CWORD,
12178 CWORD, CWORD, CWORD, CWORD,
12179 CWORD, CWORD, CWORD, CWORD,
12180 CWORD, CWORD, CWORD, CCTL,
12181 CENDQUOTE,CWORD, CVAR, CWORD,
12182 CWORD, CWORD, CWORD, CWORD,
12183 CCTL, CWORD, CWORD, CCTL,
12184 CWORD, CCTL, CWORD, CWORD,
12185 CWORD, CWORD, CWORD, CWORD,
12186 CWORD, CWORD, CWORD, CWORD,
12187 CCTL, CWORD, CWORD, CCTL,
12188 CWORD, CCTL, CWORD, CWORD,
12189 CWORD, CWORD, CWORD, CWORD,
12190 CWORD, CWORD, CWORD, CWORD,
12191 CWORD, CWORD, CWORD, CWORD,
12192 CWORD, CWORD, CWORD, CWORD,
12193 CWORD, CWORD, CWORD, CWORD,
12194 CWORD, CWORD, CWORD, CWORD,
12195 CWORD, CCTL, CBACK, CCTL,
12196 CWORD, CWORD, CBQUOTE, CWORD,
12197 CWORD, CWORD, CWORD, CWORD,
12198 CWORD, CWORD, CWORD, CWORD,
12199 CWORD, CWORD, CWORD, CWORD,
12200 CWORD, CWORD, CWORD, CWORD,
12201 CWORD, CWORD, CWORD, CWORD,
12202 CWORD, CWORD, CWORD, CWORD,
12203 CWORD, CWORD, CWORD, CENDVAR,
12207 /* syntax table used when in single quotes */
12208 static const char sqsyntax[257] = {
12209 CEOF, CIGN, CWORD, CCTL,
12210 CCTL, CCTL, CCTL, CCTL,
12211 CCTL, CCTL, CCTL, CWORD,
12212 CWORD, CWORD, CWORD, CWORD,
12213 CWORD, CWORD, CWORD, CWORD,
12214 CWORD, CWORD, CWORD, CWORD,
12215 CWORD, CWORD, CWORD, CWORD,
12216 CWORD, CWORD, CWORD, CWORD,
12217 CWORD, CWORD, CWORD, CWORD,
12218 CWORD, CWORD, CWORD, CWORD,
12219 CWORD, CWORD, CWORD, CWORD,
12220 CWORD, CWORD, CWORD, CWORD,
12221 CWORD, CWORD, CWORD, CWORD,
12222 CWORD, CWORD, CWORD, CWORD,
12223 CWORD, CWORD, CWORD, CWORD,
12224 CWORD, CWORD, CWORD, CWORD,
12225 CWORD, CWORD, CWORD, CWORD,
12226 CWORD, CWORD, CWORD, CWORD,
12227 CWORD, CWORD, CWORD, CWORD,
12228 CWORD, CWORD, CWORD, CWORD,
12229 CWORD, CWORD, CWORD, CWORD,
12230 CWORD, CWORD, CWORD, CWORD,
12231 CWORD, CWORD, CWORD, CWORD,
12232 CWORD, CWORD, CWORD, CWORD,
12233 CWORD, CWORD, CWORD, CWORD,
12234 CWORD, CWORD, CWORD, CWORD,
12235 CWORD, CWORD, CWORD, CWORD,
12236 CWORD, CWORD, CWORD, CWORD,
12237 CWORD, CWORD, CWORD, CWORD,
12238 CWORD, CWORD, CWORD, CWORD,
12239 CWORD, CWORD, CWORD, CWORD,
12240 CWORD, CWORD, CWORD, CWORD,
12241 CWORD, CWORD, CWORD, CWORD,
12242 CWORD, CWORD, CWORD, CWORD,
12243 CWORD, CWORD, CWORD, CWORD,
12244 CNL, CWORD, CWORD, CWORD,
12245 CWORD, CWORD, CWORD, CWORD,
12246 CWORD, CWORD, CWORD, CWORD,
12247 CWORD, CWORD, CWORD, CWORD,
12248 CWORD, CWORD, CWORD, CWORD,
12249 CWORD, CWORD, CWORD, CCTL,
12250 CWORD, CWORD, CWORD, CWORD,
12251 CWORD, CENDQUOTE,CWORD, CWORD,
12252 CCTL, CWORD, CWORD, CCTL,
12253 CWORD, CCTL, CWORD, CWORD,
12254 CWORD, CWORD, CWORD, CWORD,
12255 CWORD, CWORD, CWORD, CWORD,
12256 CCTL, CWORD, CWORD, CCTL,
12257 CWORD, CCTL, CWORD, CWORD,
12258 CWORD, CWORD, CWORD, CWORD,
12259 CWORD, CWORD, CWORD, CWORD,
12260 CWORD, CWORD, CWORD, CWORD,
12261 CWORD, CWORD, CWORD, CWORD,
12262 CWORD, CWORD, CWORD, CWORD,
12263 CWORD, CWORD, CWORD, CWORD,
12264 CWORD, CCTL, CCTL, CCTL,
12265 CWORD, CWORD, CWORD, CWORD,
12266 CWORD, CWORD, CWORD, CWORD,
12267 CWORD, CWORD, CWORD, CWORD,
12268 CWORD, CWORD, CWORD, CWORD,
12269 CWORD, CWORD, CWORD, CWORD,
12270 CWORD, CWORD, CWORD, CWORD,
12271 CWORD, CWORD, CWORD, CWORD,
12272 CWORD, CWORD, CWORD, CWORD,
12276 /* syntax table used when in arithmetic */
12277 static const char arisyntax[257] = {
12278 CEOF, CIGN, CWORD, CCTL,
12279 CCTL, CCTL, CCTL, CCTL,
12280 CCTL, CCTL, CCTL, CWORD,
12281 CWORD, CWORD, CWORD, CWORD,
12282 CWORD, CWORD, CWORD, CWORD,
12283 CWORD, CWORD, CWORD, CWORD,
12284 CWORD, CWORD, CWORD, CWORD,
12285 CWORD, CWORD, CWORD, CWORD,
12286 CWORD, CWORD, CWORD, CWORD,
12287 CWORD, CWORD, CWORD, CWORD,
12288 CWORD, CWORD, CWORD, CWORD,
12289 CWORD, CWORD, CWORD, CWORD,
12290 CWORD, CWORD, CWORD, CWORD,
12291 CWORD, CWORD, CWORD, CWORD,
12292 CWORD, CWORD, CWORD, CWORD,
12293 CWORD, CWORD, CWORD, CWORD,
12294 CWORD, CWORD, CWORD, CWORD,
12295 CWORD, CWORD, CWORD, CWORD,
12296 CWORD, CWORD, CWORD, CWORD,
12297 CWORD, CWORD, CWORD, CWORD,
12298 CWORD, CWORD, CWORD, CWORD,
12299 CWORD, CWORD, CWORD, CWORD,
12300 CWORD, CWORD, CWORD, CWORD,
12301 CWORD, CWORD, CWORD, CWORD,
12302 CWORD, CWORD, CWORD, CWORD,
12303 CWORD, CWORD, CWORD, CWORD,
12304 CWORD, CWORD, CWORD, CWORD,
12305 CWORD, CWORD, CWORD, CWORD,
12306 CWORD, CWORD, CWORD, CWORD,
12307 CWORD, CWORD, CWORD, CWORD,
12308 CWORD, CWORD, CWORD, CWORD,
12309 CWORD, CWORD, CWORD, CWORD,
12310 CWORD, CWORD, CWORD, CWORD,
12311 CWORD, CWORD, CWORD, CWORD,
12312 CWORD, CWORD, CWORD, CWORD,
12313 CNL, CWORD, CWORD, CWORD,
12314 CWORD, CWORD, CWORD, CWORD,
12315 CWORD, CWORD, CWORD, CWORD,
12316 CWORD, CWORD, CWORD, CWORD,
12317 CWORD, CWORD, CWORD, CWORD,
12318 CWORD, CWORD, CWORD, CWORD,
12319 CDQUOTE, CWORD, CVAR, CWORD,
12320 CWORD, CSQUOTE, CLP, CRP,
12321 CWORD, CWORD, CWORD, CWORD,
12322 CWORD, CWORD, CWORD, CWORD,
12323 CWORD, CWORD, CWORD, CWORD,
12324 CWORD, CWORD, CWORD, CWORD,
12325 CWORD, CWORD, CWORD, CWORD,
12326 CWORD, CWORD, CWORD, CWORD,
12327 CWORD, CWORD, CWORD, CWORD,
12328 CWORD, CWORD, CWORD, CWORD,
12329 CWORD, CWORD, CWORD, CWORD,
12330 CWORD, CWORD, CWORD, CWORD,
12331 CWORD, CWORD, CWORD, CWORD,
12332 CWORD, CWORD, CWORD, CWORD,
12333 CWORD, CWORD, CBACK, CWORD,
12334 CWORD, CWORD, CBQUOTE, CWORD,
12335 CWORD, CWORD, CWORD, CWORD,
12336 CWORD, CWORD, CWORD, CWORD,
12337 CWORD, CWORD, CWORD, CWORD,
12338 CWORD, CWORD, CWORD, CWORD,
12339 CWORD, CWORD, CWORD, CWORD,
12340 CWORD, CWORD, CWORD, CWORD,
12341 CWORD, CWORD, CWORD, CENDVAR,
12345 /* character classification table */
12346 static const char is_type[257] = {
12388 0, ISSPECL, ISSPECL, 0,
12390 ISSPECL, 0, 0, ISSPECL,
12391 0, 0, ISDIGIT, ISDIGIT,
12392 ISDIGIT, ISDIGIT, ISDIGIT, ISDIGIT,
12393 ISDIGIT, ISDIGIT, ISDIGIT, ISDIGIT,
12395 0, ISSPECL, ISSPECL, ISUPPER,
12396 ISUPPER, ISUPPER, ISUPPER, ISUPPER,
12397 ISUPPER, ISUPPER, ISUPPER, ISUPPER,
12398 ISUPPER, ISUPPER, ISUPPER, ISUPPER,
12399 ISUPPER, ISUPPER, ISUPPER, ISUPPER,
12400 ISUPPER, ISUPPER, ISUPPER, ISUPPER,
12401 ISUPPER, ISUPPER, ISUPPER, ISUPPER,
12403 0, ISUNDER, 0, ISLOWER,
12404 ISLOWER, ISLOWER, ISLOWER, ISLOWER,
12405 ISLOWER, ISLOWER, ISLOWER, ISLOWER,
12406 ISLOWER, ISLOWER, ISLOWER, ISLOWER,
12407 ISLOWER, ISLOWER, ISLOWER, ISLOWER,
12408 ISLOWER, ISLOWER, ISLOWER, ISLOWER,
12409 ISLOWER, ISLOWER, ISLOWER, ISLOWER,
12413 /* $NetBSD: trap.c,v 1.25 2001/02/04 19:52:07 christos Exp $ */
12416 * The trap builtin.
12420 trapcmd(argc, argv)
12429 for (signo = 0 ; signo < NSIG ; signo++) {
12430 if (trap[signo] != NULL) {
12433 p = single_quote(trap[signo]);
12434 out1fmt("trap -- %s %s\n", p,
12435 signal_names[signo] + (signo ? 3 : 0)
12448 if ((signo = decode_signal(*ap, 0)) < 0)
12449 error("%s: bad trap", *ap);
12452 if (action[0] == '-' && action[1] == '\0')
12455 action = savestr(action);
12458 ckfree(trap[signo]);
12459 trap[signo] = action;
12471 * Clear traps on a fork.
12478 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
12479 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
12483 if (tp != &trap[0])
12484 setsignal(tp - trap);
12493 * Set the signal handler for the specified signal. The routine figures
12494 * out what it should be set to.
12503 struct sigaction act;
12505 if ((t = trap[signo]) == NULL)
12507 else if (*t != '\0')
12511 if (rootshell && action == S_DFL) {
12514 if (iflag || minusc || sflag == 0)
12541 t = &sigmode[signo - 1];
12544 * current setting unknown
12546 if (sigaction(signo, 0, &act) == -1) {
12548 * Pretend it worked; maybe we should give a warning
12549 * here, but other shells don't. We don't alter
12550 * sigmode, so that we retry every time.
12554 if (act.sa_handler == SIG_IGN) {
12555 if (mflag && (signo == SIGTSTP ||
12556 signo == SIGTTIN || signo == SIGTTOU)) {
12557 *t = S_IGN; /* don't hard ignore these */
12561 *t = S_RESET; /* force to be set */
12564 if (*t == S_HARD_IGN || *t == action)
12568 act.sa_handler = onsig;
12571 act.sa_handler = SIG_IGN;
12574 act.sa_handler = SIG_DFL;
12578 sigemptyset(&act.sa_mask);
12579 sigaction(signo, &act, 0);
12590 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
12591 signal(signo, SIG_IGN);
12593 sigmode[signo - 1] = S_HARD_IGN;
12605 for (sm = sigmode ; sm < sigmode + NSIG - 1; sm++) {
12622 if (signo == SIGINT && trap[SIGINT] == NULL) {
12626 gotsig[signo - 1] = 1;
12633 * Called to execute a trap. Perhaps we should avoid entering new trap
12634 * handlers while we are executing a trap handler.
12643 for (i = 1 ; ; i++) {
12650 savestatus=exitstatus;
12651 evalstring(trap[i], 0);
12652 exitstatus=savestatus;
12661 * Controls whether the shell is interactive or not.
12669 static int is_interactive;
12671 if (on == is_interactive)
12674 setsignal(SIGQUIT);
12675 setsignal(SIGTERM);
12677 is_interactive = on;
12683 * Called to exit the shell.
12690 struct jmploc loc1, loc2;
12693 TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
12694 if (setjmp(loc1.loc)) {
12697 if (setjmp(loc2.loc)) {
12701 if ((p = trap[0]) != NULL && *p != '\0') {
12705 l1: handler = &loc2; /* probably unnecessary */
12714 static int decode_signal(const char *string, int minsig)
12718 if (is_number(string)) {
12719 signo = atoi(string);
12720 if (signo >= NSIG) {
12730 for (; signo < NSIG; signo++) {
12731 if (!strcasecmp(string, &(signal_names[signo])[3])) {
12735 if (!strcasecmp(string, signal_names[signo])) {
12742 /* $NetBSD: var.c,v 1.27 2001/02/04 19:52:07 christos Exp $ */
12744 #define VTABSIZE 39
12751 void (*func) __P((const char *));
12754 struct localvar *localvars;
12766 struct var voptind;
12768 static const char defpathvar[] =
12769 "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
12771 static const char defifsvar[] = "IFS= \t\n";
12773 static const char defifs[] = " \t\n";
12776 static const struct varinit varinit[] = {
12778 { &vatty, VSTRFIXED|VTEXTFIXED|VUNSET, "ATTY=",
12782 { &vifs, VSTRFIXED|VTEXTFIXED, defifsvar,
12784 { &vifs, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS=",
12787 { &vmail, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL=",
12789 { &vmpath, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH=",
12791 { &vpath, VSTRFIXED|VTEXTFIXED, defpathvar,
12794 * vps1 depends on uid
12796 { &vps2, VSTRFIXED|VTEXTFIXED, "PS2=> ",
12798 { &voptind, VSTRFIXED|VTEXTFIXED, "OPTIND=1",
12804 struct var *vartab[VTABSIZE];
12806 static struct var **hashvar __P((const char *));
12807 static void showvars __P((const char *, int, int));
12808 static struct var **findvar __P((struct var **, const char *));
12811 * Initialize the varable symbol tables and import the environment
12818 static char **environ;
12824 for (envp = environ ; *envp ; envp++) {
12825 if (strchr(*envp, '=')) {
12826 setvareq(*envp, VEXPORT|VTEXTFIXED);
12830 fmtstr(ppid, sizeof(ppid), "%d", (int) getppid());
12831 setvar("PPID", ppid, 0);
12837 * This routine initializes the builtin variables. It is called when the
12838 * shell is initialized and again when a shell procedure is spawned.
12843 const struct varinit *ip;
12847 for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
12848 if ((vp->flags & VEXPORT) == 0) {
12849 vpp = hashvar(ip->text);
12852 vp->text = strdup(ip->text);
12853 vp->flags = ip->flags;
12854 vp->func = ip->func;
12858 * PS1 depends on uid
12860 if ((vps1.flags & VEXPORT) == 0) {
12861 vpp = hashvar("PS1=");
12864 vps1.text = strdup(geteuid() ? "PS1=$ " : "PS1=# ");
12865 vps1.flags = VSTRFIXED|VTEXTFIXED;
12870 * Set the value of a variable. The flags argument is ored with the
12871 * flags of the variable. If val is NULL, the variable is unset.
12875 setvar(name, val, flags)
12876 const char *name, *val;
12892 if (! is_in_name(*p)) {
12893 if (*p == '\0' || *p == '=')
12899 namelen = p - name;
12901 error("%.*s: bad variable name", namelen, name);
12902 len = namelen + 2; /* 2 is space for '=' and '\0' */
12906 len += vallen = strlen(val);
12909 nameeq = ckmalloc(len);
12910 memcpy(nameeq, name, namelen);
12911 nameeq[namelen] = '=';
12913 memcpy(nameeq + namelen + 1, val, vallen + 1);
12915 nameeq[namelen + 1] = '\0';
12917 setvareq(nameeq, flags);
12924 * Same as setvar except that the variable and value are passed in
12925 * the first argument as name=value. Since the first argument will
12926 * be actually stored in the table, it should not be a string that
12935 struct var *vp, **vpp;
12938 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
12939 if ((vp = *findvar(vpp, s))) {
12940 if (vp->flags & VREADONLY) {
12941 size_t len = strchr(s, '=') - s;
12942 error("%.*s: is read only", len, s);
12946 if (vp->func && (flags & VNOFUNC) == 0)
12947 (*vp->func)(strchr(s, '=') + 1);
12949 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12952 vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET);
12953 vp->flags |= flags;
12957 * We could roll this to a function, to handle it as
12958 * a regular variable function callback, but why bother?
12960 if (iflag && (vp == &vmpath || (vp == &vmail && !mpathset())))
12966 vp = ckmalloc(sizeof (*vp));
12977 * Process a linked list of variable assignments.
12982 struct strlist *mylist;
12984 struct strlist *lp;
12987 for (lp = mylist ; lp ; lp = lp->next) {
12988 setvareq(savestr(lp->text), 0);
12996 * Find the value of a variable. Returns NULL if not set.
13005 if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
13006 return strchr(v->text, '=') + 1;
13014 * Search the environment of a builtin command.
13021 struct strlist *sp;
13023 for (sp = cmdenviron ; sp ; sp = sp->next) {
13024 if (varequal(sp->text, name))
13025 return strchr(sp->text, '=') + 1;
13027 return lookupvar(name);
13033 * Generate a list of exported variables. This routine is used to construct
13034 * the third argument to execve when executing a program.
13046 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
13047 for (vp = *vpp ; vp ; vp = vp->next)
13048 if (vp->flags & VEXPORT)
13051 ep = env = stalloc((nenv + 1) * sizeof *env);
13052 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
13053 for (vp = *vpp ; vp ; vp = vp->next)
13054 if (vp->flags & VEXPORT)
13063 * Called when a shell procedure is invoked to clear out nonexported
13064 * variables. It is also necessary to reallocate variables of with
13065 * VSTACK set since these are currently allocated on the stack.
13069 static void shprocvar __P((void));
13079 struct var *vp, **prev;
13081 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
13082 for (prev = vpp ; (vp = *prev) != NULL ; ) {
13083 if ((vp->flags & VEXPORT) == 0) {
13085 if ((vp->flags & VTEXTFIXED) == 0)
13087 if ((vp->flags & VSTRFIXED) == 0)
13090 if (vp->flags & VSTACK) {
13091 vp->text = savestr(vp->text);
13092 vp->flags &=~ VSTACK;
13104 * Command to list all variables which are set. Currently this command
13105 * is invoked from the set command when the set command is called without
13110 showvarscmd(argc, argv)
13114 showvars(nullstr, VUNSET, VUNSET);
13121 * The export and readonly commands.
13125 exportcmd(argc, argv)
13132 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
13135 listsetvar(cmdenviron);
13136 pflag = (nextopt("p") == 'p');
13137 if (argc > 1 && !pflag) {
13138 while ((name = *argptr++) != NULL) {
13139 if ((p = strchr(name, '=')) != NULL) {
13142 if ((vp = *findvar(hashvar(name), name))) {
13147 setvar(name, p, flag);
13151 showvars(argv[0], flag, 0);
13158 * The "local" command.
13162 localcmd(argc, argv)
13168 if (! in_function())
13169 error("Not in a function");
13170 while ((name = *argptr++) != NULL) {
13178 * Make a variable a local variable. When a variable is made local, it's
13179 * value and flags are saved in a localvar structure. The saved values
13180 * will be restored when the shell function returns. We handle the name
13181 * "-" as a special case.
13188 struct localvar *lvp;
13193 lvp = ckmalloc(sizeof (struct localvar));
13194 if (name[0] == '-' && name[1] == '\0') {
13196 p = ckmalloc(sizeof optlist);
13197 lvp->text = memcpy(p, optlist, sizeof optlist);
13200 vpp = hashvar(name);
13201 vp = *findvar(vpp, name);
13203 if (strchr(name, '='))
13204 setvareq(savestr(name), VSTRFIXED);
13206 setvar(name, NULL, VSTRFIXED);
13207 vp = *vpp; /* the new variable */
13209 lvp->flags = VUNSET;
13211 lvp->text = vp->text;
13212 lvp->flags = vp->flags;
13213 vp->flags |= VSTRFIXED|VTEXTFIXED;
13214 if (strchr(name, '='))
13215 setvareq(savestr(name), 0);
13219 lvp->next = localvars;
13226 * Called after a function returns.
13231 struct localvar *lvp;
13234 while ((lvp = localvars) != NULL) {
13235 localvars = lvp->next;
13237 if (vp == NULL) { /* $- saved */
13238 memcpy(optlist, lvp->text, sizeof optlist);
13240 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
13241 (void)unsetvar(vp->text);
13243 if ((vp->flags & VTEXTFIXED) == 0)
13245 vp->flags = lvp->flags;
13246 vp->text = lvp->text;
13254 setvarcmd(argc, argv)
13259 return unsetcmd(argc, argv);
13260 else if (argc == 3)
13261 setvar(argv[1], argv[2], 0);
13263 error("List assignment not implemented");
13269 * The unset builtin command. We unset the function before we unset the
13270 * variable to allow a function to be unset when there is a readonly variable
13271 * with the same name.
13275 unsetcmd(argc, argv)
13285 while ((i = nextopt("vf")) != '\0') {
13291 if (flg_func == 0 && flg_var == 0)
13294 for (ap = argptr; *ap ; ap++) {
13298 ret |= unsetvar(*ap);
13305 * Unset the specified variable.
13315 vpp = findvar(hashvar(s), s);
13318 if (vp->flags & VREADONLY)
13321 if (*(strchr(vp->text, '=') + 1) != '\0')
13322 setvar(s, nullstr, 0);
13323 vp->flags &= ~VEXPORT;
13324 vp->flags |= VUNSET;
13325 if ((vp->flags & VSTRFIXED) == 0) {
13326 if ((vp->flags & VTEXTFIXED) == 0)
13341 * Find the appropriate entry in the hash table from the name.
13344 static struct var **
13348 unsigned int hashval;
13350 hashval = ((unsigned char) *p) << 4;
13351 while (*p && *p != '=')
13352 hashval += (unsigned char) *p++;
13353 return &vartab[hashval % VTABSIZE];
13359 * Returns true if the two strings specify the same varable. The first
13360 * variable name is terminated by '='; the second may be terminated by
13361 * either '=' or '\0'.
13368 while (*p == *q++) {
13372 if (*p == '=' && *(q - 1) == '\0')
13378 showvars(const char *myprefix, int mask, int xor)
13382 const char *sep = myprefix == nullstr ? myprefix : spcstr;
13384 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
13385 for (vp = *vpp ; vp ; vp = vp->next) {
13386 if ((vp->flags & mask) ^ xor) {
13390 p = strchr(vp->text, '=') + 1;
13391 len = p - vp->text;
13392 p = single_quote(p);
13395 "%s%s%.*s%s\n", myprefix, sep, len,
13404 static struct var **
13405 findvar(struct var **vpp, const char *name)
13407 for (; *vpp; vpp = &(*vpp)->next) {
13408 if (varequal((*vpp)->text, name)) {
13416 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
13417 * This file contains code for the times builtin.
13418 * $Id: ash.c,v 1.3 2001/06/28 16:43:57 andersen Exp $
13420 static int timescmd (int argc, char **argv)
13423 long int clk_tck = sysconf(_SC_CLK_TCK);
13426 printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
13427 (int) (buf.tms_utime / clk_tck / 60),
13428 ((double) buf.tms_utime) / clk_tck,
13429 (int) (buf.tms_stime / clk_tck / 60),
13430 ((double) buf.tms_stime) / clk_tck,
13431 (int) (buf.tms_cutime / clk_tck / 60),
13432 ((double) buf.tms_cutime) / clk_tck,
13433 (int) (buf.tms_cstime / clk_tck / 60),
13434 ((double) buf.tms_cstime) / clk_tck);
13440 * Copyright (c) 1989, 1991, 1993, 1994
13441 * The Regents of the University of California. All rights reserved.
13443 * This code is derived from software contributed to Berkeley by
13444 * Kenneth Almquist.
13446 * Redistribution and use in source and binary forms, with or without
13447 * modification, are permitted provided that the following conditions
13449 * 1. Redistributions of source code must retain the above copyright
13450 * notice, this list of conditions and the following disclaimer.
13451 * 2. Redistributions in binary form must reproduce the above copyright
13452 * notice, this list of conditions and the following disclaimer in the
13453 * documentation and/or other materials provided with the distribution.
13455 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
13456 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
13458 * 4. Neither the name of the University nor the names of its contributors
13459 * may be used to endorse or promote products derived from this software
13460 * without specific prior written permission.
13462 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13463 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13464 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13465 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13466 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13467 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13468 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13469 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13470 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13471 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF