aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Andersen <andersen@codepoet.org>2001-07-10 06:09:16 +0000
committerEric Andersen <andersen@codepoet.org>2001-07-10 06:09:16 +0000
commit6248355c6f64cf2828ec0080930d3926e38d4c97 (patch)
treef51e43c461d7f6d0610f4e48967e844cd634720d
parent5a4a46a2519af1e79d931a856ee1a3b70e60d168 (diff)
downloadbusybox-w32-6248355c6f64cf2828ec0080930d3926e38d4c97.tar.gz
busybox-w32-6248355c6f64cf2828ec0080930d3926e38d4c97.tar.bz2
busybox-w32-6248355c6f64cf2828ec0080930d3926e38d4c97.zip
vodz' latest update to ash.c
-rw-r--r--ash.c2104
-rw-r--r--shell/ash.c2104
2 files changed, 1884 insertions, 2324 deletions
diff --git a/ash.c b/ash.c
index 4250f50e2..5756c6304 100644
--- a/ash.c
+++ b/ash.c
@@ -36,15 +36,14 @@
36/* These defines allow you to adjust the feature set to be compiled 36/* These defines allow you to adjust the feature set to be compiled
37 * into the ash shell. As a rule, enabling these options will make 37 * into the ash shell. As a rule, enabling these options will make
38 * ash get bigger... With all of these options off, ash adds about 38 * ash get bigger... With all of these options off, ash adds about
39 * 62k to busybox on an x86 system.*/ 39 * 60k to busybox on an x86 system.*/
40
41 40
42 41
43/* Enable job control. This allows you to run jobs in the background, 42/* Enable job control. This allows you to run jobs in the background,
44 * which is great when ash is being used as an interactive shell, but 43 * which is great when ash is being used as an interactive shell, but
45 * it completely useless for is all you are doing is running scripts. 44 * it completely useless for is all you are doing is running scripts.
46 * This adds about 2.5k on an x86 system. */ 45 * This adds about 2.5k on an x86 system. */
47#define JOBS 46#undef JOBS
48 47
49/* This enables alias support in ash. If you want to support things 48/* This enables alias support in ash. If you want to support things
50 * like "alias ls='ls -l'" with ash, enable this. This is only useful 49 * like "alias ls='ls -l'" with ash, enable this. This is only useful
@@ -56,12 +55,6 @@
56 * doesn't compile right now... */ 55 * doesn't compile right now... */
57#undef ASH_MATH_SUPPORT 56#undef ASH_MATH_SUPPORT
58 57
59/* This shell builtin is used to indicate how the shell would interpret
60 * what you give it. This command is only useful when debugging, and
61 * is obsolete anyways. Adds about 670 bytes... You probably want to
62 * leave this disabled. */
63#undef ASH_TYPE
64
65/* Getopts is used by shell procedures to parse positional parameters. 58/* Getopts is used by shell procedures to parse positional parameters.
66 * You probably want to leave this disabled, and use the busybox getopt 59 * You probably want to leave this disabled, and use the busybox getopt
67 * applet if you want to do this sort of thing. There are some scripts 60 * applet if you want to do this sort of thing. There are some scripts
@@ -71,13 +64,9 @@
71 64
72/* This allows you to override shell builtins and use whatever is on 65/* This allows you to override shell builtins and use whatever is on
73 * the filesystem. This is most useful when ash is acting as a 66 * the filesystem. This is most useful when ash is acting as a
74 * standalone shell. Adds about 320 bytes. */ 67 * standalone shell. Adds about 272 bytes. */
75#undef ASH_CMDCMD 68#undef ASH_CMDCMD
76 69
77/* This makes a few common apps that are usually part of busybox
78 * anyways to be used as builtins. This may cause these builtins to be
79 * a little bit faster, but leaving this disabled will save you 2k. */
80#undef ASH_BBAPPS_AS_BUILTINS
81 70
82/* Optimize size vs speed as size */ 71/* Optimize size vs speed as size */
83#define ASH_OPTIMIZE_FOR_SIZE 72#define ASH_OPTIMIZE_FOR_SIZE
@@ -87,8 +76,6 @@
87 * will generate a core dump. */ 76 * will generate a core dump. */
88#undef DEBUG 77#undef DEBUG
89 78
90
91
92/* These are here to work with glibc -- Don't change these... */ 79/* These are here to work with glibc -- Don't change these... */
93#undef FNMATCH_BROKEN 80#undef FNMATCH_BROKEN
94#undef GLOB_BROKEN 81#undef GLOB_BROKEN
@@ -105,7 +92,6 @@
105#include <setjmp.h> 92#include <setjmp.h>
106#include <signal.h> 93#include <signal.h>
107#include <stdarg.h> 94#include <stdarg.h>
108#include <stdbool.h>
109#include <stdio.h> 95#include <stdio.h>
110#include <stdlib.h> 96#include <stdlib.h>
111#include <string.h> 97#include <string.h>
@@ -217,7 +203,7 @@
217#define CTLENDARI '\207' 203#define CTLENDARI '\207'
218#define CTLQUOTEMARK '\210' 204#define CTLQUOTEMARK '\210'
219 205
220#define is_digit(c) ((((unsigned char)(c)) - '0') <= 9) 206#define is_digit(c) ((c)>='0' && (c)<='9')
221#define is_alpha(c) (((c) < CTLESC || (c) > CTLENDARI) && isalpha((unsigned char) (c))) 207#define is_alpha(c) (((c) < CTLESC || (c) > CTLENDARI) && isalpha((unsigned char) (c)))
222#define is_name(c) (((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalpha((unsigned char) (c)))) 208#define is_name(c) (((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalpha((unsigned char) (c))))
223#define is_in_name(c) (((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalnum((unsigned char) (c)))) 209#define is_in_name(c) (((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalnum((unsigned char) (c))))
@@ -262,7 +248,7 @@
262 * so we use _setjmp instead. 248 * so we use _setjmp instead.
263 */ 249 */
264 250
265#if !defined(__GLIBC__) 251#if defined(BSD)
266#define setjmp(jmploc) _setjmp(jmploc) 252#define setjmp(jmploc) _setjmp(jmploc)
267#define longjmp(jmploc, val) _longjmp(jmploc, val) 253#define longjmp(jmploc, val) _longjmp(jmploc, val)
268#endif 254#endif
@@ -662,18 +648,55 @@ struct shparam {
662 int optoff; /* used by getopts */ 648 int optoff; /* used by getopts */
663}; 649};
664 650
651/*
652 * When commands are first encountered, they are entered in a hash table.
653 * This ensures that a full path search will not have to be done for them
654 * on each invocation.
655 *
656 * We should investigate converting to a linear search, even though that
657 * would make the command name "hash" a misnomer.
658 */
659#define CMDTABLESIZE 31 /* should be prime */
660#define ARB 1 /* actual size determined at run time */
661
662
663
664struct tblentry {
665 struct tblentry *next; /* next entry in hash chain */
666 union param param; /* definition of builtin function */
667 short cmdtype; /* index identifying command */
668 char rehash; /* if set, cd done since entry created */
669 char cmdname[ARB]; /* name of command */
670};
671
672
673static struct tblentry *cmdtable[CMDTABLESIZE];
674static int builtinloc = -1; /* index in path of %builtin, or -1 */
675static int exerrno = 0; /* Last exec error */
676
677
678static void tryexec (char *, char **, char **);
679static void printentry (struct tblentry *, int);
680static void clearcmdentry (int);
681static struct tblentry *cmdlookup (const char *, int);
682static void delete_cmd_entry (void);
683static int path_change (const char *, int *);
684
685
665static void flushall (void); 686static void flushall (void);
666static void out2fmt (const char *, ...) 687static void out2fmt (const char *, ...)
667 __attribute__((__format__(__printf__,1,2))); 688 __attribute__((__format__(__printf__,1,2)));
668static void out1fmt (const char *, ...)
669 __attribute__((__format__(__printf__,1,2)));
670static int xwrite (int, const char *, int); 689static int xwrite (int, const char *, int);
671 690
672static void outstr (const char *p, FILE *file) { fputs(p, file); } 691static void outstr (const char *p, FILE *file) { fputs(p, file); }
673static void out1str(const char *p) { outstr(p, stdout); } 692static void out1str(const char *p) { outstr(p, stdout); }
674static void out2str(const char *p) { outstr(p, stderr); } 693static void out2str(const char *p) { outstr(p, stderr); }
675 694
695#ifndef ASH_OPTIMIZE_FOR_SIZE
676#define out2c(c) putc((c), stderr) 696#define out2c(c) putc((c), stderr)
697#else
698static void out2c(int c) { putc(c, stderr); }
699#endif
677 700
678/* syntax table used when not in quotes */ 701/* syntax table used when not in quotes */
679static const char basesyntax[257] = { 702static const char basesyntax[257] = {
@@ -1193,7 +1216,7 @@ struct localvar {
1193}; 1216};
1194 1217
1195 1218
1196#if defined(__GLIBC__) && !defined(FNMATCH_BROKEN) 1219#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
1197#define rmescapes(p) _rmescapes((p), 0) 1220#define rmescapes(p) _rmescapes((p), 0)
1198static char *_rmescapes (char *, int); 1221static char *_rmescapes (char *, int);
1199#else 1222#else
@@ -1316,8 +1339,8 @@ static void initvar (void);
1316static void setvar (const char *, const char *, int); 1339static void setvar (const char *, const char *, int);
1317static void setvareq (char *, int); 1340static void setvareq (char *, int);
1318static void listsetvar (struct strlist *); 1341static void listsetvar (struct strlist *);
1319static char *lookupvar (const char *); 1342static const char *lookupvar (const char *);
1320static char *bltinlookup (const char *); 1343static const char *bltinlookup (const char *);
1321static char **environment (void); 1344static char **environment (void);
1322static int showvarscmd (int, char **); 1345static int showvarscmd (int, char **);
1323static void mklocal (char *); 1346static void mklocal (char *);
@@ -1433,7 +1456,7 @@ printalias(const struct alias *ap) {
1433 char *p; 1456 char *p;
1434 1457
1435 p = single_quote(ap->val); 1458 p = single_quote(ap->val);
1436 out1fmt("alias %s=%s\n", ap->name, p); 1459 printf("alias %s=%s\n", ap->name, p);
1437 stunalloc(p); 1460 stunalloc(p);
1438} 1461}
1439 1462
@@ -1627,18 +1650,14 @@ static int timescmd (int, char **);
1627#ifdef ASH_MATH_SUPPORT 1650#ifdef ASH_MATH_SUPPORT
1628static int expcmd (int, char **); 1651static int expcmd (int, char **);
1629#endif 1652#endif
1630#ifdef ASH_TYPE
1631static int typecmd (int, char **); 1653static int typecmd (int, char **);
1632#endif
1633#ifdef ASH_GETOPTS 1654#ifdef ASH_GETOPTS
1634static int getoptscmd (int, char **); 1655static int getoptscmd (int, char **);
1635#endif 1656#endif
1636 1657
1637#ifndef BB_TRUE_FALSE 1658#ifndef BB_TRUE_FALSE
1638# ifdef ASH_BBAPPS_AS_BUILTINS
1639static int true_main (int, char **); 1659static int true_main (int, char **);
1640static int false_main (int, char **); 1660static int false_main (int, char **);
1641# endif
1642#endif 1661#endif
1643 1662
1644static void setpwd (const char *, int); 1663static void setpwd (const char *, int);
@@ -1669,7 +1688,7 @@ struct builtincmd {
1669 * have been warned. 1688 * have been warned.
1670 */ 1689 */
1671static const struct builtincmd builtincmds[] = { 1690static const struct builtincmd builtincmds[] = {
1672 { BUILTIN_SPECIAL ".", dotcmd }, 1691 { BUILTIN_SPECIAL ".", dotcmd }, /* first, see declare DOTCMD */
1673 { BUILTIN_SPECIAL ":", true_main }, 1692 { BUILTIN_SPECIAL ":", true_main },
1674#ifdef ASH_ALIAS 1693#ifdef ASH_ALIAS
1675 { BUILTIN_REG_ASSG "alias", aliascmd }, 1694 { BUILTIN_REG_ASSG "alias", aliascmd },
@@ -1680,9 +1699,7 @@ static const struct builtincmd builtincmds[] = {
1680 { BUILTIN_SPECIAL "break", breakcmd }, 1699 { BUILTIN_SPECIAL "break", breakcmd },
1681 { BUILTIN_SPECIAL "builtin", bltincmd }, 1700 { BUILTIN_SPECIAL "builtin", bltincmd },
1682 { BUILTIN_REGULAR "cd", cdcmd }, 1701 { BUILTIN_REGULAR "cd", cdcmd },
1683#ifdef ASH_BBAPPS_AS_BUILTINS
1684 { BUILTIN_NOSPEC "chdir", cdcmd }, 1702 { BUILTIN_NOSPEC "chdir", cdcmd },
1685#endif
1686#ifdef ASH_CMDCMD 1703#ifdef ASH_CMDCMD
1687 { BUILTIN_REGULAR "command", commandcmd }, 1704 { BUILTIN_REGULAR "command", commandcmd },
1688#endif 1705#endif
@@ -1694,9 +1711,7 @@ static const struct builtincmd builtincmds[] = {
1694 { BUILTIN_NOSPEC "exp", expcmd }, 1711 { BUILTIN_NOSPEC "exp", expcmd },
1695#endif 1712#endif
1696 { BUILTIN_SPEC_ASSG "export", exportcmd }, 1713 { BUILTIN_SPEC_ASSG "export", exportcmd },
1697#ifdef ASH_BBAPPS_AS_BUILTINS
1698 { BUILTIN_REGULAR "false", false_main }, 1714 { BUILTIN_REGULAR "false", false_main },
1699#endif
1700 { BUILTIN_REGULAR "fc", histcmd }, 1715 { BUILTIN_REGULAR "fc", histcmd },
1701#ifdef JOBS 1716#ifdef JOBS
1702 { BUILTIN_REGULAR "fg", fgcmd }, 1717 { BUILTIN_REGULAR "fg", fgcmd },
@@ -1725,12 +1740,8 @@ static const struct builtincmd builtincmds[] = {
1725 { BUILTIN_SPECIAL "shift", shiftcmd }, 1740 { BUILTIN_SPECIAL "shift", shiftcmd },
1726 { BUILTIN_SPECIAL "times", timescmd }, 1741 { BUILTIN_SPECIAL "times", timescmd },
1727 { BUILTIN_SPECIAL "trap", trapcmd }, 1742 { BUILTIN_SPECIAL "trap", trapcmd },
1728#ifdef ASH_BBAPPS_AS_BUILTINS
1729 { BUILTIN_REGULAR "true", true_main }, 1743 { BUILTIN_REGULAR "true", true_main },
1730#endif
1731#ifdef ASH_TYPE
1732 { BUILTIN_NOSPEC "type", typecmd }, 1744 { BUILTIN_NOSPEC "type", typecmd },
1733#endif
1734 { BUILTIN_NOSPEC "ulimit", ulimitcmd }, 1745 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
1735 { BUILTIN_REGULAR "umask", umaskcmd }, 1746 { BUILTIN_REGULAR "umask", umaskcmd },
1736#ifdef ASH_ALIAS 1747#ifdef ASH_ALIAS
@@ -1796,8 +1807,8 @@ static int jobctl;
1796#endif 1807#endif
1797static int intreceived; 1808static int intreceived;
1798 1809
1799static struct job *makejob (union node *, int); 1810static struct job *makejob (const union node *, int);
1800static int forkshell (struct job *, union node *, int); 1811static int forkshell (struct job *, const union node *, int);
1801static int waitforjob (struct job *); 1812static int waitforjob (struct job *);
1802 1813
1803static int docd (char *, int); 1814static int docd (char *, int);
@@ -1920,7 +1931,7 @@ docd(dest, print)
1920 updatepwd(badstat ? NULL : dest); 1931 updatepwd(badstat ? NULL : dest);
1921 INTON; 1932 INTON;
1922 if (print && iflag) 1933 if (print && iflag)
1923 out1fmt(snlfmt, curdir); 1934 printf(snlfmt, curdir);
1924 return 0; 1935 return 0;
1925} 1936}
1926 1937
@@ -2009,7 +2020,7 @@ pwdcmd(argc, argv)
2009 int argc; 2020 int argc;
2010 char **argv; 2021 char **argv;
2011{ 2022{
2012 out1fmt(snlfmt, curdir); 2023 printf(snlfmt, curdir);
2013 return 0; 2024 return 0;
2014} 2025}
2015#endif 2026#endif
@@ -2095,6 +2106,7 @@ exraise(int e)
2095 if (handler == NULL) 2106 if (handler == NULL)
2096 abort(); 2107 abort();
2097#endif 2108#endif
2109 flushall();
2098 exception = e; 2110 exception = e;
2099 longjmp(handler->loc, 1); 2111 longjmp(handler->loc, 1);
2100} 2112}
@@ -2156,7 +2168,6 @@ exverror(int cond, const char *msg, va_list ap)
2156 vfprintf(stderr, msg, ap); 2168 vfprintf(stderr, msg, ap);
2157 out2c('\n'); 2169 out2c('\n');
2158 } 2170 }
2159 flushall();
2160 exraise(cond); 2171 exraise(cond);
2161 /* NOTREACHED */ 2172 /* NOTREACHED */
2162} 2173}
@@ -2221,7 +2232,7 @@ exerror(va_alist)
2221 2232
2222struct errname { 2233struct errname {
2223 short errcode; /* error number */ 2234 short errcode; /* error number */
2224 short action; /* operation which encountered the error */ 2235 char action; /* operation which encountered the error */
2225}; 2236};
2226 2237
2227/* 2238/*
@@ -2337,19 +2348,12 @@ static int loopnest; /* current loop nesting level */
2337static int funcnest; /* depth of function calls */ 2348static int funcnest; /* depth of function calls */
2338 2349
2339 2350
2340
2341static struct strlist *cmdenviron; /* environment for builtin command */ 2351static struct strlist *cmdenviron; /* environment for builtin command */
2342static int exitstatus; /* exit status of last command */ 2352static int exitstatus; /* exit status of last command */
2343static int oexitstatus; /* saved exit status */ 2353static int oexitstatus; /* saved exit status */
2344 2354
2345 2355static void evalsubshell (const union node *, int);
2346static void evalloop (union node *, int);
2347static void evalfor (union node *, int);
2348static void evalcase (union node *, int);
2349static void evalsubshell (union node *, int);
2350static void expredir (union node *); 2356static void expredir (union node *);
2351static void evalpipe (union node *);
2352static void evalcommand (union node *, int);
2353static void prehash (union node *); 2357static void prehash (union node *);
2354static void eprintlist (struct strlist *); 2358static void eprintlist (struct strlist *);
2355 2359
@@ -2419,125 +2423,68 @@ evalstring(char *s, int flag)
2419 popstackmark(&smark); 2423 popstackmark(&smark);
2420} 2424}
2421 2425
2426static struct builtincmd *find_builtin (const char *);
2427static void expandarg (union node *, struct arglist *, int);
2428static void calcsize (const union node *);
2429static union node *copynode (const union node *);
2430
2431/*
2432 * Make a copy of a parse tree.
2433 */
2434
2435static int funcblocksize; /* size of structures in function */
2436static int funcstringsize; /* size of strings in node */
2437static pointer funcblock; /* block to allocate function from */
2438static char *funcstring; /* block to allocate strings from */
2439
2440
2441static inline union node *
2442copyfunc(union node *n)
2443{
2444 if (n == NULL)
2445 return NULL;
2446 funcblocksize = 0;
2447 funcstringsize = 0;
2448 calcsize(n);
2449 funcblock = ckmalloc(funcblocksize + funcstringsize);
2450 funcstring = (char *) funcblock + funcblocksize;
2451 return copynode(n);
2452}
2453
2422/* 2454/*
2423 * Evaluate a parse tree. The value is left in the global variable 2455 * Free a parse tree.
2424 * exitstatus.
2425 */ 2456 */
2426static struct builtincmd *find_builtin (const char *);
2427static void defun (char *, union node *);
2428 2457
2429static void 2458static void
2430evaltree(n, flags) 2459freefunc(union node *n)
2431 union node *n;
2432 int flags;
2433{ 2460{
2434 int checkexit = 0; 2461 if (n)
2435 if (n == NULL) { 2462 ckfree(n);
2436 TRACE(("evaltree(NULL) called\n")); 2463}
2437 goto out;
2438 }
2439 TRACE(("evaltree(0x%lx: %d) called\n", (long)n, n->type));
2440 switch (n->type) {
2441 case NSEMI:
2442 evaltree(n->nbinary.ch1, flags & EV_TESTED);
2443 if (evalskip)
2444 goto out;
2445 evaltree(n->nbinary.ch2, flags);
2446 break;
2447 case NAND:
2448 evaltree(n->nbinary.ch1, EV_TESTED);
2449 if (evalskip || exitstatus != 0)
2450 goto out;
2451 evaltree(n->nbinary.ch2, flags);
2452 break;
2453 case NOR:
2454 evaltree(n->nbinary.ch1, EV_TESTED);
2455 if (evalskip || exitstatus == 0)
2456 goto out;
2457 evaltree(n->nbinary.ch2, flags);
2458 break;
2459 case NREDIR:
2460 expredir(n->nredir.redirect);
2461 redirect(n->nredir.redirect, REDIR_PUSH);
2462 evaltree(n->nredir.n, flags);
2463 popredir();
2464 break;
2465 case NSUBSHELL:
2466 evalsubshell(n, flags);
2467 break;
2468 case NBACKGND:
2469 evalsubshell(n, flags);
2470 break;
2471 case NIF: {
2472 evaltree(n->nif.test, EV_TESTED);
2473 if (evalskip)
2474 goto out;
2475 if (exitstatus == 0)
2476 evaltree(n->nif.ifpart, flags);
2477 else if (n->nif.elsepart)
2478 evaltree(n->nif.elsepart, flags);
2479 else
2480 exitstatus = 0;
2481 break;
2482 }
2483 case NWHILE:
2484 case NUNTIL:
2485 evalloop(n, flags);
2486 break;
2487 case NFOR:
2488 evalfor(n, flags);
2489 break;
2490 case NCASE:
2491 evalcase(n, flags);
2492 break;
2493 case NDEFUN: {
2494 struct builtincmd *bcmd;
2495 if (
2496 (bcmd = find_builtin(n->narg.text)) &&
2497 IS_BUILTIN_SPECIAL(bcmd)
2498 ) {
2499 out2fmt("%s is a special built-in\n", n->narg.text);
2500 exitstatus = 1;
2501 break;
2502 }
2503 defun(n->narg.text, n->narg.next);
2504 exitstatus = 0;
2505 break;
2506 }
2507 case NNOT:
2508 evaltree(n->nnot.com, EV_TESTED);
2509 exitstatus = !exitstatus;
2510 break;
2511 2464
2512 case NPIPE: 2465
2513 evalpipe(n); 2466/*
2514 checkexit = 1; 2467 * Add a new command entry, replacing any existing command entry for
2515 break; 2468 * the same name.
2516 case NCMD: 2469 */
2517 evalcommand(n, flags); 2470
2518 checkexit = 1; 2471static inline void
2519 break; 2472addcmdentry(char *name, struct cmdentry *entry)
2520#ifdef DEBUG 2473{
2521 default: 2474 struct tblentry *cmdp;
2522 out1fmt("Node type = %d\n", n->type); 2475
2523 break; 2476 INTOFF;
2524#endif 2477 cmdp = cmdlookup(name, 1);
2478 if (cmdp->cmdtype == CMDFUNCTION) {
2479 freefunc(cmdp->param.func);
2525 } 2480 }
2526out: 2481 cmdp->cmdtype = entry->cmdtype;
2527 if (pendingsigs) 2482 cmdp->param = entry->u;
2528 dotrap(); 2483 INTON;
2529 if (
2530 flags & EV_EXIT ||
2531 (checkexit && eflag && exitstatus && !(flags & EV_TESTED))
2532 )
2533 exitshell(exitstatus);
2534} 2484}
2535 2485
2536 2486static inline void
2537static void 2487evalloop(const union node *n, int flags)
2538evalloop(n, flags)
2539 union node *n;
2540 int flags;
2541{ 2488{
2542 int status; 2489 int status;
2543 2490
@@ -2570,13 +2517,8 @@ skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
2570 exitstatus = status; 2517 exitstatus = status;
2571} 2518}
2572 2519
2573static void expandarg (union node *, struct arglist *, int);
2574static void fixredir(union node *n, const char *text, int err);
2575
2576static void 2520static void
2577evalfor(n, flags) 2521evalfor(const union node *n, int flags)
2578 union node *n;
2579 int flags;
2580{ 2522{
2581 struct arglist arglist; 2523 struct arglist arglist;
2582 union node *argp; 2524 union node *argp;
@@ -2613,11 +2555,8 @@ out:
2613 popstackmark(&smark); 2555 popstackmark(&smark);
2614} 2556}
2615 2557
2616 2558static inline void
2617static void 2559evalcase(const union node *n, int flags)
2618evalcase(n, flags)
2619 union node *n;
2620 int flags;
2621{ 2560{
2622 union node *cp; 2561 union node *cp;
2623 union node *patp; 2562 union node *patp;
@@ -2643,75 +2582,13 @@ out:
2643} 2582}
2644 2583
2645/* 2584/*
2646 * Kick off a subshell to evaluate a tree.
2647 */
2648
2649static void
2650evalsubshell(n, flags)
2651 union node *n;
2652 int flags;
2653{
2654 struct job *jp;
2655 int backgnd = (n->type == NBACKGND);
2656
2657 expredir(n->nredir.redirect);
2658 jp = makejob(n, 1);
2659 if (forkshell(jp, n, backgnd) == 0) {
2660 if (backgnd)
2661 flags &=~ EV_TESTED;
2662 redirect(n->nredir.redirect, 0);
2663 evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */
2664 }
2665 if (! backgnd) {
2666 INTOFF;
2667 exitstatus = waitforjob(jp);
2668 INTON;
2669 }
2670}
2671
2672
2673/*
2674 * Compute the names of the files in a redirection list.
2675 */
2676
2677static void
2678expredir(n)
2679 union node *n;
2680{
2681 union node *redir;
2682
2683 for (redir = n ; redir ; redir = redir->nfile.next) {
2684 struct arglist fn;
2685 fn.lastp = &fn.list;
2686 oexitstatus = exitstatus;
2687 switch (redir->type) {
2688 case NFROMTO:
2689 case NFROM:
2690 case NTO:
2691 case NAPPEND:
2692 case NTOOV:
2693 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
2694 redir->nfile.expfname = fn.list->text;
2695 break;
2696 case NFROMFD:
2697 case NTOFD:
2698 if (redir->ndup.vname) {
2699 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
2700 fixredir(redir, fn.list->text, 1);
2701 }
2702 break;
2703 }
2704 }
2705}
2706
2707/*
2708 * Evaluate a pipeline. All the processes in the pipeline are children 2585 * Evaluate a pipeline. All the processes in the pipeline are children
2709 * of the process creating the pipeline. (This differs from some versions 2586 * of the process creating the pipeline. (This differs from some versions
2710 * of the shell, which make the last process in a pipeline the parent 2587 * of the shell, which make the last process in a pipeline the parent
2711 * of all the rest.) 2588 * of all the rest.)
2712 */ 2589 */
2713 2590
2714static void 2591static inline void
2715evalpipe(n) 2592evalpipe(n)
2716 union node *n; 2593 union node *n;
2717{ 2594{
@@ -2773,61 +2650,6 @@ evalpipe(n)
2773 } 2650 }
2774} 2651}
2775 2652
2776
2777
2778/*
2779 * Execute a command inside back quotes. If it's a builtin command, we
2780 * want to save its output in a block obtained from malloc. Otherwise
2781 * we fork off a subprocess and get the output of the command via a pipe.
2782 * Should be called with interrupts off.
2783 */
2784
2785static void
2786evalbackcmd(union node *n, struct backcmd *result)
2787{
2788 int pip[2];
2789 struct job *jp;
2790 struct stackmark smark; /* unnecessary */
2791
2792 setstackmark(&smark);
2793 result->fd = -1;
2794 result->buf = NULL;
2795 result->nleft = 0;
2796 result->jp = NULL;
2797 if (n == NULL) {
2798 exitstatus = 0;
2799 goto out;
2800 }
2801 exitstatus = 0;
2802 if (pipe(pip) < 0)
2803 error("Pipe call failed");
2804 jp = makejob(n, 1);
2805 if (forkshell(jp, n, FORK_NOJOB) == 0) {
2806 FORCEINTON;
2807 close(pip[0]);
2808 if (pip[1] != 1) {
2809 close(1);
2810 dup_as_newfd(pip[1], 1);
2811 close(pip[1]);
2812 }
2813 eflag = 0;
2814 evaltree(n, EV_EXIT);
2815 }
2816 close(pip[1]);
2817 result->fd = pip[0];
2818 result->jp = jp;
2819out:
2820 popstackmark(&smark);
2821 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
2822 result->fd, result->buf, result->nleft, result->jp));
2823}
2824
2825
2826
2827/*
2828 * Execute a simple command.
2829 */
2830
2831static void find_command (const char *, struct cmdentry *, int, const char *); 2653static void find_command (const char *, struct cmdentry *, int, const char *);
2832 2654
2833static int 2655static int
@@ -2841,6 +2663,7 @@ isassignment(const char *word) {
2841 return *word == '='; 2663 return *word == '=';
2842} 2664}
2843 2665
2666
2844static void 2667static void
2845evalcommand(union node *cmd, int flags) 2668evalcommand(union node *cmd, int flags)
2846{ 2669{
@@ -2892,7 +2715,7 @@ evalcommand(union node *cmd, int flags)
2892 } 2715 }
2893 if (argp) { 2716 if (argp) {
2894 struct builtincmd *bcmd; 2717 struct builtincmd *bcmd;
2895 bool pseudovarflag; 2718 int pseudovarflag;
2896 bcmd = find_builtin(arglist.list->text); 2719 bcmd = find_builtin(arglist.list->text);
2897 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd); 2720 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
2898 for (; argp; argp = argp->narg.next) { 2721 for (; argp; argp = argp->narg.next) {
@@ -3144,9 +2967,234 @@ out:
3144 popstackmark(&smark); 2967 popstackmark(&smark);
3145} 2968}
3146 2969
2970/*
2971 * Evaluate a parse tree. The value is left in the global variable
2972 * exitstatus.
2973 */
2974static void
2975evaltree(n, flags)
2976 union node *n;
2977 int flags;
2978{
2979 int checkexit = 0;
2980 if (n == NULL) {
2981 TRACE(("evaltree(NULL) called\n"));
2982 goto out;
2983 }
2984 TRACE(("evaltree(0x%lx: %d) called\n", (long)n, n->type));
2985 switch (n->type) {
2986 case NSEMI:
2987 evaltree(n->nbinary.ch1, flags & EV_TESTED);
2988 if (evalskip)
2989 goto out;
2990 evaltree(n->nbinary.ch2, flags);
2991 break;
2992 case NAND:
2993 evaltree(n->nbinary.ch1, EV_TESTED);
2994 if (evalskip || exitstatus != 0)
2995 goto out;
2996 evaltree(n->nbinary.ch2, flags);
2997 break;
2998 case NOR:
2999 evaltree(n->nbinary.ch1, EV_TESTED);
3000 if (evalskip || exitstatus == 0)
3001 goto out;
3002 evaltree(n->nbinary.ch2, flags);
3003 break;
3004 case NREDIR:
3005 expredir(n->nredir.redirect);
3006 redirect(n->nredir.redirect, REDIR_PUSH);
3007 evaltree(n->nredir.n, flags);
3008 popredir();
3009 break;
3010 case NSUBSHELL:
3011 evalsubshell(n, flags);
3012 break;
3013 case NBACKGND:
3014 evalsubshell(n, flags);
3015 break;
3016 case NIF: {
3017 evaltree(n->nif.test, EV_TESTED);
3018 if (evalskip)
3019 goto out;
3020 if (exitstatus == 0)
3021 evaltree(n->nif.ifpart, flags);
3022 else if (n->nif.elsepart)
3023 evaltree(n->nif.elsepart, flags);
3024 else
3025 exitstatus = 0;
3026 break;
3027 }
3028 case NWHILE:
3029 case NUNTIL:
3030 evalloop(n, flags);
3031 break;
3032 case NFOR:
3033 evalfor(n, flags);
3034 break;
3035 case NCASE:
3036 evalcase(n, flags);
3037 break;
3038 case NDEFUN: {
3039 struct builtincmd *bcmd;
3040 struct cmdentry entry;
3041 if (
3042 (bcmd = find_builtin(n->narg.text)) &&
3043 IS_BUILTIN_SPECIAL(bcmd)
3044 ) {
3045 out2fmt("%s is a special built-in\n", n->narg.text);
3046 exitstatus = 1;
3047 break;
3048 }
3049 entry.cmdtype = CMDFUNCTION;
3050 entry.u.func = copyfunc(n->narg.next);
3051 addcmdentry(n->narg.text, &entry);
3052 exitstatus = 0;
3053 break;
3054 }
3055 case NNOT:
3056 evaltree(n->nnot.com, EV_TESTED);
3057 exitstatus = !exitstatus;
3058 break;
3059
3060 case NPIPE:
3061 evalpipe(n);
3062 checkexit = 1;
3063 break;
3064 case NCMD:
3065 evalcommand(n, flags);
3066 checkexit = 1;
3067 break;
3068#ifdef DEBUG
3069 default:
3070 printf("Node type = %d\n", n->type);
3071 break;
3072#endif
3073 }
3074out:
3075 if (pendingsigs)
3076 dotrap();
3077 if (
3078 flags & EV_EXIT ||
3079 (checkexit && eflag && exitstatus && !(flags & EV_TESTED))
3080 )
3081 exitshell(exitstatus);
3082}
3083
3084/*
3085 * Kick off a subshell to evaluate a tree.
3086 */
3087
3088static void
3089evalsubshell(const union node *n, int flags)
3090{
3091 struct job *jp;
3092 int backgnd = (n->type == NBACKGND);
3093
3094 expredir(n->nredir.redirect);
3095 jp = makejob(n, 1);
3096 if (forkshell(jp, n, backgnd) == 0) {
3097 if (backgnd)
3098 flags &=~ EV_TESTED;
3099 redirect(n->nredir.redirect, 0);
3100 evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */
3101 }
3102 if (! backgnd) {
3103 INTOFF;
3104 exitstatus = waitforjob(jp);
3105 INTON;
3106 }
3107}
3108
3109/*
3110 * Compute the names of the files in a redirection list.
3111 */
3112
3113static void fixredir(union node *n, const char *text, int err);
3114
3115static void
3116expredir(union node *n)
3117{
3118 union node *redir;
3119
3120 for (redir = n ; redir ; redir = redir->nfile.next) {
3121 struct arglist fn;
3122 fn.lastp = &fn.list;
3123 oexitstatus = exitstatus;
3124 switch (redir->type) {
3125 case NFROMTO:
3126 case NFROM:
3127 case NTO:
3128 case NAPPEND:
3129 case NTOOV:
3130 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
3131 redir->nfile.expfname = fn.list->text;
3132 break;
3133 case NFROMFD:
3134 case NTOFD:
3135 if (redir->ndup.vname) {
3136 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
3137 fixredir(redir, fn.list->text, 1);
3138 }
3139 break;
3140 }
3141 }
3142}
3147 3143
3148 3144
3149/* 3145/*
3146 * Execute a command inside back quotes. If it's a builtin command, we
3147 * want to save its output in a block obtained from malloc. Otherwise
3148 * we fork off a subprocess and get the output of the command via a pipe.
3149 * Should be called with interrupts off.
3150 */
3151
3152static void
3153evalbackcmd(union node *n, struct backcmd *result)
3154{
3155 int pip[2];
3156 struct job *jp;
3157 struct stackmark smark; /* unnecessary */
3158
3159 setstackmark(&smark);
3160 result->fd = -1;
3161 result->buf = NULL;
3162 result->nleft = 0;
3163 result->jp = NULL;
3164 if (n == NULL) {
3165 exitstatus = 0;
3166 goto out;
3167 }
3168 exitstatus = 0;
3169 if (pipe(pip) < 0)
3170 error("Pipe call failed");
3171 jp = makejob(n, 1);
3172 if (forkshell(jp, n, FORK_NOJOB) == 0) {
3173 FORCEINTON;
3174 close(pip[0]);
3175 if (pip[1] != 1) {
3176 close(1);
3177 dup_as_newfd(pip[1], 1);
3178 close(pip[1]);
3179 }
3180 eflag = 0;
3181 evaltree(n, EV_EXIT);
3182 }
3183 close(pip[1]);
3184 result->fd = pip[0];
3185 result->jp = jp;
3186out:
3187 popstackmark(&smark);
3188 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
3189 result->fd, result->buf, result->nleft, result->jp));
3190}
3191
3192
3193/*
3194 * Execute a simple command.
3195 */
3196
3197/*
3150 * Search for a command. This is called before we fork so that the 3198 * Search for a command. This is called before we fork so that the
3151 * location of the command will be available in the parent as well as 3199 * location of the command will be available in the parent as well as
3152 * the child. The check for "goodname" is an overly conservative 3200 * the child. The check for "goodname" is an overly conservative
@@ -3166,7 +3214,6 @@ prehash(n)
3166} 3214}
3167 3215
3168 3216
3169
3170/* 3217/*
3171 * Builtin commands. Builtin commands whose functions are closely 3218 * Builtin commands. Builtin commands whose functions are closely
3172 * tied to evaluation are implemented here. 3219 * tied to evaluation are implemented here.
@@ -3244,7 +3291,6 @@ returncmd(argc, argv)
3244 3291
3245 3292
3246#ifndef BB_TRUE_FALSE 3293#ifndef BB_TRUE_FALSE
3247#ifdef ASH_BBAPPS_AS_BUILTINS
3248static int 3294static int
3249false_main(argc, argv) 3295false_main(argc, argv)
3250 int argc; 3296 int argc;
@@ -3262,7 +3308,6 @@ true_main(argc, argv)
3262 return 0; 3308 return 0;
3263} 3309}
3264#endif 3310#endif
3265#endif
3266 3311
3267/* 3312/*
3268 * Controls whether the shell is interactive or not. 3313 * Controls whether the shell is interactive or not.
@@ -3326,43 +3371,6 @@ eprintlist(struct strlist *sp)
3326 out2fmt(" %s",sp->text); 3371 out2fmt(" %s",sp->text);
3327 } 3372 }
3328} 3373}
3329/*
3330 * When commands are first encountered, they are entered in a hash table.
3331 * This ensures that a full path search will not have to be done for them
3332 * on each invocation.
3333 *
3334 * We should investigate converting to a linear search, even though that
3335 * would make the command name "hash" a misnomer.
3336 */
3337#define CMDTABLESIZE 31 /* should be prime */
3338#define ARB 1 /* actual size determined at run time */
3339
3340
3341
3342struct tblentry {
3343 struct tblentry *next; /* next entry in hash chain */
3344 union param param; /* definition of builtin function */
3345 short cmdtype; /* index identifying command */
3346 char rehash; /* if set, cd done since entry created */
3347 char cmdname[ARB]; /* name of command */
3348};
3349
3350
3351static struct tblentry *cmdtable[CMDTABLESIZE];
3352static int builtinloc = -1; /* index in path of %builtin, or -1 */
3353static int exerrno = 0; /* Last exec error */
3354
3355
3356static void tryexec (char *, char **, char **);
3357static void printentry (struct tblentry *, int);
3358static void clearcmdentry (int);
3359static struct tblentry *cmdlookup (const char *, int);
3360static void delete_cmd_entry (void);
3361#ifdef ASH_TYPE
3362static int describe_command (char *, int);
3363#endif
3364static int path_change (const char *, int *);
3365
3366 3374
3367/* 3375/*
3368 * Exec a program. Never returns. If you change this routine, you may 3376 * Exec a program. Never returns. If you change this routine, you may
@@ -3492,7 +3500,6 @@ initshellproc(void) {
3492 3500
3493static int preadbuffer(void); 3501static int preadbuffer(void);
3494static void pushfile (void); 3502static void pushfile (void);
3495static int preadfd (void);
3496 3503
3497/* 3504/*
3498 * Read a character from the script, returning PEOF on end of file. 3505 * Read a character from the script, returning PEOF on end of file.
@@ -3632,11 +3639,8 @@ setinputfile(const char *fname, int push)
3632 3639
3633 3640
3634static void 3641static void
3635tryexec(cmd, argv, envp) 3642tryexec(char *cmd, char **argv, char **envp)
3636 char *cmd; 3643{
3637 char **argv;
3638 char **envp;
3639 {
3640 int e; 3644 int e;
3641 3645
3642#ifdef BB_FEATURE_SH_STANDALONE_SHELL 3646#ifdef BB_FEATURE_SH_STANDALONE_SHELL
@@ -3650,7 +3654,7 @@ tryexec(cmd, argv, envp)
3650 for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++) 3654 for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++)
3651 putenv(*argv_l); 3655 putenv(*argv_l);
3652 argv_l=argv; 3656 argv_l=argv;
3653 for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++); 3657 for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++)
3654 optind = 1; 3658 optind = 1;
3655 run_applet_by_name(name, argc_l, argv); 3659 run_applet_by_name(name, argc_l, argv);
3656#endif 3660#endif
@@ -3718,6 +3722,25 @@ padvance(const char **path, const char *name)
3718 return stalloc(len); 3722 return stalloc(len);
3719} 3723}
3720 3724
3725/*
3726 * Wrapper around strcmp for qsort/bsearch/...
3727 */
3728static int
3729pstrcmp(const void *a, const void *b)
3730{
3731 return strcmp((const char *) a, *(const char *const *) b);
3732}
3733
3734/*
3735 * Find a keyword is in a sorted array.
3736 */
3737
3738static const char *const *
3739findkwd(const char *s)
3740{
3741 return bsearch(s, parsekwd, sizeof(parsekwd) / sizeof(const char *),
3742 sizeof(const char *), pstrcmp);
3743}
3721 3744
3722 3745
3723/*** Command hashing code ***/ 3746/*** Command hashing code ***/
@@ -3734,14 +3757,17 @@ hashcmd(argc, argv)
3734 int verbose; 3757 int verbose;
3735 struct cmdentry entry; 3758 struct cmdentry entry;
3736 char *name; 3759 char *name;
3760#ifdef ASH_ALIAS
3761 const struct alias *ap;
3762#endif
3737 3763
3738 verbose = 0; 3764 verbose = 0;
3739 while ((c = nextopt("rv")) != '\0') { 3765 while ((c = nextopt("rvV")) != '\0') {
3740 if (c == 'r') { 3766 if (c == 'r') {
3741 clearcmdentry(0); 3767 clearcmdentry(0);
3742 return 0; 3768 return 0;
3743 } else if (c == 'v') { 3769 } else if (c == 'v' || c == 'V') {
3744 verbose++; 3770 verbose = c;
3745 } 3771 }
3746 } 3772 }
3747 if (*argptr == NULL) { 3773 if (*argptr == NULL) {
@@ -3755,24 +3781,41 @@ hashcmd(argc, argv)
3755 return 0; 3781 return 0;
3756 } 3782 }
3757 c = 0; 3783 c = 0;
3758 while ((name = *argptr) != NULL) { 3784 while ((name = *argptr++) != NULL) {
3759 if ((cmdp = cmdlookup(name, 0)) != NULL 3785 if ((cmdp = cmdlookup(name, 0)) != NULL
3760 && (cmdp->cmdtype == CMDNORMAL 3786 && (cmdp->cmdtype == CMDNORMAL
3761 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))) 3787 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
3762 delete_cmd_entry(); 3788 delete_cmd_entry();
3789#ifdef ASH_ALIAS
3790 /* Then look at the aliases */
3791 if ((ap = lookupalias(name, 0)) != NULL) {
3792 if (verbose=='v')
3793 printf("%s is an alias for %s\n", name, ap->val);
3794 else
3795 printalias(ap);
3796 continue;
3797 }
3798#endif
3799 /* First look at the keywords */
3800 if (findkwd(name)!=0) {
3801 if (verbose=='v')
3802 printf("%s is a shell keyword\n", name);
3803 else
3804 printf(snlfmt, name);
3805 continue;
3806 }
3807
3763 find_command(name, &entry, DO_ERR, pathval()); 3808 find_command(name, &entry, DO_ERR, pathval());
3764 if (entry.cmdtype == CMDUNKNOWN) c = 1; 3809 if (entry.cmdtype == CMDUNKNOWN) c = 1;
3765 else if (verbose) { 3810 else if (verbose) {
3766 cmdp = cmdlookup(name, 0); 3811 cmdp = cmdlookup(name, 0);
3767 if (cmdp) printentry(cmdp, verbose); 3812 if (cmdp) printentry(cmdp, verbose=='v');
3768 flushall(); 3813 flushall();
3769 } 3814 }
3770 argptr++;
3771 } 3815 }
3772 return c; 3816 return c;
3773} 3817}
3774 3818
3775
3776static void 3819static void
3777printentry(cmdp, verbose) 3820printentry(cmdp, verbose)
3778 struct tblentry *cmdp; 3821 struct tblentry *cmdp;
@@ -3782,6 +3825,7 @@ printentry(cmdp, verbose)
3782 const char *path; 3825 const char *path;
3783 char *name; 3826 char *name;
3784 3827
3828 printf("%s%s", cmdp->cmdname, (verbose ? " is " : ""));
3785 if (cmdp->cmdtype == CMDNORMAL) { 3829 if (cmdp->cmdtype == CMDNORMAL) {
3786 idx = cmdp->param.index; 3830 idx = cmdp->param.index;
3787 path = pathval(); 3831 path = pathval();
@@ -3789,15 +3833,17 @@ printentry(cmdp, verbose)
3789 name = padvance(&path, cmdp->cmdname); 3833 name = padvance(&path, cmdp->cmdname);
3790 stunalloc(name); 3834 stunalloc(name);
3791 } while (--idx >= 0); 3835 } while (--idx >= 0);
3792 out1str(name); 3836 if(verbose)
3837 out1str(name);
3793 } else if (cmdp->cmdtype == CMDBUILTIN) { 3838 } else if (cmdp->cmdtype == CMDBUILTIN) {
3794 out1fmt("builtin %s", cmdp->cmdname); 3839 if(verbose)
3840 out1str("a shell builtin");
3795 } else if (cmdp->cmdtype == CMDFUNCTION) { 3841 } else if (cmdp->cmdtype == CMDFUNCTION) {
3796 out1fmt("function %s", cmdp->cmdname);
3797 if (verbose) { 3842 if (verbose) {
3798 INTOFF; 3843 INTOFF;
3844 out1str("a function\n");
3799 name = commandtext(cmdp->param.func); 3845 name = commandtext(cmdp->param.func);
3800 out1fmt(" %s", name); 3846 printf("%s() {\n %s\n}", cmdp->cmdname, name);
3801 ckfree(name); 3847 ckfree(name);
3802 INTON; 3848 INTON;
3803 } 3849 }
@@ -3806,7 +3852,7 @@ printentry(cmdp, verbose)
3806 error("internal error: cmdtype %d", cmdp->cmdtype); 3852 error("internal error: cmdtype %d", cmdp->cmdtype);
3807#endif 3853#endif
3808 } 3854 }
3809 out1fmt(snlfmt, cmdp->rehash ? "*" : nullstr); 3855 printf(snlfmt, cmdp->rehash ? "*" : nullstr);
3810} 3856}
3811 3857
3812 3858
@@ -3817,15 +3863,11 @@ printentry(cmdp, verbose)
3817static int helpcmd(int argc, char** argv) 3863static int helpcmd(int argc, char** argv)
3818{ 3864{
3819 int col, i; 3865 int col, i;
3820 const struct builtincmd *x;
3821 3866
3822 printf("\nBuilt-in commands:\n"); 3867 printf("\nBuilt-in commands:\n-------------------\n");
3823 printf("-------------------\n"); 3868 for (col=0, i=0; i < NUMBUILTINS; i++) {
3824 for (col=0, i=0, x = builtincmds; i < NUMBUILTINS; x++, i++) { 3869 col += printf("%c%s", ((col == 0) ? '\t' : ' '),
3825 if (!x->name || ! (x->name+1)) 3870 builtincmds[i].name+1);
3826 continue;
3827 col += printf("%s%s", ((col == 0) ? "\t" : " "),
3828 (x->name+1));
3829 if (col > 60) { 3871 if (col > 60) {
3830 printf("\n"); 3872 printf("\n");
3831 col = 0; 3873 col = 0;
@@ -3833,16 +3875,13 @@ static int helpcmd(int argc, char** argv)
3833 } 3875 }
3834#ifdef BB_FEATURE_SH_STANDALONE_SHELL 3876#ifdef BB_FEATURE_SH_STANDALONE_SHELL
3835 { 3877 {
3836 const struct BB_applet *applet;
3837 extern const struct BB_applet applets[]; 3878 extern const struct BB_applet applets[];
3838 extern const size_t NUM_APPLETS; 3879 extern const size_t NUM_APPLETS;
3839 3880
3840 for (i=0, applet = applets; i < NUM_APPLETS; applet++, i++) { 3881 for (i=0; i < NUM_APPLETS; i++) {
3841 if (!applet->name) 3882
3842 continue; 3883 col += printf("%c%s", ((col == 0) ? '\t' : ' '),
3843 3884 applets[i].name);
3844 col += printf("%s%s", ((col == 0) ? "\t" : " "),
3845 applet->name);
3846 if (col > 60) { 3885 if (col > 60) {
3847 printf("\n"); 3886 printf("\n");
3848 col = 0; 3887 col = 0;
@@ -3854,8 +3893,6 @@ static int helpcmd(int argc, char** argv)
3854 return EXIT_SUCCESS; 3893 return EXIT_SUCCESS;
3855} 3894}
3856 3895
3857
3858
3859/* 3896/*
3860 * Resolve a command name. If you change this routine, you may have to 3897 * Resolve a command name. If you change this routine, you may have to
3861 * change the shellexec routine as well. 3898 * change the shellexec routine as well.
@@ -3875,7 +3912,7 @@ find_command(const char *name, struct cmdentry *entry, int act, const char *path
3875 int bltin; 3912 int bltin;
3876 int firstchange; 3913 int firstchange;
3877 int updatetbl; 3914 int updatetbl;
3878 bool regular; 3915 int regular;
3879 struct builtincmd *bcmd; 3916 struct builtincmd *bcmd;
3880 3917
3881 /* If name contains a slash, don't use the hash table */ 3918 /* If name contains a slash, don't use the hash table */
@@ -4138,17 +4175,6 @@ clearcmdentry(firstchange)
4138 INTON; 4175 INTON;
4139} 4176}
4140 4177
4141/*
4142 * Free a parse tree.
4143 */
4144
4145static void
4146freefunc(union node *n)
4147{
4148 if (n)
4149 ckfree(n);
4150}
4151
4152 4178
4153/* 4179/*
4154 * Delete all functions. 4180 * Delete all functions.
@@ -4238,42 +4264,37 @@ delete_cmd_entry() {
4238 4264
4239 4265
4240 4266
4241/*
4242 * Add a new command entry, replacing any existing command entry for
4243 * the same name.
4244 */
4245 4267
4246static void
4247addcmdentry(char *name, struct cmdentry *entry)
4248{
4249 struct tblentry *cmdp;
4250 4268
4251 INTOFF; 4269static const short nodesize[26] = {
4252 cmdp = cmdlookup(name, 1); 4270 ALIGN(sizeof (struct nbinary)),
4253 if (cmdp->cmdtype == CMDFUNCTION) { 4271 ALIGN(sizeof (struct ncmd)),
4254 freefunc(cmdp->param.func); 4272 ALIGN(sizeof (struct npipe)),
4255 } 4273 ALIGN(sizeof (struct nredir)),
4256 cmdp->cmdtype = entry->cmdtype; 4274 ALIGN(sizeof (struct nredir)),
4257 cmdp->param = entry->u; 4275 ALIGN(sizeof (struct nredir)),
4258 INTON; 4276 ALIGN(sizeof (struct nbinary)),
4259} 4277 ALIGN(sizeof (struct nbinary)),
4260 4278 ALIGN(sizeof (struct nif)),
4261 4279 ALIGN(sizeof (struct nbinary)),
4262/* 4280 ALIGN(sizeof (struct nbinary)),
4263 * Define a shell function. 4281 ALIGN(sizeof (struct nfor)),
4264 */ 4282 ALIGN(sizeof (struct ncase)),
4265 4283 ALIGN(sizeof (struct nclist)),
4266static union node *copyfunc(union node *); 4284 ALIGN(sizeof (struct narg)),
4267 4285 ALIGN(sizeof (struct narg)),
4268static void 4286 ALIGN(sizeof (struct nfile)),
4269defun(char *name, union node *func) 4287 ALIGN(sizeof (struct nfile)),
4270{ 4288 ALIGN(sizeof (struct nfile)),
4271 struct cmdentry entry; 4289 ALIGN(sizeof (struct nfile)),
4290 ALIGN(sizeof (struct nfile)),
4291 ALIGN(sizeof (struct ndup)),
4292 ALIGN(sizeof (struct ndup)),
4293 ALIGN(sizeof (struct nhere)),
4294 ALIGN(sizeof (struct nhere)),
4295 ALIGN(sizeof (struct nnot)),
4296};
4272 4297
4273 entry.cmdtype = CMDFUNCTION;
4274 entry.u.func = copyfunc(func);
4275 addcmdentry(name, &entry);
4276}
4277 4298
4278 4299
4279/* 4300/*
@@ -4291,141 +4312,29 @@ unsetfunc(char *name)
4291 } 4312 }
4292} 4313}
4293 4314
4294/*
4295 * Wrapper around strcmp for qsort/bsearch/...
4296 */
4297static int
4298pstrcmp(const void *a, const void *b)
4299{
4300 return strcmp((const char *) a, *(const char *const *) b);
4301}
4302 4315
4303/* 4316/*
4304 * Find a keyword is in a sorted array.
4305 */
4306
4307static const char *const *
4308findkwd(const char *s)
4309{
4310 return bsearch(s, parsekwd, sizeof(parsekwd) / sizeof(const char *),
4311 sizeof(const char *), pstrcmp);
4312}
4313
4314#ifdef ASH_TYPE
4315/*
4316 * Locate and print what a word is... 4317 * Locate and print what a word is...
4317 */ 4318 */
4318 4319
4319static int 4320static int
4320typecmd(argc, argv) 4321typecmd(int argc, char **argv)
4321 int argc;
4322 char **argv;
4323{ 4322{
4324 int i; 4323 int i;
4325 int err = 0; 4324 int err = 0;
4325 char *argv_a[2];
4326
4327 argv_a[1] = 0;
4326 4328
4327 for (i = 1; i < argc; i++) { 4329 for (i = 1; i < argc; i++) {
4328 err |= describe_command(argv[i], 1); 4330 argv_a[0] = argv[i];
4331 argptr = argv_a;
4332 optptr = "v";
4333 err |= hashcmd(argc, argv);
4329 } 4334 }
4330 return err; 4335 return err;
4331} 4336}
4332 4337
4333static int
4334describe_command(char *command, int verbose)
4335{
4336 struct cmdentry entry;
4337 struct tblentry *cmdp;
4338#ifdef ASH_ALIAS
4339 const struct alias *ap;
4340#endif
4341 const char *path = pathval();
4342
4343 if (verbose) {
4344 out1str(command);
4345 }
4346
4347 /* First look at the keywords */
4348 if (findkwd(command)) {
4349 out1str(verbose ? " is a shell keyword" : command);
4350 goto out;
4351 }
4352
4353#ifdef ASH_ALIAS
4354 /* Then look at the aliases */
4355 if ((ap = lookupalias(command, 0)) != NULL) {
4356 if (verbose) {
4357 out1fmt(" is an alias for %s", ap->val);
4358 } else {
4359 printalias(ap);
4360 }
4361 goto out;
4362 }
4363#endif
4364 /* Then check if it is a tracked alias */
4365 if ((cmdp = cmdlookup(command, 0)) != NULL) {
4366 entry.cmdtype = cmdp->cmdtype;
4367 entry.u = cmdp->param;
4368 } else {
4369 /* Finally use brute force */
4370 find_command(command, &entry, DO_ABS, path);
4371 }
4372
4373 switch (entry.cmdtype) {
4374 case CMDNORMAL: {
4375 int j = entry.u.index;
4376 char *p;
4377 if (j == -1) {
4378 p = command;
4379 } else {
4380 do {
4381 p = padvance(&path, command);
4382 stunalloc(p);
4383 } while (--j >= 0);
4384 }
4385 if (verbose) {
4386 out1fmt(
4387 " is%s %s",
4388 cmdp ? " a tracked alias for" : nullstr, p
4389 );
4390 } else {
4391 out1str(p);
4392 }
4393 break;
4394 }
4395
4396 case CMDFUNCTION:
4397 if (verbose) {
4398 out1str(" is a shell function");
4399 } else {
4400 out1str(command);
4401 }
4402 break;
4403
4404 case CMDBUILTIN:
4405 if (verbose) {
4406 out1fmt(
4407 " is a %sshell builtin",
4408 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
4409 "special " : nullstr
4410 );
4411 } else {
4412 out1str(command);
4413 }
4414 break;
4415
4416 default:
4417 if (verbose) {
4418 out1str(": not found\n");
4419 }
4420 return 127;
4421 }
4422
4423out:
4424 putchar('\n');
4425 return 0;
4426}
4427#endif
4428
4429#ifdef ASH_CMDCMD 4338#ifdef ASH_CMDCMD
4430static int 4339static int
4431commandcmd(argc, argv) 4340commandcmd(argc, argv)
@@ -4448,26 +4357,25 @@ commandcmd(argc, argv)
4448 case 'V': 4357 case 'V':
4449 verbose_verify_only = 1; 4358 verbose_verify_only = 1;
4450 break; 4359 break;
4451 default:
4452 out2fmt(
4453"command: nextopt returned character code 0%o\n", c);
4454 return EX_SOFTWARE;
4455 } 4360 }
4456 4361
4457 if (default_path + verify_only + verbose_verify_only > 1 || 4362 if (default_path + verify_only + verbose_verify_only > 1 ||
4458 !*argptr) { 4363 !*argptr) {
4459 out2fmt( 4364 out2str(
4460"command [-p] command [arg ...]\n"); 4365 "command [-p] command [arg ...]\n"
4461 out2fmt( 4366 "command {-v|-V} command\n");
4462"command {-v|-V} command\n");
4463 return EX_USAGE; 4367 return EX_USAGE;
4464 } 4368 }
4465 4369
4466#ifdef ASH_TYPE
4467 if (verify_only || verbose_verify_only) { 4370 if (verify_only || verbose_verify_only) {
4468 return describe_command(*argptr, verbose_verify_only); 4371 char *argv_a[2];
4372
4373 argv_a[1] = 0;
4374 argv_a[0] = *argptr;
4375 argptr = argv_a;
4376 optptr = verbose_verify_only ? "v" : "V"; /* reverse special */
4377 return hashcmd(argc, argv);
4469 } 4378 }
4470#endif
4471 4379
4472 return 0; 4380 return 0;
4473} 4381}
@@ -4541,7 +4449,6 @@ static void argstr (char *, int);
4541static char *exptilde (char *, int); 4449static char *exptilde (char *, int);
4542static void expbackq (union node *, int, int); 4450static void expbackq (union node *, int, int);
4543static int subevalvar (char *, char *, int, int, int, int, int); 4451static int subevalvar (char *, char *, int, int, int, int, int);
4544static char *evalvar (char *, int);
4545static int varisset (char *, int); 4452static int varisset (char *, int);
4546static void strtodest (const char *, const char *, int); 4453static void strtodest (const char *, const char *, int);
4547static void varvalue (char *, int, int); 4454static void varvalue (char *, int, int);
@@ -4550,21 +4457,21 @@ static void removerecordregions (int);
4550static void ifsbreakup (char *, struct arglist *); 4457static void ifsbreakup (char *, struct arglist *);
4551static void ifsfree (void); 4458static void ifsfree (void);
4552static void expandmeta (struct strlist *, int); 4459static void expandmeta (struct strlist *, int);
4553#if defined(__GLIBC__) && !defined(FNMATCH_BROKEN) 4460#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
4554#define preglob(p) _rmescapes((p), RMESCAPE_ALLOC | RMESCAPE_GLOB) 4461#define preglob(p) _rmescapes((p), RMESCAPE_ALLOC | RMESCAPE_GLOB)
4555#if !defined(GLOB_BROKEN) 4462#if !defined(GLOB_BROKEN)
4556static void addglob (const glob_t *); 4463static void addglob (const glob_t *);
4557#endif 4464#endif
4558#endif 4465#endif
4559#if !(defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)) 4466#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
4560static void expmeta (char *, char *); 4467static void expmeta (char *, char *);
4561#endif 4468#endif
4562#if !(defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)) 4469#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
4563static struct strlist *expsort (struct strlist *); 4470static struct strlist *expsort (struct strlist *);
4564static struct strlist *msort (struct strlist *, int); 4471static struct strlist *msort (struct strlist *, int);
4565#endif 4472#endif
4566#if defined(__GLIBC__) && !defined(FNMATCH_BROKEN)
4567static int patmatch (char *, char *, int); 4473static int patmatch (char *, char *, int);
4474#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
4568static int patmatch2 (char *, char *, int); 4475static int patmatch2 (char *, char *, int);
4569#else 4476#else
4570static int pmatch (char *, char *, int); 4477static int pmatch (char *, char *, int);
@@ -4577,7 +4484,7 @@ static char *cvtnum (int, char *);
4577 */ 4484 */
4578 4485
4579/* arg: the document, fd: where to write the expanded version */ 4486/* arg: the document, fd: where to write the expanded version */
4580static void 4487static inline void
4581expandhere(union node *arg, int fd) 4488expandhere(union node *arg, int fd)
4582{ 4489{
4583 herefd = fd; 4490 herefd = fd;
@@ -4638,6 +4545,168 @@ expandarg(arg, arglist, flag)
4638} 4545}
4639 4546
4640 4547
4548/*
4549 * Expand a variable, and return a pointer to the next character in the
4550 * input string.
4551 */
4552
4553static inline char *
4554evalvar(p, flag)
4555 char *p;
4556 int flag;
4557{
4558 int subtype;
4559 int varflags;
4560 char *var;
4561 const char *val;
4562 int patloc;
4563 int c;
4564 int set;
4565 int special;
4566 int startloc;
4567 int varlen;
4568 int easy;
4569 int quotes = flag & (EXP_FULL | EXP_CASE);
4570
4571 varflags = *p++;
4572 subtype = varflags & VSTYPE;
4573 var = p;
4574 special = 0;
4575 if (! is_name(*p))
4576 special = 1;
4577 p = strchr(p, '=') + 1;
4578again: /* jump here after setting a variable with ${var=text} */
4579 if (special) {
4580 set = varisset(var, varflags & VSNUL);
4581 val = NULL;
4582 } else {
4583 val = lookupvar(var);
4584 if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
4585 val = NULL;
4586 set = 0;
4587 } else
4588 set = 1;
4589 }
4590 varlen = 0;
4591 startloc = expdest - stackblock();
4592 if (set && subtype != VSPLUS) {
4593 /* insert the value of the variable */
4594 if (special) {
4595 varvalue(var, varflags & VSQUOTE, flag);
4596 if (subtype == VSLENGTH) {
4597 varlen = expdest - stackblock() - startloc;
4598 STADJUST(-varlen, expdest);
4599 }
4600 } else {
4601 if (subtype == VSLENGTH) {
4602 varlen = strlen(val);
4603 } else {
4604 strtodest(
4605 val,
4606 varflags & VSQUOTE ?
4607 DQSYNTAX : BASESYNTAX,
4608 quotes
4609 );
4610 }
4611 }
4612 }
4613
4614 if (subtype == VSPLUS)
4615 set = ! set;
4616
4617 easy = ((varflags & VSQUOTE) == 0 ||
4618 (*var == '@' && shellparam.nparam != 1));
4619
4620
4621 switch (subtype) {
4622 case VSLENGTH:
4623 expdest = cvtnum(varlen, expdest);
4624 goto record;
4625
4626 case VSNORMAL:
4627 if (!easy)
4628 break;
4629record:
4630 recordregion(startloc, expdest - stackblock(),
4631 varflags & VSQUOTE);
4632 break;
4633
4634 case VSPLUS:
4635 case VSMINUS:
4636 if (!set) {
4637 argstr(p, flag);
4638 break;
4639 }
4640 if (easy)
4641 goto record;
4642 break;
4643
4644 case VSTRIMLEFT:
4645 case VSTRIMLEFTMAX:
4646 case VSTRIMRIGHT:
4647 case VSTRIMRIGHTMAX:
4648 if (!set)
4649 break;
4650 /*
4651 * Terminate the string and start recording the pattern
4652 * right after it
4653 */
4654 STPUTC('\0', expdest);
4655 patloc = expdest - stackblock();
4656 if (subevalvar(p, NULL, patloc, subtype,
4657 startloc, varflags, quotes) == 0) {
4658 int amount = (expdest - stackblock() - patloc) + 1;
4659 STADJUST(-amount, expdest);
4660 }
4661 /* Remove any recorded regions beyond start of variable */
4662 removerecordregions(startloc);
4663 goto record;
4664
4665 case VSASSIGN:
4666 case VSQUESTION:
4667 if (!set) {
4668 if (subevalvar(p, var, 0, subtype, startloc,
4669 varflags, quotes)) {
4670 varflags &= ~VSNUL;
4671 /*
4672 * Remove any recorded regions beyond
4673 * start of variable
4674 */
4675 removerecordregions(startloc);
4676 goto again;
4677 }
4678 break;
4679 }
4680 if (easy)
4681 goto record;
4682 break;
4683
4684#ifdef DEBUG
4685 default:
4686 abort();
4687#endif
4688 }
4689
4690 if (subtype != VSNORMAL) { /* skip to end of alternative */
4691 int nesting = 1;
4692 for (;;) {
4693 if ((c = *p++) == CTLESC)
4694 p++;
4695 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
4696 if (set)
4697 argbackq = argbackq->next;
4698 } else if (c == CTLVAR) {
4699 if ((*p++ & VSTYPE) != VSNORMAL)
4700 nesting++;
4701 } else if (c == CTLENDVAR) {
4702 if (--nesting == 0)
4703 break;
4704 }
4705 }
4706 }
4707 return p;
4708}
4709
4641 4710
4642/* 4711/*
4643 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC 4712 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
@@ -5091,168 +5160,6 @@ recordright:
5091 5160
5092 5161
5093/* 5162/*
5094 * Expand a variable, and return a pointer to the next character in the
5095 * input string.
5096 */
5097
5098static char *
5099evalvar(p, flag)
5100 char *p;
5101 int flag;
5102{
5103 int subtype;
5104 int varflags;
5105 char *var;
5106 char *val;
5107 int patloc;
5108 int c;
5109 int set;
5110 int special;
5111 int startloc;
5112 int varlen;
5113 int easy;
5114 int quotes = flag & (EXP_FULL | EXP_CASE);
5115
5116 varflags = *p++;
5117 subtype = varflags & VSTYPE;
5118 var = p;
5119 special = 0;
5120 if (! is_name(*p))
5121 special = 1;
5122 p = strchr(p, '=') + 1;
5123again: /* jump here after setting a variable with ${var=text} */
5124 if (special) {
5125 set = varisset(var, varflags & VSNUL);
5126 val = NULL;
5127 } else {
5128 val = lookupvar(var);
5129 if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
5130 val = NULL;
5131 set = 0;
5132 } else
5133 set = 1;
5134 }
5135 varlen = 0;
5136 startloc = expdest - stackblock();
5137 if (set && subtype != VSPLUS) {
5138 /* insert the value of the variable */
5139 if (special) {
5140 varvalue(var, varflags & VSQUOTE, flag);
5141 if (subtype == VSLENGTH) {
5142 varlen = expdest - stackblock() - startloc;
5143 STADJUST(-varlen, expdest);
5144 }
5145 } else {
5146 if (subtype == VSLENGTH) {
5147 varlen = strlen(val);
5148 } else {
5149 strtodest(
5150 val,
5151 varflags & VSQUOTE ?
5152 DQSYNTAX : BASESYNTAX,
5153 quotes
5154 );
5155 }
5156 }
5157 }
5158
5159 if (subtype == VSPLUS)
5160 set = ! set;
5161
5162 easy = ((varflags & VSQUOTE) == 0 ||
5163 (*var == '@' && shellparam.nparam != 1));
5164
5165
5166 switch (subtype) {
5167 case VSLENGTH:
5168 expdest = cvtnum(varlen, expdest);
5169 goto record;
5170
5171 case VSNORMAL:
5172 if (!easy)
5173 break;
5174record:
5175 recordregion(startloc, expdest - stackblock(),
5176 varflags & VSQUOTE);
5177 break;
5178
5179 case VSPLUS:
5180 case VSMINUS:
5181 if (!set) {
5182 argstr(p, flag);
5183 break;
5184 }
5185 if (easy)
5186 goto record;
5187 break;
5188
5189 case VSTRIMLEFT:
5190 case VSTRIMLEFTMAX:
5191 case VSTRIMRIGHT:
5192 case VSTRIMRIGHTMAX:
5193 if (!set)
5194 break;
5195 /*
5196 * Terminate the string and start recording the pattern
5197 * right after it
5198 */
5199 STPUTC('\0', expdest);
5200 patloc = expdest - stackblock();
5201 if (subevalvar(p, NULL, patloc, subtype,
5202 startloc, varflags, quotes) == 0) {
5203 int amount = (expdest - stackblock() - patloc) + 1;
5204 STADJUST(-amount, expdest);
5205 }
5206 /* Remove any recorded regions beyond start of variable */
5207 removerecordregions(startloc);
5208 goto record;
5209
5210 case VSASSIGN:
5211 case VSQUESTION:
5212 if (!set) {
5213 if (subevalvar(p, var, 0, subtype, startloc,
5214 varflags, quotes)) {
5215 varflags &= ~VSNUL;
5216 /*
5217 * Remove any recorded regions beyond
5218 * start of variable
5219 */
5220 removerecordregions(startloc);
5221 goto again;
5222 }
5223 break;
5224 }
5225 if (easy)
5226 goto record;
5227 break;
5228
5229#ifdef DEBUG
5230 default:
5231 abort();
5232#endif
5233 }
5234
5235 if (subtype != VSNORMAL) { /* skip to end of alternative */
5236 int nesting = 1;
5237 for (;;) {
5238 if ((c = *p++) == CTLESC)
5239 p++;
5240 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
5241 if (set)
5242 argbackq = argbackq->next;
5243 } else if (c == CTLVAR) {
5244 if ((*p++ & VSTYPE) != VSNORMAL)
5245 nesting++;
5246 } else if (c == CTLENDVAR) {
5247 if (--nesting == 0)
5248 break;
5249 }
5250 }
5251 }
5252 return p;
5253}
5254
5255/*
5256 * Test whether a specialized variable is set. 5163 * Test whether a specialized variable is set.
5257 */ 5164 */
5258 5165
@@ -5542,7 +5449,7 @@ addfname(const char *name)
5542 * should be escapes. The results are stored in the list exparg. 5449 * should be escapes. The results are stored in the list exparg.
5543 */ 5450 */
5544 5451
5545#if defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) 5452#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)
5546static void 5453static void
5547expandmeta(str, flag) 5454expandmeta(str, flag)
5548 struct strlist *str; 5455 struct strlist *str;
@@ -5787,7 +5694,7 @@ expmeta(enddir, name)
5787 5694
5788 5695
5789 5696
5790#if !(defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)) 5697#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
5791/* 5698/*
5792 * Sort the results of file name expansion. It calculates the number of 5699 * Sort the results of file name expansion. It calculates the number of
5793 * strings to sort and then calls msort (short for merge sort) to do the 5700 * strings to sort and then calls msort (short for merge sort) to do the
@@ -5857,7 +5764,7 @@ msort(list, len)
5857 * Returns true if the pattern matches the string. 5764 * Returns true if the pattern matches the string.
5858 */ 5765 */
5859 5766
5860#if defined(__GLIBC__) && !defined(FNMATCH_BROKEN) 5767#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
5861/* squoted: string might have quote chars */ 5768/* squoted: string might have quote chars */
5862static int 5769static int
5863patmatch(char *pattern, char *string, int squoted) 5770patmatch(char *pattern, char *string, int squoted)
@@ -6015,7 +5922,7 @@ breakloop:
6015 * Remove any CTLESC characters from a string. 5922 * Remove any CTLESC characters from a string.
6016 */ 5923 */
6017 5924
6018#if defined(__GLIBC__) && !defined(FNMATCH_BROKEN) 5925#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
6019static char * 5926static char *
6020_rmescapes(char *str, int flag) 5927_rmescapes(char *str, int flag)
6021{ 5928{
@@ -6032,12 +5939,8 @@ _rmescapes(char *str, int flag)
6032 size_t len = p - str; 5939 size_t len = p - str;
6033 q = r = stalloc(strlen(p) + len + 1); 5940 q = r = stalloc(strlen(p) + len + 1);
6034 if (len > 0) { 5941 if (len > 0) {
6035#ifdef _GNU_SOURCE
6036 q = mempcpy(q, str, len);
6037#else
6038 memcpy(q, str, len); 5942 memcpy(q, str, len);
6039 q += len; 5943 q += len;
6040#endif
6041 } 5944 }
6042 } 5945 }
6043 while (*p) { 5946 while (*p) {
@@ -6135,12 +6038,10 @@ static int histcmd(argc, argv)
6135} 6038}
6136 6039
6137 6040
6138static int whichprompt; /* 1 == PS1, 2 == PS2 */
6139
6140
6141struct redirtab { 6041struct redirtab {
6142 struct redirtab *next; 6042 struct redirtab *next;
6143 short renamed[10]; 6043 /* short renamed[10]; *//* Current ash support only 0-9 descriptors */
6044 char renamed[10];
6144}; 6045};
6145 6046
6146static struct redirtab *redirlist; 6047static struct redirtab *redirlist;
@@ -6273,7 +6174,7 @@ static inline int pgetc2() { return pgetc_macro(); }
6273 * Read a line from the script. 6174 * Read a line from the script.
6274 */ 6175 */
6275 6176
6276static char * 6177static inline char *
6277pfgets(char *line, int len) 6178pfgets(char *line, int len)
6278{ 6179{
6279 char *p = line; 6180 char *p = line;
@@ -6295,7 +6196,7 @@ pfgets(char *line, int len)
6295 return line; 6196 return line;
6296} 6197}
6297 6198
6298static int 6199static inline int
6299preadfd(void) 6200preadfd(void)
6300{ 6201{
6301 int nr; 6202 int nr;
@@ -6480,16 +6381,13 @@ pushstring(char *s, int len, void *ap)
6480} 6381}
6481 6382
6482 6383
6483
6484
6485/* 6384/*
6486 * Like setinputfile, but takes input from a string. 6385 * Like setinputfile, but takes input from a string.
6487 */ 6386 */
6488 6387
6489static void 6388static void
6490setinputstring(string) 6389setinputstring(char *string)
6491 char *string; 6390{
6492 {
6493 INTOFF; 6391 INTOFF;
6494 pushfile(); 6392 pushfile();
6495 parsenextc = string; 6393 parsenextc = string;
@@ -6528,7 +6426,6 @@ static void restartjob (struct job *);
6528static void freejob (struct job *); 6426static void freejob (struct job *);
6529static struct job *getjob (const char *); 6427static struct job *getjob (const char *);
6530static int dowait (int, struct job *); 6428static int dowait (int, struct job *);
6531static int waitproc (int, int *);
6532static void waitonint(int); 6429static void waitonint(int);
6533 6430
6534 6431
@@ -6545,12 +6442,7 @@ fd0_redirected_p () {
6545 return fd0_redirected != 0; 6442 return fd0_redirected != 0;
6546} 6443}
6547 6444
6548static int openredirect (union node *); 6445static void dupredirect (const union node *, int, int fd1dup);
6549static void dupredirect (union node *, int, char[10 ]);
6550static int openhere (union node *);
6551static int noclobberopen (const char *);
6552
6553
6554 6446
6555#ifdef JOBS 6447#ifdef JOBS
6556/* 6448/*
@@ -6656,6 +6548,7 @@ static char *signal_names[NSIG + 2] = {
6656 "SIGIO", 6548 "SIGIO",
6657 "SIGPWR", 6549 "SIGPWR",
6658 "SIGSYS", 6550 "SIGSYS",
6551#ifdef SIGRTMIN
6659 "SIGRTMIN", 6552 "SIGRTMIN",
6660 "SIGRTMIN+1", 6553 "SIGRTMIN+1",
6661 "SIGRTMIN+2", 6554 "SIGRTMIN+2",
@@ -6688,6 +6581,7 @@ static char *signal_names[NSIG + 2] = {
6688 "SIGRTMAX-2", 6581 "SIGRTMAX-2",
6689 "SIGRTMAX-1", 6582 "SIGRTMAX-1",
6690 "SIGRTMAX", 6583 "SIGRTMAX",
6584#endif
6691 "DEBUG", 6585 "DEBUG",
6692 (char *)0x0, 6586 (char *)0x0,
6693}; 6587};
@@ -6754,7 +6648,7 @@ usage:
6754 if (!*argptr) { 6648 if (!*argptr) {
6755 out1str("0\n"); 6649 out1str("0\n");
6756 for (i = 1; i < NSIG; i++) { 6650 for (i = 1; i < NSIG; i++) {
6757 out1fmt(snlfmt, signal_names[i] + 3); 6651 printf(snlfmt, signal_names[i] + 3);
6758 } 6652 }
6759 return 0; 6653 return 0;
6760 } 6654 }
@@ -6762,7 +6656,7 @@ usage:
6762 if (signo > 128) 6656 if (signo > 128)
6763 signo -= 128; 6657 signo -= 128;
6764 if (0 < signo && signo < NSIG) 6658 if (0 < signo && signo < NSIG)
6765 out1fmt(snlfmt, signal_names[signo] + 3); 6659 printf(snlfmt, signal_names[signo] + 3);
6766 else 6660 else
6767 error("invalid signal number or exit status: %s", 6661 error("invalid signal number or exit status: %s",
6768 *argptr); 6662 *argptr);
@@ -6926,7 +6820,7 @@ showjobs(change)
6926 } 6820 }
6927 out1str(s); 6821 out1str(s);
6928 col += strlen(s); 6822 col += strlen(s);
6929 out1fmt( 6823 printf(
6930 "%*c%s\n", 30 - col >= 0 ? 30 - col : 0, ' ', 6824 "%*c%s\n", 30 - col >= 0 ? 30 - col : 0, ' ',
6931 ps->cmd 6825 ps->cmd
6932 ); 6826 );
@@ -6946,10 +6840,9 @@ showjobs(change)
6946 */ 6840 */
6947 6841
6948static void 6842static void
6949freejob(jp) 6843freejob(struct job *jp)
6950 struct job *jp; 6844{
6951 { 6845 const struct procstat *ps;
6952 struct procstat *ps;
6953 int i; 6846 int i;
6954 6847
6955 INTOFF; 6848 INTOFF;
@@ -7084,9 +6977,7 @@ currentjob:
7084 */ 6977 */
7085 6978
7086static struct job * 6979static struct job *
7087makejob(node, nprocs) 6980makejob(const union node *node, int nprocs)
7088 union node *node;
7089 int nprocs;
7090{ 6981{
7091 int i; 6982 int i;
7092 struct job *jp; 6983 struct job *jp;
@@ -7152,10 +7043,12 @@ makejob(node, nprocs)
7152 7043
7153 7044
7154static int 7045static int
7155forkshell(struct job *jp, union node *n, int mode) 7046forkshell(struct job *jp, const union node *n, int mode)
7156{ 7047{
7157 int pid; 7048 int pid;
7049#ifdef JOBS
7158 int pgrp; 7050 int pgrp;
7051#endif
7159 const char *devnull = _PATH_DEVNULL; 7052 const char *devnull = _PATH_DEVNULL;
7160 const char *nullerr = "Can't open %s"; 7053 const char *nullerr = "Can't open %s";
7161 7054
@@ -7231,6 +7124,7 @@ forkshell(struct job *jp, union node *n, int mode)
7231 } 7124 }
7232 return pid; 7125 return pid;
7233 } 7126 }
7127#ifdef JOBS
7234 if (rootshell && mode != FORK_NOJOB && mflag) { 7128 if (rootshell && mode != FORK_NOJOB && mflag) {
7235 if (jp == NULL || jp->nprocs == 0) 7129 if (jp == NULL || jp->nprocs == 0)
7236 pgrp = pid; 7130 pgrp = pid;
@@ -7238,6 +7132,7 @@ forkshell(struct job *jp, union node *n, int mode)
7238 pgrp = jp->ps[0].pid; 7132 pgrp = jp->ps[0].pid;
7239 setpgid(pid, pgrp); 7133 setpgid(pid, pgrp);
7240 } 7134 }
7135#endif
7241 if (mode == FORK_BG) 7136 if (mode == FORK_BG)
7242 backgndpid = pid; /* set $! */ 7137 backgndpid = pid; /* set $! */
7243 if (jp) { 7138 if (jp) {
@@ -7275,9 +7170,8 @@ forkshell(struct job *jp, union node *n, int mode)
7275 */ 7170 */
7276 7171
7277static int 7172static int
7278waitforjob(jp) 7173waitforjob(struct job *jp)
7279 struct job *jp; 7174{
7280 {
7281#ifdef JOBS 7175#ifdef JOBS
7282 int mypgrp = getpgrp(); 7176 int mypgrp = getpgrp();
7283#endif 7177#endif
@@ -7358,10 +7252,47 @@ waitforjob(jp)
7358 * Wait for a process to terminate. 7252 * Wait for a process to terminate.
7359 */ 7253 */
7360 7254
7255/*
7256 * Do a wait system call. If job control is compiled in, we accept
7257 * stopped processes. If block is zero, we return a value of zero
7258 * rather than blocking.
7259 *
7260 * System V doesn't have a non-blocking wait system call. It does
7261 * have a SIGCLD signal that is sent to a process when one of it's
7262 * children dies. The obvious way to use SIGCLD would be to install
7263 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7264 * was received, and have waitproc bump another counter when it got
7265 * the status of a process. Waitproc would then know that a wait
7266 * system call would not block if the two counters were different.
7267 * This approach doesn't work because if a process has children that
7268 * have not been waited for, System V will send it a SIGCLD when it
7269 * installs a signal handler for SIGCLD. What this means is that when
7270 * a child exits, the shell will be sent SIGCLD signals continuously
7271 * until is runs out of stack space, unless it does a wait call before
7272 * restoring the signal handler. The code below takes advantage of
7273 * this (mis)feature by installing a signal handler for SIGCLD and
7274 * then checking to see whether it was called. If there are any
7275 * children to be waited for, it will be.
7276 *
7277 */
7278
7279static inline int
7280waitproc(int block, int *status)
7281{
7282 int flags;
7283
7284 flags = 0;
7285#ifdef JOBS
7286 if (jobctl)
7287 flags |= WUNTRACED;
7288#endif
7289 if (block == 0)
7290 flags |= WNOHANG;
7291 return wait3(status, flags, (struct rusage *)NULL);
7292}
7293
7361static int 7294static int
7362dowait(block, job) 7295dowait(int block, struct job *job)
7363 int block;
7364 struct job *job;
7365{ 7296{
7366 int pid; 7297 int pid;
7367 int status; 7298 int status;
@@ -7451,46 +7382,6 @@ dowait(block, job)
7451 7382
7452 7383
7453 7384
7454/*
7455 * Do a wait system call. If job control is compiled in, we accept
7456 * stopped processes. If block is zero, we return a value of zero
7457 * rather than blocking.
7458 *
7459 * System V doesn't have a non-blocking wait system call. It does
7460 * have a SIGCLD signal that is sent to a process when one of it's
7461 * children dies. The obvious way to use SIGCLD would be to install
7462 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7463 * was received, and have waitproc bump another counter when it got
7464 * the status of a process. Waitproc would then know that a wait
7465 * system call would not block if the two counters were different.
7466 * This approach doesn't work because if a process has children that
7467 * have not been waited for, System V will send it a SIGCLD when it
7468 * installs a signal handler for SIGCLD. What this means is that when
7469 * a child exits, the shell will be sent SIGCLD signals continuously
7470 * until is runs out of stack space, unless it does a wait call before
7471 * restoring the signal handler. The code below takes advantage of
7472 * this (mis)feature by installing a signal handler for SIGCLD and
7473 * then checking to see whether it was called. If there are any
7474 * children to be waited for, it will be.
7475 *
7476 */
7477
7478static int
7479waitproc(block, status)
7480 int block;
7481 int *status;
7482{
7483 int flags;
7484
7485 flags = 0;
7486#ifdef JOBS
7487 if (jobctl)
7488 flags |= WUNTRACED;
7489#endif
7490 if (block == 0)
7491 flags |= WNOHANG;
7492 return wait3(status, flags, (struct rusage *)NULL);
7493}
7494 7385
7495/* 7386/*
7496 * return 1 if there are stopped jobs, otherwise 0 7387 * return 1 if there are stopped jobs, otherwise 0
@@ -7778,10 +7669,8 @@ extern int etext();
7778#endif 7669#endif
7779 7670
7780static void read_profile (const char *); 7671static void read_profile (const char *);
7781static char *find_dot_file (char *);
7782static void cmdloop (int); 7672static void cmdloop (int);
7783static void options (int); 7673static void options (int);
7784static void minus_o (char *, int);
7785static void setoption (int, int); 7674static void setoption (int, int);
7786static void procargs (int, char **); 7675static void procargs (int, char **);
7787 7676
@@ -7802,9 +7691,8 @@ shell_main(argc, argv)
7802 struct jmploc jmploc; 7691 struct jmploc jmploc;
7803 struct stackmark smark; 7692 struct stackmark smark;
7804 volatile int state; 7693 volatile int state;
7805 char *shinit; 7694 const char *shinit;
7806 7695
7807 DOTCMD = find_builtin(".");
7808 BLTINCMD = find_builtin("builtin"); 7696 BLTINCMD = find_builtin("builtin");
7809 EXECCMD = find_builtin("exec"); 7697 EXECCMD = find_builtin("exec");
7810 EVALCMD = find_builtin("eval"); 7698 EVALCMD = find_builtin("eval");
@@ -8045,7 +7933,7 @@ readcmdfile(const char *name)
8045 */ 7933 */
8046 7934
8047 7935
8048static char * 7936static inline char *
8049find_dot_file(mybasename) 7937find_dot_file(mybasename)
8050 char *mybasename; 7938 char *mybasename;
8051{ 7939{
@@ -8114,6 +8002,7 @@ exitcmd(argc, argv)
8114 exitshell(exitstatus); 8002 exitshell(exitstatus);
8115 /* NOTREACHED */ 8003 /* NOTREACHED */
8116} 8004}
8005
8117static pointer 8006static pointer
8118stalloc(int nbytes) 8007stalloc(int nbytes)
8119{ 8008{
@@ -8314,13 +8203,13 @@ ungrabstackstr(char *s, char *p)
8314 8203
8315#undef rflag 8204#undef rflag
8316 8205
8317#ifdef __GLIBC__ 8206//#ifdef __GLIBC__
8318static mode_t getmode(const void *, mode_t); 8207static mode_t getmode(const void *, mode_t);
8319static void *setmode(const char *); 8208static void *setmode(const char *);
8209//#endif
8320 8210
8321#if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1 8211#if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
8322typedef enum __rlimit_resource rlim_t; 8212typedef long rlim_t;
8323#endif
8324#endif 8213#endif
8325 8214
8326 8215
@@ -8429,7 +8318,7 @@ umaskcmd(argc, argv)
8429 int i; 8318 int i;
8430 int symbolic_mode = 0; 8319 int symbolic_mode = 0;
8431 8320
8432 while ((i = nextopt("S")) != '\0') { 8321 while (nextopt("S") != '\0') {
8433 symbolic_mode = 1; 8322 symbolic_mode = 1;
8434 } 8323 }
8435 8324
@@ -8469,12 +8358,12 @@ umaskcmd(argc, argv)
8469 o[i++] = 'x'; 8358 o[i++] = 'x';
8470 o[i] = '\0'; 8359 o[i] = '\0';
8471 8360
8472 out1fmt("u=%s,g=%s,o=%s\n", u, g, o); 8361 printf("u=%s,g=%s,o=%s\n", u, g, o);
8473 } else { 8362 } else {
8474 out1fmt("%.4o\n", mask); 8363 printf("%.4o\n", mask);
8475 } 8364 }
8476 } else { 8365 } else {
8477 if (isdigit((unsigned char)*ap)) { 8366 if (is_digit((unsigned char)*ap)) {
8478 mask = 0; 8367 mask = 0;
8479 do { 8368 do {
8480 if (*ap >= '8' || *ap < '0') 8369 if (*ap >= '8' || *ap < '0')
@@ -8619,13 +8508,13 @@ ulimitcmd(argc, argv)
8619 else if (how & HARD) 8508 else if (how & HARD)
8620 val = limit.rlim_max; 8509 val = limit.rlim_max;
8621 8510
8622 out1fmt("%-20s ", l->name); 8511 printf("%-20s ", l->name);
8623 if (val == RLIM_INFINITY) 8512 if (val == RLIM_INFINITY)
8624 out1fmt("unlimited\n"); 8513 printf("unlimited\n");
8625 else 8514 else
8626 { 8515 {
8627 val /= l->factor; 8516 val /= l->factor;
8628 out1fmt("%lld\n", (long long) val); 8517 printf("%lld\n", (long long) val);
8629 } 8518 }
8630 } 8519 }
8631 return 0; 8520 return 0;
@@ -8646,11 +8535,11 @@ ulimitcmd(argc, argv)
8646 val = limit.rlim_max; 8535 val = limit.rlim_max;
8647 8536
8648 if (val == RLIM_INFINITY) 8537 if (val == RLIM_INFINITY)
8649 out1fmt("unlimited\n"); 8538 printf("unlimited\n");
8650 else 8539 else
8651 { 8540 {
8652 val /= l->factor; 8541 val /= l->factor;
8653 out1fmt("%lld\n", (long long) val); 8542 printf("%lld\n", (long long) val);
8654 } 8543 }
8655 } 8544 }
8656 return 0; 8545 return 0;
@@ -8660,10 +8549,8 @@ ulimitcmd(argc, argv)
8660 */ 8549 */
8661 8550
8662static int 8551static int
8663prefix(pfx, string) 8552prefix(char const *pfx, char const *string)
8664 char const *pfx; 8553{
8665 char const *string;
8666 {
8667 while (*pfx) { 8554 while (*pfx) {
8668 if (*pfx++ != *string++) 8555 if (*pfx++ != *string++)
8669 return 0; 8556 return 0;
@@ -8741,12 +8628,8 @@ single_quote(const char *s) {
8741 8628
8742 if (len1) { 8629 if (len1) {
8743 *p = '\''; 8630 *p = '\'';
8744#ifdef _GNU_SOURCE
8745 q = mempcpy(p + 1, s, len1);
8746#else
8747 q = p + 1 + len1; 8631 q = p + 1 + len1;
8748 memcpy(p + 1, s, len1); 8632 memcpy(p + 1, s, len1);
8749#endif
8750 *q++ = '\''; 8633 *q++ = '\'';
8751 s += len1; 8634 s += len1;
8752 } 8635 }
@@ -8761,13 +8644,9 @@ single_quote(const char *s) {
8761 break; 8644 break;
8762 default: 8645 default:
8763 *q = '"'; 8646 *q = '"';
8764#ifdef _GNU_SOURCE
8765 *(char *) mempcpy(q + 1, s, len2) = '"';
8766#else
8767 q += 1 + len2; 8647 q += 1 + len2;
8768 memcpy(q + 1, s, len2); 8648 memcpy(q + 1, s, len2);
8769 *q = '"'; 8649 *q = '"';
8770#endif
8771 s += len2; 8650 s += len2;
8772 } 8651 }
8773 8652
@@ -8792,79 +8671,16 @@ sstrdup(const char *p)
8792 8671
8793 8672
8794/* 8673/*
8795 * This file was generated by the mknodes program.
8796 */
8797
8798/*
8799 * Routine for dealing with parsed shell commands. 8674 * Routine for dealing with parsed shell commands.
8800 */ 8675 */
8801 8676
8802 8677
8803static int funcblocksize; /* size of structures in function */ 8678static void sizenodelist (const struct nodelist *);
8804static int funcstringsize; /* size of strings in node */ 8679static struct nodelist *copynodelist (const struct nodelist *);
8805static pointer funcblock; /* block to allocate function from */ 8680static char *nodesavestr (const char *);
8806static char *funcstring; /* block to allocate strings from */
8807
8808static const short nodesize[26] = {
8809 ALIGN(sizeof (struct nbinary)),
8810 ALIGN(sizeof (struct ncmd)),
8811 ALIGN(sizeof (struct npipe)),
8812 ALIGN(sizeof (struct nredir)),
8813 ALIGN(sizeof (struct nredir)),
8814 ALIGN(sizeof (struct nredir)),
8815 ALIGN(sizeof (struct nbinary)),
8816 ALIGN(sizeof (struct nbinary)),
8817 ALIGN(sizeof (struct nif)),
8818 ALIGN(sizeof (struct nbinary)),
8819 ALIGN(sizeof (struct nbinary)),
8820 ALIGN(sizeof (struct nfor)),
8821 ALIGN(sizeof (struct ncase)),
8822 ALIGN(sizeof (struct nclist)),
8823 ALIGN(sizeof (struct narg)),
8824 ALIGN(sizeof (struct narg)),
8825 ALIGN(sizeof (struct nfile)),
8826 ALIGN(sizeof (struct nfile)),
8827 ALIGN(sizeof (struct nfile)),
8828 ALIGN(sizeof (struct nfile)),
8829 ALIGN(sizeof (struct nfile)),
8830 ALIGN(sizeof (struct ndup)),
8831 ALIGN(sizeof (struct ndup)),
8832 ALIGN(sizeof (struct nhere)),
8833 ALIGN(sizeof (struct nhere)),
8834 ALIGN(sizeof (struct nnot)),
8835};
8836
8837
8838static void calcsize (union node *);
8839static void sizenodelist (struct nodelist *);
8840static union node *copynode (union node *);
8841static struct nodelist *copynodelist (struct nodelist *);
8842static char *nodesavestr (char *);
8843
8844
8845
8846/*
8847 * Make a copy of a parse tree.
8848 */
8849
8850static union node *
8851copyfunc(union node *n)
8852{
8853 if (n == NULL)
8854 return NULL;
8855 funcblocksize = 0;
8856 funcstringsize = 0;
8857 calcsize(n);
8858 funcblock = ckmalloc(funcblocksize + funcstringsize);
8859 funcstring = (char *) funcblock + funcblocksize;
8860 return copynode(n);
8861}
8862
8863
8864 8681
8865static void 8682static void
8866calcsize(n) 8683calcsize(const union node *n)
8867 union node *n;
8868{ 8684{
8869 if (n == NULL) 8685 if (n == NULL)
8870 return; 8686 return;
@@ -8941,11 +8757,8 @@ calcsize(n)
8941 }; 8757 };
8942} 8758}
8943 8759
8944
8945
8946static void 8760static void
8947sizenodelist(lp) 8761sizenodelist(const struct nodelist *lp)
8948 struct nodelist *lp;
8949{ 8762{
8950 while (lp) { 8763 while (lp) {
8951 funcblocksize += ALIGN(sizeof(struct nodelist)); 8764 funcblocksize += ALIGN(sizeof(struct nodelist));
@@ -8955,12 +8768,10 @@ sizenodelist(lp)
8955} 8768}
8956 8769
8957 8770
8958
8959static union node * 8771static union node *
8960copynode(n) 8772copynode(const union node *n)
8961 union node *n;
8962{ 8773{
8963 union node *new; 8774 union node *new;
8964 8775
8965 if (n == NULL) 8776 if (n == NULL)
8966 return NULL; 8777 return NULL;
@@ -9043,13 +8854,12 @@ copynode(n)
9043 break; 8854 break;
9044 }; 8855 };
9045 new->type = n->type; 8856 new->type = n->type;
9046 return new; 8857 return new;
9047} 8858}
9048 8859
9049 8860
9050static struct nodelist * 8861static struct nodelist *
9051copynodelist(lp) 8862copynodelist(const struct nodelist *lp)
9052 struct nodelist *lp;
9053{ 8863{
9054 struct nodelist *start; 8864 struct nodelist *start;
9055 struct nodelist **lpp; 8865 struct nodelist **lpp;
@@ -9067,10 +8877,8 @@ copynodelist(lp)
9067} 8877}
9068 8878
9069 8879
9070
9071static char * 8880static char *
9072nodesavestr(s) 8881nodesavestr(const char *s)
9073 char *s;
9074{ 8882{
9075#ifdef _GNU_SOURCE 8883#ifdef _GNU_SOURCE
9076 char *rtn = funcstring; 8884 char *rtn = funcstring;
@@ -9078,8 +8886,8 @@ nodesavestr(s)
9078 funcstring = stpcpy(funcstring, s) + 1; 8886 funcstring = stpcpy(funcstring, s) + 1;
9079 return rtn; 8887 return rtn;
9080#else 8888#else
9081 register char *p = s; 8889 const char *p = s;
9082 register char *q = funcstring; 8890 char *q = funcstring;
9083 char *rtn = funcstring; 8891 char *rtn = funcstring;
9084 8892
9085 while ((*q++ = *p++) != '\0') 8893 while ((*q++ = *p++) != '\0')
@@ -9149,9 +8957,29 @@ procargs(argc, argv)
9149 * to the argument list; we advance it past the options. 8957 * to the argument list; we advance it past the options.
9150 */ 8958 */
9151 8959
8960static inline void
8961minus_o(const char *name, int val)
8962{
8963 int i;
8964
8965 if (name == NULL) {
8966 out1str("Current option settings\n");
8967 for (i = 0; i < NOPTS; i++)
8968 printf("%-16s%s\n", optent_name(optlist[i]),
8969 optent_val(i) ? "on" : "off");
8970 } else {
8971 for (i = 0; i < NOPTS; i++)
8972 if (equal(name, optent_name(optlist[i]))) {
8973 setoption(optent_letter(optlist[i]), val);
8974 return;
8975 }
8976 error("Illegal option -o %s", name);
8977 }
8978}
8979
8980
9152static void 8981static void
9153options(cmdline) 8982options(int cmdline)
9154 int cmdline;
9155{ 8983{
9156 char *p; 8984 char *p;
9157 int val; 8985 int val;
@@ -9204,28 +9032,6 @@ options(cmdline)
9204 } 9032 }
9205} 9033}
9206 9034
9207static void
9208minus_o(name, val)
9209 char *name;
9210 int val;
9211{
9212 int i;
9213
9214 if (name == NULL) {
9215 out1str("Current option settings\n");
9216 for (i = 0; i < NOPTS; i++)
9217 out1fmt("%-16s%s\n", optent_name(optlist[i]),
9218 optent_val(i) ? "on" : "off");
9219 } else {
9220 for (i = 0; i < NOPTS; i++)
9221 if (equal(name, optent_name(optlist[i]))) {
9222 setoption(optent_letter(optlist[i]), val);
9223 return;
9224 }
9225 error("Illegal option -o %s", name);
9226 }
9227}
9228
9229 9035
9230static void 9036static void
9231setoption(int flag, int val) 9037setoption(int flag, int val)
@@ -9528,7 +9334,6 @@ out:
9528 if (err) { 9334 if (err) {
9529 *myoptind = 1; 9335 *myoptind = 1;
9530 *optoff = -1; 9336 *optoff = -1;
9531 flushall();
9532 exraise(EXERROR); 9337 exraise(EXERROR);
9533 } 9338 }
9534 return done; 9339 return done;
@@ -9547,9 +9352,8 @@ out:
9547 */ 9352 */
9548 9353
9549static int 9354static int
9550nextopt(optstring) 9355nextopt(const char *optstring)
9551 const char *optstring; 9356{
9552 {
9553 char *p; 9357 char *p;
9554 const char *q; 9358 const char *q;
9555 char c; 9359 char c;
@@ -9596,16 +9400,6 @@ out2fmt(const char *fmt, ...)
9596 va_end(ap); 9400 va_end(ap);
9597} 9401}
9598 9402
9599
9600static void
9601out1fmt(const char *fmt, ...)
9602{
9603 va_list ap;
9604 va_start(ap, fmt);
9605 vfprintf(stdout, fmt, ap);
9606 va_end(ap);
9607}
9608
9609/* 9403/*
9610 * Version of write which resumes after a signal is caught. 9404 * Version of write which resumes after a signal is caught.
9611 */ 9405 */
@@ -11121,26 +10915,21 @@ synerror(const char *msg)
11121 * called by editline -- any expansions to the prompt 10915 * called by editline -- any expansions to the prompt
11122 * should be added here. 10916 * should be added here.
11123 */ 10917 */
11124static inline const char * 10918static void
11125getprompt(void *unused) 10919setprompt(int whichprompt)
11126{ 10920{
11127 switch (whichprompt) { 10921 char *prompt;
11128 case 0: 10922 switch (whichprompt) {
11129 return "";
11130 case 1: 10923 case 1:
11131 return ps1val(); 10924 prompt = ps1val();
10925 break;
11132 case 2: 10926 case 2:
11133 return ps2val(); 10927 prompt = ps2val();
11134 default: 10928 break;
11135 return "<internal prompt error>"; 10929 default: /* 0 */
11136 } 10930 prompt = "";
11137} 10931 }
11138 10932 putprompt(prompt);
11139static void
11140setprompt(int which)
11141{
11142 whichprompt = which;
11143 putprompt(getprompt(NULL));
11144} 10933}
11145 10934
11146 10935
@@ -11156,90 +10945,109 @@ setprompt(int which)
11156#endif 10945#endif
11157 10946
11158 10947
11159
11160/* 10948/*
11161 * Process a list of redirection commands. If the REDIR_PUSH flag is set, 10949 * Open a file in noclobber mode.
11162 * old file descriptors are stashed away so that the redirection can be 10950 * The code was copied from bash.
11163 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11164 * standard output, and the standard error if it becomes a duplicate of
11165 * stdout.
11166 */ 10951 */
10952static inline int
10953noclobberopen(const char *fname)
10954{
10955 int r, fd;
10956 struct stat finfo, finfo2;
11167 10957
11168static void 10958 /*
11169redirect(redir, flags) 10959 * If the file exists and is a regular file, return an error
11170 union node *redir; 10960 * immediately.
11171 int flags; 10961 */
11172 { 10962 r = stat(fname, &finfo);
11173 union node *n; 10963 if (r == 0 && S_ISREG(finfo.st_mode)) {
11174 struct redirtab *sv = NULL; 10964 errno = EEXIST;
11175 int i; 10965 return -1;
11176 int fd;
11177 int newfd;
11178 int try;
11179 char memory[10]; /* file descriptors to write to memory */
11180
11181 for (i = 10 ; --i >= 0 ; )
11182 memory[i] = 0;
11183 memory[1] = flags & REDIR_BACKQ;
11184 if (flags & REDIR_PUSH) {
11185 sv = ckmalloc(sizeof (struct redirtab));
11186 for (i = 0 ; i < 10 ; i++)
11187 sv->renamed[i] = EMPTY;
11188 sv->next = redirlist;
11189 redirlist = sv;
11190 } 10966 }
11191 for (n = redir ; n ; n = n->nfile.next) {
11192 fd = n->nfile.fd;
11193 try = 0;
11194 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
11195 n->ndup.dupfd == fd)
11196 continue; /* redirect from/to same file descriptor */
11197 10967
11198 INTOFF; 10968 /*
11199 newfd = openredirect(n); 10969 * If the file was not present (r != 0), make sure we open it
11200 if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) { 10970 * exclusively so that if it is created before we open it, our open
11201 if (newfd == fd) { 10971 * will fail. Make sure that we do not truncate an existing file.
11202 try++; 10972 * Note that we don't turn on O_EXCL unless the stat failed -- if the
11203 } else if ((i = fcntl(fd, F_DUPFD, 10)) == -1) { 10973 * file was not a regular file, we leave O_EXCL off.
11204 switch (errno) { 10974 */
11205 case EBADF: 10975 if (r != 0)
11206 if (!try) { 10976 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
11207 dupredirect(n, newfd, memory); 10977 fd = open(fname, O_WRONLY|O_CREAT, 0666);
11208 try++; 10978
11209 break; 10979 /* If the open failed, return the file descriptor right away. */
11210 } 10980 if (fd < 0)
11211 /* FALLTHROUGH*/ 10981 return fd;
11212 default: 10982
11213 if (newfd >= 0) { 10983 /*
11214 close(newfd); 10984 * OK, the open succeeded, but the file may have been changed from a
11215 } 10985 * non-regular file to a regular file between the stat and the open.
11216 INTON; 10986 * We are assuming that the O_EXCL open handles the case where FILENAME
11217 error("%d: %m", fd); 10987 * did not exist and is symlinked to an existing file between the stat
11218 /* NOTREACHED */ 10988 * and open.
11219 } 10989 */
11220 } 10990
11221 if (!try) { 10991 /*
11222 close(fd); 10992 * If we can open it and fstat the file descriptor, and neither check
11223 if (flags & REDIR_PUSH) { 10993 * revealed that it was a regular file, and the file has not been
11224 sv->renamed[fd] = i; 10994 * replaced, return the file descriptor.
11225 } 10995 */
11226 } 10996 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
11227 } else if (fd != newfd) { 10997 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
11228 close(fd); 10998 return fd;
10999
11000 /* The file has been replaced. badness. */
11001 close(fd);
11002 errno = EEXIST;
11003 return -1;
11004}
11005
11006/*
11007 * Handle here documents. Normally we fork off a process to write the
11008 * data to a pipe. If the document is short, we can stuff the data in
11009 * the pipe without forking.
11010 */
11011
11012static inline int
11013openhere(const union node *redir)
11014{
11015 int pip[2];
11016 int len = 0;
11017
11018 if (pipe(pip) < 0)
11019 error("Pipe call failed");
11020 if (redir->type == NHERE) {
11021 len = strlen(redir->nhere.doc->narg.text);
11022 if (len <= PIPESIZE) {
11023 xwrite(pip[1], redir->nhere.doc->narg.text, len);
11024 goto out;
11229 } 11025 }
11230 if (fd == 0)
11231 fd0_redirected++;
11232 if (!try)
11233 dupredirect(n, newfd, memory);
11234 INTON;
11235 } 11026 }
11027 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
11028 close(pip[0]);
11029 signal(SIGINT, SIG_IGN);
11030 signal(SIGQUIT, SIG_IGN);
11031 signal(SIGHUP, SIG_IGN);
11032#ifdef SIGTSTP
11033 signal(SIGTSTP, SIG_IGN);
11034#endif
11035 signal(SIGPIPE, SIG_DFL);
11036 if (redir->type == NHERE)
11037 xwrite(pip[1], redir->nhere.doc->narg.text, len);
11038 else
11039 expandhere(redir->nhere.doc, pip[1]);
11040 _exit(0);
11041 }
11042out:
11043 close(pip[1]);
11044 return pip[0];
11236} 11045}
11237 11046
11238 11047
11239static int 11048static inline int
11240openredirect(redir) 11049openredirect(const union node *redir)
11241 union node *redir; 11050{
11242 {
11243 char *fname; 11051 char *fname;
11244 int f; 11052 int f;
11245 11053
@@ -11307,17 +11115,90 @@ eopen:
11307} 11115}
11308 11116
11309 11117
11118/*
11119 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11120 * old file descriptors are stashed away so that the redirection can be
11121 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11122 * standard output, and the standard error if it becomes a duplicate of
11123 * stdout.
11124 */
11125
11126static void
11127redirect(union node *redir, int flags)
11128{
11129 union node *n;
11130 struct redirtab *sv = NULL;
11131 int i;
11132 int fd;
11133 int newfd;
11134 int try;
11135 int fd1dup = flags & REDIR_BACKQ;; /* stdout `cmd` redir to pipe */
11136
11137 if (flags & REDIR_PUSH) {
11138 sv = ckmalloc(sizeof (struct redirtab));
11139 for (i = 0 ; i < 10 ; i++)
11140 sv->renamed[i] = EMPTY;
11141 sv->next = redirlist;
11142 redirlist = sv;
11143 }
11144 for (n = redir ; n ; n = n->nfile.next) {
11145 fd = n->nfile.fd;
11146 try = 0;
11147 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
11148 n->ndup.dupfd == fd)
11149 continue; /* redirect from/to same file descriptor */
11150
11151 INTOFF;
11152 newfd = openredirect(n);
11153 if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
11154 if (newfd == fd) {
11155 try++;
11156 } else if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
11157 switch (errno) {
11158 case EBADF:
11159 if (!try) {
11160 dupredirect(n, newfd, fd1dup);
11161 try++;
11162 break;
11163 }
11164 /* FALLTHROUGH*/
11165 default:
11166 if (newfd >= 0) {
11167 close(newfd);
11168 }
11169 INTON;
11170 error("%d: %m", fd);
11171 /* NOTREACHED */
11172 }
11173 }
11174 if (!try) {
11175 close(fd);
11176 if (flags & REDIR_PUSH) {
11177 sv->renamed[fd] = i;
11178 }
11179 }
11180 } else if (fd != newfd) {
11181 close(fd);
11182 }
11183 if (fd == 0)
11184 fd0_redirected++;
11185 if (!try)
11186 dupredirect(n, newfd, fd1dup);
11187 INTON;
11188 }
11189}
11190
11191
11310static void 11192static void
11311dupredirect(union node *redir, int f, char memory[10]) 11193dupredirect(const union node *redir, int f, int fd1dup)
11312{ 11194{
11313 int fd = redir->nfile.fd; 11195 int fd = redir->nfile.fd;
11314 11196
11315 memory[fd] = 0; 11197 if(fd==1)
11198 fd1dup = 0;
11316 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) { 11199 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
11317 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */ 11200 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
11318 if (memory[redir->ndup.dupfd]) 11201 if (redir->ndup.dupfd!=1 || fd1dup!=1)
11319 memory[fd] = 1;
11320 else
11321 dup_as_newfd(redir->ndup.dupfd, fd); 11202 dup_as_newfd(redir->ndup.dupfd, fd);
11322 } 11203 }
11323 return; 11204 return;
@@ -11331,48 +11212,6 @@ dupredirect(union node *redir, int f, char memory[10])
11331} 11212}
11332 11213
11333 11214
11334/*
11335 * Handle here documents. Normally we fork off a process to write the
11336 * data to a pipe. If the document is short, we can stuff the data in
11337 * the pipe without forking.
11338 */
11339
11340static int
11341openhere(redir)
11342 union node *redir;
11343 {
11344 int pip[2];
11345 int len = 0;
11346
11347 if (pipe(pip) < 0)
11348 error("Pipe call failed");
11349 if (redir->type == NHERE) {
11350 len = strlen(redir->nhere.doc->narg.text);
11351 if (len <= PIPESIZE) {
11352 xwrite(pip[1], redir->nhere.doc->narg.text, len);
11353 goto out;
11354 }
11355 }
11356 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
11357 close(pip[0]);
11358 signal(SIGINT, SIG_IGN);
11359 signal(SIGQUIT, SIG_IGN);
11360 signal(SIGHUP, SIG_IGN);
11361#ifdef SIGTSTP
11362 signal(SIGTSTP, SIG_IGN);
11363#endif
11364 signal(SIGPIPE, SIG_DFL);
11365 if (redir->type == NHERE)
11366 xwrite(pip[1], redir->nhere.doc->narg.text, len);
11367 else
11368 expandhere(redir->nhere.doc, pip[1]);
11369 _exit(0);
11370 }
11371out:
11372 close(pip[1]);
11373 return pip[0];
11374}
11375
11376 11215
11377/* 11216/*
11378 * Undo the effects of the last redirection. 11217 * Undo the effects of the last redirection.
@@ -11444,70 +11283,17 @@ dup_as_newfd(from, to)
11444 return newfd; 11283 return newfd;
11445} 11284}
11446 11285
11447/*
11448 * Open a file in noclobber mode.
11449 * The code was copied from bash.
11450 */
11451static int
11452noclobberopen(const char *fname)
11453{
11454 int r, fd;
11455 struct stat finfo, finfo2;
11456
11457 /*
11458 * If the file exists and is a regular file, return an error
11459 * immediately.
11460 */
11461 r = stat(fname, &finfo);
11462 if (r == 0 && S_ISREG(finfo.st_mode)) {
11463 errno = EEXIST;
11464 return -1;
11465 }
11466
11467 /*
11468 * If the file was not present (r != 0), make sure we open it
11469 * exclusively so that if it is created before we open it, our open
11470 * will fail. Make sure that we do not truncate an existing file.
11471 * Note that we don't turn on O_EXCL unless the stat failed -- if the
11472 * file was not a regular file, we leave O_EXCL off.
11473 */
11474 if (r != 0)
11475 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
11476 fd = open(fname, O_WRONLY|O_CREAT, 0666);
11477
11478 /* If the open failed, return the file descriptor right away. */
11479 if (fd < 0)
11480 return fd;
11481
11482 /*
11483 * OK, the open succeeded, but the file may have been changed from a
11484 * non-regular file to a regular file between the stat and the open.
11485 * We are assuming that the O_EXCL open handles the case where FILENAME
11486 * did not exist and is symlinked to an existing file between the stat
11487 * and open.
11488 */
11489
11490 /*
11491 * If we can open it and fstat the file descriptor, and neither check
11492 * revealed that it was a regular file, and the file has not been
11493 * replaced, return the file descriptor.
11494 */
11495 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
11496 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
11497 return fd;
11498
11499 /* The file has been replaced. badness. */
11500 close(fd);
11501 errno = EEXIST;
11502 return -1;
11503}
11504/*#ifdef __weak_alias 11286/*#ifdef __weak_alias
11505__weak_alias(getmode,_getmode) 11287__weak_alias(getmode,_getmode)
11506__weak_alias(setmode,_setmode) 11288__weak_alias(setmode,_setmode)
11507#endif*/ 11289#endif*/
11508 11290
11509#ifdef __GLIBC__ 11291#ifndef S_ISTXT
11292#if defined(__GLIBC__) && __GLIBC__ >= 2
11510#define S_ISTXT __S_ISVTX 11293#define S_ISTXT __S_ISVTX
11294#else
11295#define S_ISTXT S_ISVTX
11296#endif
11511#endif 11297#endif
11512 11298
11513#define SET_LEN 6 /* initial # of bitcmd struct to malloc */ 11299#define SET_LEN 6 /* initial # of bitcmd struct to malloc */
@@ -11665,7 +11451,7 @@ setmode(p)
11665 * If an absolute number, get it and return; disallow non-octal digits 11451 * If an absolute number, get it and return; disallow non-octal digits
11666 * or illegal bits. 11452 * or illegal bits.
11667 */ 11453 */
11668 if (isdigit((unsigned char)*p)) { 11454 if (is_digit((unsigned char)*p)) {
11669 perm = (mode_t)strtol(p, &ep, 8); 11455 perm = (mode_t)strtol(p, &ep, 8);
11670 if (*ep || perm & ~(STANDARD_BITS|S_ISTXT)) { 11456 if (*ep || perm & ~(STANDARD_BITS|S_ISTXT)) {
11671 free(saveset); 11457 free(saveset);
@@ -12320,7 +12106,7 @@ trapcmd(argc, argv)
12320 char *p; 12106 char *p;
12321 12107
12322 p = single_quote(trap[signo]); 12108 p = single_quote(trap[signo]);
12323 out1fmt("trap -- %s %s\n", p, 12109 printf("trap -- %s %s\n", p,
12324 signal_names[signo] + (signo ? 3 : 0) 12110 signal_names[signo] + (signo ? 3 : 0)
12325 ); 12111 );
12326 stunalloc(p); 12112 stunalloc(p);
@@ -12734,7 +12520,7 @@ listsetvar(mylist)
12734 * Find the value of a variable. Returns NULL if not set. 12520 * Find the value of a variable. Returns NULL if not set.
12735 */ 12521 */
12736 12522
12737static char * 12523static const char *
12738lookupvar(name) 12524lookupvar(name)
12739 const char *name; 12525 const char *name;
12740 { 12526 {
@@ -12752,11 +12538,10 @@ lookupvar(name)
12752 * Search the environment of a builtin command. 12538 * Search the environment of a builtin command.
12753 */ 12539 */
12754 12540
12755static char * 12541static const char *
12756bltinlookup(name) 12542bltinlookup(const char *name)
12757 const char *name;
12758{ 12543{
12759 struct strlist *sp; 12544 const struct strlist *sp;
12760 12545
12761 for (sp = cmdenviron ; sp ; sp = sp->next) { 12546 for (sp = cmdenviron ; sp ; sp = sp->next) {
12762 if (varequal(sp->text, name)) 12547 if (varequal(sp->text, name))
@@ -13038,9 +12823,8 @@ unsetcmd(argc, argv)
13038 */ 12823 */
13039 12824
13040static int 12825static int
13041unsetvar(s) 12826unsetvar(const char *s)
13042 const char *s; 12827{
13043 {
13044 struct var **vpp; 12828 struct var **vpp;
13045 struct var *vp; 12829 struct var *vp;
13046 12830
@@ -13074,9 +12858,8 @@ unsetvar(s)
13074 */ 12858 */
13075 12859
13076static struct var ** 12860static struct var **
13077hashvar(p) 12861hashvar(const char *p)
13078 const char *p; 12862{
13079 {
13080 unsigned int hashval; 12863 unsigned int hashval;
13081 12864
13082 hashval = ((unsigned char) *p) << 4; 12865 hashval = ((unsigned char) *p) << 4;
@@ -13094,9 +12877,8 @@ hashvar(p)
13094 */ 12877 */
13095 12878
13096static int 12879static int
13097varequal(p, q) 12880varequal(const char *p, const char *q)
13098 const char *p, *q; 12881{
13099 {
13100 while (*p == *q++) { 12882 while (*p == *q++) {
13101 if (*p++ == '=') 12883 if (*p++ == '=')
13102 return 1; 12884 return 1;
@@ -13123,10 +12905,8 @@ showvars(const char *myprefix, int mask, int xor)
13123 len = p - vp->text; 12905 len = p - vp->text;
13124 p = single_quote(p); 12906 p = single_quote(p);
13125 12907
13126 out1fmt( 12908 printf("%s%s%.*s%s\n", myprefix, sep, len,
13127 "%s%s%.*s%s\n", myprefix, sep, len, 12909 vp->text, p);
13128 vp->text, p
13129 );
13130 stunalloc(p); 12910 stunalloc(p);
13131 } 12911 }
13132 } 12912 }
@@ -13147,7 +12927,7 @@ findvar(struct var **vpp, const char *name)
13147/* 12927/*
13148 * Copyright (c) 1999 Herbert Xu <herbert@debian.org> 12928 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
13149 * This file contains code for the times builtin. 12929 * This file contains code for the times builtin.
13150 * $Id: ash.c,v 1.7 2001/07/07 00:05:55 andersen Exp $ 12930 * $Id: ash.c,v 1.8 2001/07/10 06:09:16 andersen Exp $
13151 */ 12931 */
13152static int timescmd (int argc, char **argv) 12932static int timescmd (int argc, char **argv)
13153{ 12933{
diff --git a/shell/ash.c b/shell/ash.c
index 4250f50e2..5756c6304 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -36,15 +36,14 @@
36/* These defines allow you to adjust the feature set to be compiled 36/* These defines allow you to adjust the feature set to be compiled
37 * into the ash shell. As a rule, enabling these options will make 37 * into the ash shell. As a rule, enabling these options will make
38 * ash get bigger... With all of these options off, ash adds about 38 * ash get bigger... With all of these options off, ash adds about
39 * 62k to busybox on an x86 system.*/ 39 * 60k to busybox on an x86 system.*/
40
41 40
42 41
43/* Enable job control. This allows you to run jobs in the background, 42/* Enable job control. This allows you to run jobs in the background,
44 * which is great when ash is being used as an interactive shell, but 43 * which is great when ash is being used as an interactive shell, but
45 * it completely useless for is all you are doing is running scripts. 44 * it completely useless for is all you are doing is running scripts.
46 * This adds about 2.5k on an x86 system. */ 45 * This adds about 2.5k on an x86 system. */
47#define JOBS 46#undef JOBS
48 47
49/* This enables alias support in ash. If you want to support things 48/* This enables alias support in ash. If you want to support things
50 * like "alias ls='ls -l'" with ash, enable this. This is only useful 49 * like "alias ls='ls -l'" with ash, enable this. This is only useful
@@ -56,12 +55,6 @@
56 * doesn't compile right now... */ 55 * doesn't compile right now... */
57#undef ASH_MATH_SUPPORT 56#undef ASH_MATH_SUPPORT
58 57
59/* This shell builtin is used to indicate how the shell would interpret
60 * what you give it. This command is only useful when debugging, and
61 * is obsolete anyways. Adds about 670 bytes... You probably want to
62 * leave this disabled. */
63#undef ASH_TYPE
64
65/* Getopts is used by shell procedures to parse positional parameters. 58/* Getopts is used by shell procedures to parse positional parameters.
66 * You probably want to leave this disabled, and use the busybox getopt 59 * You probably want to leave this disabled, and use the busybox getopt
67 * applet if you want to do this sort of thing. There are some scripts 60 * applet if you want to do this sort of thing. There are some scripts
@@ -71,13 +64,9 @@
71 64
72/* This allows you to override shell builtins and use whatever is on 65/* This allows you to override shell builtins and use whatever is on
73 * the filesystem. This is most useful when ash is acting as a 66 * the filesystem. This is most useful when ash is acting as a
74 * standalone shell. Adds about 320 bytes. */ 67 * standalone shell. Adds about 272 bytes. */
75#undef ASH_CMDCMD 68#undef ASH_CMDCMD
76 69
77/* This makes a few common apps that are usually part of busybox
78 * anyways to be used as builtins. This may cause these builtins to be
79 * a little bit faster, but leaving this disabled will save you 2k. */
80#undef ASH_BBAPPS_AS_BUILTINS
81 70
82/* Optimize size vs speed as size */ 71/* Optimize size vs speed as size */
83#define ASH_OPTIMIZE_FOR_SIZE 72#define ASH_OPTIMIZE_FOR_SIZE
@@ -87,8 +76,6 @@
87 * will generate a core dump. */ 76 * will generate a core dump. */
88#undef DEBUG 77#undef DEBUG
89 78
90
91
92/* These are here to work with glibc -- Don't change these... */ 79/* These are here to work with glibc -- Don't change these... */
93#undef FNMATCH_BROKEN 80#undef FNMATCH_BROKEN
94#undef GLOB_BROKEN 81#undef GLOB_BROKEN
@@ -105,7 +92,6 @@
105#include <setjmp.h> 92#include <setjmp.h>
106#include <signal.h> 93#include <signal.h>
107#include <stdarg.h> 94#include <stdarg.h>
108#include <stdbool.h>
109#include <stdio.h> 95#include <stdio.h>
110#include <stdlib.h> 96#include <stdlib.h>
111#include <string.h> 97#include <string.h>
@@ -217,7 +203,7 @@
217#define CTLENDARI '\207' 203#define CTLENDARI '\207'
218#define CTLQUOTEMARK '\210' 204#define CTLQUOTEMARK '\210'
219 205
220#define is_digit(c) ((((unsigned char)(c)) - '0') <= 9) 206#define is_digit(c) ((c)>='0' && (c)<='9')
221#define is_alpha(c) (((c) < CTLESC || (c) > CTLENDARI) && isalpha((unsigned char) (c))) 207#define is_alpha(c) (((c) < CTLESC || (c) > CTLENDARI) && isalpha((unsigned char) (c)))
222#define is_name(c) (((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalpha((unsigned char) (c)))) 208#define is_name(c) (((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalpha((unsigned char) (c))))
223#define is_in_name(c) (((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalnum((unsigned char) (c)))) 209#define is_in_name(c) (((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalnum((unsigned char) (c))))
@@ -262,7 +248,7 @@
262 * so we use _setjmp instead. 248 * so we use _setjmp instead.
263 */ 249 */
264 250
265#if !defined(__GLIBC__) 251#if defined(BSD)
266#define setjmp(jmploc) _setjmp(jmploc) 252#define setjmp(jmploc) _setjmp(jmploc)
267#define longjmp(jmploc, val) _longjmp(jmploc, val) 253#define longjmp(jmploc, val) _longjmp(jmploc, val)
268#endif 254#endif
@@ -662,18 +648,55 @@ struct shparam {
662 int optoff; /* used by getopts */ 648 int optoff; /* used by getopts */
663}; 649};
664 650
651/*
652 * When commands are first encountered, they are entered in a hash table.
653 * This ensures that a full path search will not have to be done for them
654 * on each invocation.
655 *
656 * We should investigate converting to a linear search, even though that
657 * would make the command name "hash" a misnomer.
658 */
659#define CMDTABLESIZE 31 /* should be prime */
660#define ARB 1 /* actual size determined at run time */
661
662
663
664struct tblentry {
665 struct tblentry *next; /* next entry in hash chain */
666 union param param; /* definition of builtin function */
667 short cmdtype; /* index identifying command */
668 char rehash; /* if set, cd done since entry created */
669 char cmdname[ARB]; /* name of command */
670};
671
672
673static struct tblentry *cmdtable[CMDTABLESIZE];
674static int builtinloc = -1; /* index in path of %builtin, or -1 */
675static int exerrno = 0; /* Last exec error */
676
677
678static void tryexec (char *, char **, char **);
679static void printentry (struct tblentry *, int);
680static void clearcmdentry (int);
681static struct tblentry *cmdlookup (const char *, int);
682static void delete_cmd_entry (void);
683static int path_change (const char *, int *);
684
685
665static void flushall (void); 686static void flushall (void);
666static void out2fmt (const char *, ...) 687static void out2fmt (const char *, ...)
667 __attribute__((__format__(__printf__,1,2))); 688 __attribute__((__format__(__printf__,1,2)));
668static void out1fmt (const char *, ...)
669 __attribute__((__format__(__printf__,1,2)));
670static int xwrite (int, const char *, int); 689static int xwrite (int, const char *, int);
671 690
672static void outstr (const char *p, FILE *file) { fputs(p, file); } 691static void outstr (const char *p, FILE *file) { fputs(p, file); }
673static void out1str(const char *p) { outstr(p, stdout); } 692static void out1str(const char *p) { outstr(p, stdout); }
674static void out2str(const char *p) { outstr(p, stderr); } 693static void out2str(const char *p) { outstr(p, stderr); }
675 694
695#ifndef ASH_OPTIMIZE_FOR_SIZE
676#define out2c(c) putc((c), stderr) 696#define out2c(c) putc((c), stderr)
697#else
698static void out2c(int c) { putc(c, stderr); }
699#endif
677 700
678/* syntax table used when not in quotes */ 701/* syntax table used when not in quotes */
679static const char basesyntax[257] = { 702static const char basesyntax[257] = {
@@ -1193,7 +1216,7 @@ struct localvar {
1193}; 1216};
1194 1217
1195 1218
1196#if defined(__GLIBC__) && !defined(FNMATCH_BROKEN) 1219#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
1197#define rmescapes(p) _rmescapes((p), 0) 1220#define rmescapes(p) _rmescapes((p), 0)
1198static char *_rmescapes (char *, int); 1221static char *_rmescapes (char *, int);
1199#else 1222#else
@@ -1316,8 +1339,8 @@ static void initvar (void);
1316static void setvar (const char *, const char *, int); 1339static void setvar (const char *, const char *, int);
1317static void setvareq (char *, int); 1340static void setvareq (char *, int);
1318static void listsetvar (struct strlist *); 1341static void listsetvar (struct strlist *);
1319static char *lookupvar (const char *); 1342static const char *lookupvar (const char *);
1320static char *bltinlookup (const char *); 1343static const char *bltinlookup (const char *);
1321static char **environment (void); 1344static char **environment (void);
1322static int showvarscmd (int, char **); 1345static int showvarscmd (int, char **);
1323static void mklocal (char *); 1346static void mklocal (char *);
@@ -1433,7 +1456,7 @@ printalias(const struct alias *ap) {
1433 char *p; 1456 char *p;
1434 1457
1435 p = single_quote(ap->val); 1458 p = single_quote(ap->val);
1436 out1fmt("alias %s=%s\n", ap->name, p); 1459 printf("alias %s=%s\n", ap->name, p);
1437 stunalloc(p); 1460 stunalloc(p);
1438} 1461}
1439 1462
@@ -1627,18 +1650,14 @@ static int timescmd (int, char **);
1627#ifdef ASH_MATH_SUPPORT 1650#ifdef ASH_MATH_SUPPORT
1628static int expcmd (int, char **); 1651static int expcmd (int, char **);
1629#endif 1652#endif
1630#ifdef ASH_TYPE
1631static int typecmd (int, char **); 1653static int typecmd (int, char **);
1632#endif
1633#ifdef ASH_GETOPTS 1654#ifdef ASH_GETOPTS
1634static int getoptscmd (int, char **); 1655static int getoptscmd (int, char **);
1635#endif 1656#endif
1636 1657
1637#ifndef BB_TRUE_FALSE 1658#ifndef BB_TRUE_FALSE
1638# ifdef ASH_BBAPPS_AS_BUILTINS
1639static int true_main (int, char **); 1659static int true_main (int, char **);
1640static int false_main (int, char **); 1660static int false_main (int, char **);
1641# endif
1642#endif 1661#endif
1643 1662
1644static void setpwd (const char *, int); 1663static void setpwd (const char *, int);
@@ -1669,7 +1688,7 @@ struct builtincmd {
1669 * have been warned. 1688 * have been warned.
1670 */ 1689 */
1671static const struct builtincmd builtincmds[] = { 1690static const struct builtincmd builtincmds[] = {
1672 { BUILTIN_SPECIAL ".", dotcmd }, 1691 { BUILTIN_SPECIAL ".", dotcmd }, /* first, see declare DOTCMD */
1673 { BUILTIN_SPECIAL ":", true_main }, 1692 { BUILTIN_SPECIAL ":", true_main },
1674#ifdef ASH_ALIAS 1693#ifdef ASH_ALIAS
1675 { BUILTIN_REG_ASSG "alias", aliascmd }, 1694 { BUILTIN_REG_ASSG "alias", aliascmd },
@@ -1680,9 +1699,7 @@ static const struct builtincmd builtincmds[] = {
1680 { BUILTIN_SPECIAL "break", breakcmd }, 1699 { BUILTIN_SPECIAL "break", breakcmd },
1681 { BUILTIN_SPECIAL "builtin", bltincmd }, 1700 { BUILTIN_SPECIAL "builtin", bltincmd },
1682 { BUILTIN_REGULAR "cd", cdcmd }, 1701 { BUILTIN_REGULAR "cd", cdcmd },
1683#ifdef ASH_BBAPPS_AS_BUILTINS
1684 { BUILTIN_NOSPEC "chdir", cdcmd }, 1702 { BUILTIN_NOSPEC "chdir", cdcmd },
1685#endif
1686#ifdef ASH_CMDCMD 1703#ifdef ASH_CMDCMD
1687 { BUILTIN_REGULAR "command", commandcmd }, 1704 { BUILTIN_REGULAR "command", commandcmd },
1688#endif 1705#endif
@@ -1694,9 +1711,7 @@ static const struct builtincmd builtincmds[] = {
1694 { BUILTIN_NOSPEC "exp", expcmd }, 1711 { BUILTIN_NOSPEC "exp", expcmd },
1695#endif 1712#endif
1696 { BUILTIN_SPEC_ASSG "export", exportcmd }, 1713 { BUILTIN_SPEC_ASSG "export", exportcmd },
1697#ifdef ASH_BBAPPS_AS_BUILTINS
1698 { BUILTIN_REGULAR "false", false_main }, 1714 { BUILTIN_REGULAR "false", false_main },
1699#endif
1700 { BUILTIN_REGULAR "fc", histcmd }, 1715 { BUILTIN_REGULAR "fc", histcmd },
1701#ifdef JOBS 1716#ifdef JOBS
1702 { BUILTIN_REGULAR "fg", fgcmd }, 1717 { BUILTIN_REGULAR "fg", fgcmd },
@@ -1725,12 +1740,8 @@ static const struct builtincmd builtincmds[] = {
1725 { BUILTIN_SPECIAL "shift", shiftcmd }, 1740 { BUILTIN_SPECIAL "shift", shiftcmd },
1726 { BUILTIN_SPECIAL "times", timescmd }, 1741 { BUILTIN_SPECIAL "times", timescmd },
1727 { BUILTIN_SPECIAL "trap", trapcmd }, 1742 { BUILTIN_SPECIAL "trap", trapcmd },
1728#ifdef ASH_BBAPPS_AS_BUILTINS
1729 { BUILTIN_REGULAR "true", true_main }, 1743 { BUILTIN_REGULAR "true", true_main },
1730#endif
1731#ifdef ASH_TYPE
1732 { BUILTIN_NOSPEC "type", typecmd }, 1744 { BUILTIN_NOSPEC "type", typecmd },
1733#endif
1734 { BUILTIN_NOSPEC "ulimit", ulimitcmd }, 1745 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
1735 { BUILTIN_REGULAR "umask", umaskcmd }, 1746 { BUILTIN_REGULAR "umask", umaskcmd },
1736#ifdef ASH_ALIAS 1747#ifdef ASH_ALIAS
@@ -1796,8 +1807,8 @@ static int jobctl;
1796#endif 1807#endif
1797static int intreceived; 1808static int intreceived;
1798 1809
1799static struct job *makejob (union node *, int); 1810static struct job *makejob (const union node *, int);
1800static int forkshell (struct job *, union node *, int); 1811static int forkshell (struct job *, const union node *, int);
1801static int waitforjob (struct job *); 1812static int waitforjob (struct job *);
1802 1813
1803static int docd (char *, int); 1814static int docd (char *, int);
@@ -1920,7 +1931,7 @@ docd(dest, print)
1920 updatepwd(badstat ? NULL : dest); 1931 updatepwd(badstat ? NULL : dest);
1921 INTON; 1932 INTON;
1922 if (print && iflag) 1933 if (print && iflag)
1923 out1fmt(snlfmt, curdir); 1934 printf(snlfmt, curdir);
1924 return 0; 1935 return 0;
1925} 1936}
1926 1937
@@ -2009,7 +2020,7 @@ pwdcmd(argc, argv)
2009 int argc; 2020 int argc;
2010 char **argv; 2021 char **argv;
2011{ 2022{
2012 out1fmt(snlfmt, curdir); 2023 printf(snlfmt, curdir);
2013 return 0; 2024 return 0;
2014} 2025}
2015#endif 2026#endif
@@ -2095,6 +2106,7 @@ exraise(int e)
2095 if (handler == NULL) 2106 if (handler == NULL)
2096 abort(); 2107 abort();
2097#endif 2108#endif
2109 flushall();
2098 exception = e; 2110 exception = e;
2099 longjmp(handler->loc, 1); 2111 longjmp(handler->loc, 1);
2100} 2112}
@@ -2156,7 +2168,6 @@ exverror(int cond, const char *msg, va_list ap)
2156 vfprintf(stderr, msg, ap); 2168 vfprintf(stderr, msg, ap);
2157 out2c('\n'); 2169 out2c('\n');
2158 } 2170 }
2159 flushall();
2160 exraise(cond); 2171 exraise(cond);
2161 /* NOTREACHED */ 2172 /* NOTREACHED */
2162} 2173}
@@ -2221,7 +2232,7 @@ exerror(va_alist)
2221 2232
2222struct errname { 2233struct errname {
2223 short errcode; /* error number */ 2234 short errcode; /* error number */
2224 short action; /* operation which encountered the error */ 2235 char action; /* operation which encountered the error */
2225}; 2236};
2226 2237
2227/* 2238/*
@@ -2337,19 +2348,12 @@ static int loopnest; /* current loop nesting level */
2337static int funcnest; /* depth of function calls */ 2348static int funcnest; /* depth of function calls */
2338 2349
2339 2350
2340
2341static struct strlist *cmdenviron; /* environment for builtin command */ 2351static struct strlist *cmdenviron; /* environment for builtin command */
2342static int exitstatus; /* exit status of last command */ 2352static int exitstatus; /* exit status of last command */
2343static int oexitstatus; /* saved exit status */ 2353static int oexitstatus; /* saved exit status */
2344 2354
2345 2355static void evalsubshell (const union node *, int);
2346static void evalloop (union node *, int);
2347static void evalfor (union node *, int);
2348static void evalcase (union node *, int);
2349static void evalsubshell (union node *, int);
2350static void expredir (union node *); 2356static void expredir (union node *);
2351static void evalpipe (union node *);
2352static void evalcommand (union node *, int);
2353static void prehash (union node *); 2357static void prehash (union node *);
2354static void eprintlist (struct strlist *); 2358static void eprintlist (struct strlist *);
2355 2359
@@ -2419,125 +2423,68 @@ evalstring(char *s, int flag)
2419 popstackmark(&smark); 2423 popstackmark(&smark);
2420} 2424}
2421 2425
2426static struct builtincmd *find_builtin (const char *);
2427static void expandarg (union node *, struct arglist *, int);
2428static void calcsize (const union node *);
2429static union node *copynode (const union node *);
2430
2431/*
2432 * Make a copy of a parse tree.
2433 */
2434
2435static int funcblocksize; /* size of structures in function */
2436static int funcstringsize; /* size of strings in node */
2437static pointer funcblock; /* block to allocate function from */
2438static char *funcstring; /* block to allocate strings from */
2439
2440
2441static inline union node *
2442copyfunc(union node *n)
2443{
2444 if (n == NULL)
2445 return NULL;
2446 funcblocksize = 0;
2447 funcstringsize = 0;
2448 calcsize(n);
2449 funcblock = ckmalloc(funcblocksize + funcstringsize);
2450 funcstring = (char *) funcblock + funcblocksize;
2451 return copynode(n);
2452}
2453
2422/* 2454/*
2423 * Evaluate a parse tree. The value is left in the global variable 2455 * Free a parse tree.
2424 * exitstatus.
2425 */ 2456 */
2426static struct builtincmd *find_builtin (const char *);
2427static void defun (char *, union node *);
2428 2457
2429static void 2458static void
2430evaltree(n, flags) 2459freefunc(union node *n)
2431 union node *n;
2432 int flags;
2433{ 2460{
2434 int checkexit = 0; 2461 if (n)
2435 if (n == NULL) { 2462 ckfree(n);
2436 TRACE(("evaltree(NULL) called\n")); 2463}
2437 goto out;
2438 }
2439 TRACE(("evaltree(0x%lx: %d) called\n", (long)n, n->type));
2440 switch (n->type) {
2441 case NSEMI:
2442 evaltree(n->nbinary.ch1, flags & EV_TESTED);
2443 if (evalskip)
2444 goto out;
2445 evaltree(n->nbinary.ch2, flags);
2446 break;
2447 case NAND:
2448 evaltree(n->nbinary.ch1, EV_TESTED);
2449 if (evalskip || exitstatus != 0)
2450 goto out;
2451 evaltree(n->nbinary.ch2, flags);
2452 break;
2453 case NOR:
2454 evaltree(n->nbinary.ch1, EV_TESTED);
2455 if (evalskip || exitstatus == 0)
2456 goto out;
2457 evaltree(n->nbinary.ch2, flags);
2458 break;
2459 case NREDIR:
2460 expredir(n->nredir.redirect);
2461 redirect(n->nredir.redirect, REDIR_PUSH);
2462 evaltree(n->nredir.n, flags);
2463 popredir();
2464 break;
2465 case NSUBSHELL:
2466 evalsubshell(n, flags);
2467 break;
2468 case NBACKGND:
2469 evalsubshell(n, flags);
2470 break;
2471 case NIF: {
2472 evaltree(n->nif.test, EV_TESTED);
2473 if (evalskip)
2474 goto out;
2475 if (exitstatus == 0)
2476 evaltree(n->nif.ifpart, flags);
2477 else if (n->nif.elsepart)
2478 evaltree(n->nif.elsepart, flags);
2479 else
2480 exitstatus = 0;
2481 break;
2482 }
2483 case NWHILE:
2484 case NUNTIL:
2485 evalloop(n, flags);
2486 break;
2487 case NFOR:
2488 evalfor(n, flags);
2489 break;
2490 case NCASE:
2491 evalcase(n, flags);
2492 break;
2493 case NDEFUN: {
2494 struct builtincmd *bcmd;
2495 if (
2496 (bcmd = find_builtin(n->narg.text)) &&
2497 IS_BUILTIN_SPECIAL(bcmd)
2498 ) {
2499 out2fmt("%s is a special built-in\n", n->narg.text);
2500 exitstatus = 1;
2501 break;
2502 }
2503 defun(n->narg.text, n->narg.next);
2504 exitstatus = 0;
2505 break;
2506 }
2507 case NNOT:
2508 evaltree(n->nnot.com, EV_TESTED);
2509 exitstatus = !exitstatus;
2510 break;
2511 2464
2512 case NPIPE: 2465
2513 evalpipe(n); 2466/*
2514 checkexit = 1; 2467 * Add a new command entry, replacing any existing command entry for
2515 break; 2468 * the same name.
2516 case NCMD: 2469 */
2517 evalcommand(n, flags); 2470
2518 checkexit = 1; 2471static inline void
2519 break; 2472addcmdentry(char *name, struct cmdentry *entry)
2520#ifdef DEBUG 2473{
2521 default: 2474 struct tblentry *cmdp;
2522 out1fmt("Node type = %d\n", n->type); 2475
2523 break; 2476 INTOFF;
2524#endif 2477 cmdp = cmdlookup(name, 1);
2478 if (cmdp->cmdtype == CMDFUNCTION) {
2479 freefunc(cmdp->param.func);
2525 } 2480 }
2526out: 2481 cmdp->cmdtype = entry->cmdtype;
2527 if (pendingsigs) 2482 cmdp->param = entry->u;
2528 dotrap(); 2483 INTON;
2529 if (
2530 flags & EV_EXIT ||
2531 (checkexit && eflag && exitstatus && !(flags & EV_TESTED))
2532 )
2533 exitshell(exitstatus);
2534} 2484}
2535 2485
2536 2486static inline void
2537static void 2487evalloop(const union node *n, int flags)
2538evalloop(n, flags)
2539 union node *n;
2540 int flags;
2541{ 2488{
2542 int status; 2489 int status;
2543 2490
@@ -2570,13 +2517,8 @@ skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
2570 exitstatus = status; 2517 exitstatus = status;
2571} 2518}
2572 2519
2573static void expandarg (union node *, struct arglist *, int);
2574static void fixredir(union node *n, const char *text, int err);
2575
2576static void 2520static void
2577evalfor(n, flags) 2521evalfor(const union node *n, int flags)
2578 union node *n;
2579 int flags;
2580{ 2522{
2581 struct arglist arglist; 2523 struct arglist arglist;
2582 union node *argp; 2524 union node *argp;
@@ -2613,11 +2555,8 @@ out:
2613 popstackmark(&smark); 2555 popstackmark(&smark);
2614} 2556}
2615 2557
2616 2558static inline void
2617static void 2559evalcase(const union node *n, int flags)
2618evalcase(n, flags)
2619 union node *n;
2620 int flags;
2621{ 2560{
2622 union node *cp; 2561 union node *cp;
2623 union node *patp; 2562 union node *patp;
@@ -2643,75 +2582,13 @@ out:
2643} 2582}
2644 2583
2645/* 2584/*
2646 * Kick off a subshell to evaluate a tree.
2647 */
2648
2649static void
2650evalsubshell(n, flags)
2651 union node *n;
2652 int flags;
2653{
2654 struct job *jp;
2655 int backgnd = (n->type == NBACKGND);
2656
2657 expredir(n->nredir.redirect);
2658 jp = makejob(n, 1);
2659 if (forkshell(jp, n, backgnd) == 0) {
2660 if (backgnd)
2661 flags &=~ EV_TESTED;
2662 redirect(n->nredir.redirect, 0);
2663 evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */
2664 }
2665 if (! backgnd) {
2666 INTOFF;
2667 exitstatus = waitforjob(jp);
2668 INTON;
2669 }
2670}
2671
2672
2673/*
2674 * Compute the names of the files in a redirection list.
2675 */
2676
2677static void
2678expredir(n)
2679 union node *n;
2680{
2681 union node *redir;
2682
2683 for (redir = n ; redir ; redir = redir->nfile.next) {
2684 struct arglist fn;
2685 fn.lastp = &fn.list;
2686 oexitstatus = exitstatus;
2687 switch (redir->type) {
2688 case NFROMTO:
2689 case NFROM:
2690 case NTO:
2691 case NAPPEND:
2692 case NTOOV:
2693 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
2694 redir->nfile.expfname = fn.list->text;
2695 break;
2696 case NFROMFD:
2697 case NTOFD:
2698 if (redir->ndup.vname) {
2699 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
2700 fixredir(redir, fn.list->text, 1);
2701 }
2702 break;
2703 }
2704 }
2705}
2706
2707/*
2708 * Evaluate a pipeline. All the processes in the pipeline are children 2585 * Evaluate a pipeline. All the processes in the pipeline are children
2709 * of the process creating the pipeline. (This differs from some versions 2586 * of the process creating the pipeline. (This differs from some versions
2710 * of the shell, which make the last process in a pipeline the parent 2587 * of the shell, which make the last process in a pipeline the parent
2711 * of all the rest.) 2588 * of all the rest.)
2712 */ 2589 */
2713 2590
2714static void 2591static inline void
2715evalpipe(n) 2592evalpipe(n)
2716 union node *n; 2593 union node *n;
2717{ 2594{
@@ -2773,61 +2650,6 @@ evalpipe(n)
2773 } 2650 }
2774} 2651}
2775 2652
2776
2777
2778/*
2779 * Execute a command inside back quotes. If it's a builtin command, we
2780 * want to save its output in a block obtained from malloc. Otherwise
2781 * we fork off a subprocess and get the output of the command via a pipe.
2782 * Should be called with interrupts off.
2783 */
2784
2785static void
2786evalbackcmd(union node *n, struct backcmd *result)
2787{
2788 int pip[2];
2789 struct job *jp;
2790 struct stackmark smark; /* unnecessary */
2791
2792 setstackmark(&smark);
2793 result->fd = -1;
2794 result->buf = NULL;
2795 result->nleft = 0;
2796 result->jp = NULL;
2797 if (n == NULL) {
2798 exitstatus = 0;
2799 goto out;
2800 }
2801 exitstatus = 0;
2802 if (pipe(pip) < 0)
2803 error("Pipe call failed");
2804 jp = makejob(n, 1);
2805 if (forkshell(jp, n, FORK_NOJOB) == 0) {
2806 FORCEINTON;
2807 close(pip[0]);
2808 if (pip[1] != 1) {
2809 close(1);
2810 dup_as_newfd(pip[1], 1);
2811 close(pip[1]);
2812 }
2813 eflag = 0;
2814 evaltree(n, EV_EXIT);
2815 }
2816 close(pip[1]);
2817 result->fd = pip[0];
2818 result->jp = jp;
2819out:
2820 popstackmark(&smark);
2821 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
2822 result->fd, result->buf, result->nleft, result->jp));
2823}
2824
2825
2826
2827/*
2828 * Execute a simple command.
2829 */
2830
2831static void find_command (const char *, struct cmdentry *, int, const char *); 2653static void find_command (const char *, struct cmdentry *, int, const char *);
2832 2654
2833static int 2655static int
@@ -2841,6 +2663,7 @@ isassignment(const char *word) {
2841 return *word == '='; 2663 return *word == '=';
2842} 2664}
2843 2665
2666
2844static void 2667static void
2845evalcommand(union node *cmd, int flags) 2668evalcommand(union node *cmd, int flags)
2846{ 2669{
@@ -2892,7 +2715,7 @@ evalcommand(union node *cmd, int flags)
2892 } 2715 }
2893 if (argp) { 2716 if (argp) {
2894 struct builtincmd *bcmd; 2717 struct builtincmd *bcmd;
2895 bool pseudovarflag; 2718 int pseudovarflag;
2896 bcmd = find_builtin(arglist.list->text); 2719 bcmd = find_builtin(arglist.list->text);
2897 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd); 2720 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
2898 for (; argp; argp = argp->narg.next) { 2721 for (; argp; argp = argp->narg.next) {
@@ -3144,9 +2967,234 @@ out:
3144 popstackmark(&smark); 2967 popstackmark(&smark);
3145} 2968}
3146 2969
2970/*
2971 * Evaluate a parse tree. The value is left in the global variable
2972 * exitstatus.
2973 */
2974static void
2975evaltree(n, flags)
2976 union node *n;
2977 int flags;
2978{
2979 int checkexit = 0;
2980 if (n == NULL) {
2981 TRACE(("evaltree(NULL) called\n"));
2982 goto out;
2983 }
2984 TRACE(("evaltree(0x%lx: %d) called\n", (long)n, n->type));
2985 switch (n->type) {
2986 case NSEMI:
2987 evaltree(n->nbinary.ch1, flags & EV_TESTED);
2988 if (evalskip)
2989 goto out;
2990 evaltree(n->nbinary.ch2, flags);
2991 break;
2992 case NAND:
2993 evaltree(n->nbinary.ch1, EV_TESTED);
2994 if (evalskip || exitstatus != 0)
2995 goto out;
2996 evaltree(n->nbinary.ch2, flags);
2997 break;
2998 case NOR:
2999 evaltree(n->nbinary.ch1, EV_TESTED);
3000 if (evalskip || exitstatus == 0)
3001 goto out;
3002 evaltree(n->nbinary.ch2, flags);
3003 break;
3004 case NREDIR:
3005 expredir(n->nredir.redirect);
3006 redirect(n->nredir.redirect, REDIR_PUSH);
3007 evaltree(n->nredir.n, flags);
3008 popredir();
3009 break;
3010 case NSUBSHELL:
3011 evalsubshell(n, flags);
3012 break;
3013 case NBACKGND:
3014 evalsubshell(n, flags);
3015 break;
3016 case NIF: {
3017 evaltree(n->nif.test, EV_TESTED);
3018 if (evalskip)
3019 goto out;
3020 if (exitstatus == 0)
3021 evaltree(n->nif.ifpart, flags);
3022 else if (n->nif.elsepart)
3023 evaltree(n->nif.elsepart, flags);
3024 else
3025 exitstatus = 0;
3026 break;
3027 }
3028 case NWHILE:
3029 case NUNTIL:
3030 evalloop(n, flags);
3031 break;
3032 case NFOR:
3033 evalfor(n, flags);
3034 break;
3035 case NCASE:
3036 evalcase(n, flags);
3037 break;
3038 case NDEFUN: {
3039 struct builtincmd *bcmd;
3040 struct cmdentry entry;
3041 if (
3042 (bcmd = find_builtin(n->narg.text)) &&
3043 IS_BUILTIN_SPECIAL(bcmd)
3044 ) {
3045 out2fmt("%s is a special built-in\n", n->narg.text);
3046 exitstatus = 1;
3047 break;
3048 }
3049 entry.cmdtype = CMDFUNCTION;
3050 entry.u.func = copyfunc(n->narg.next);
3051 addcmdentry(n->narg.text, &entry);
3052 exitstatus = 0;
3053 break;
3054 }
3055 case NNOT:
3056 evaltree(n->nnot.com, EV_TESTED);
3057 exitstatus = !exitstatus;
3058 break;
3059
3060 case NPIPE:
3061 evalpipe(n);
3062 checkexit = 1;
3063 break;
3064 case NCMD:
3065 evalcommand(n, flags);
3066 checkexit = 1;
3067 break;
3068#ifdef DEBUG
3069 default:
3070 printf("Node type = %d\n", n->type);
3071 break;
3072#endif
3073 }
3074out:
3075 if (pendingsigs)
3076 dotrap();
3077 if (
3078 flags & EV_EXIT ||
3079 (checkexit && eflag && exitstatus && !(flags & EV_TESTED))
3080 )
3081 exitshell(exitstatus);
3082}
3083
3084/*
3085 * Kick off a subshell to evaluate a tree.
3086 */
3087
3088static void
3089evalsubshell(const union node *n, int flags)
3090{
3091 struct job *jp;
3092 int backgnd = (n->type == NBACKGND);
3093
3094 expredir(n->nredir.redirect);
3095 jp = makejob(n, 1);
3096 if (forkshell(jp, n, backgnd) == 0) {
3097 if (backgnd)
3098 flags &=~ EV_TESTED;
3099 redirect(n->nredir.redirect, 0);
3100 evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */
3101 }
3102 if (! backgnd) {
3103 INTOFF;
3104 exitstatus = waitforjob(jp);
3105 INTON;
3106 }
3107}
3108
3109/*
3110 * Compute the names of the files in a redirection list.
3111 */
3112
3113static void fixredir(union node *n, const char *text, int err);
3114
3115static void
3116expredir(union node *n)
3117{
3118 union node *redir;
3119
3120 for (redir = n ; redir ; redir = redir->nfile.next) {
3121 struct arglist fn;
3122 fn.lastp = &fn.list;
3123 oexitstatus = exitstatus;
3124 switch (redir->type) {
3125 case NFROMTO:
3126 case NFROM:
3127 case NTO:
3128 case NAPPEND:
3129 case NTOOV:
3130 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
3131 redir->nfile.expfname = fn.list->text;
3132 break;
3133 case NFROMFD:
3134 case NTOFD:
3135 if (redir->ndup.vname) {
3136 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
3137 fixredir(redir, fn.list->text, 1);
3138 }
3139 break;
3140 }
3141 }
3142}
3147 3143
3148 3144
3149/* 3145/*
3146 * Execute a command inside back quotes. If it's a builtin command, we
3147 * want to save its output in a block obtained from malloc. Otherwise
3148 * we fork off a subprocess and get the output of the command via a pipe.
3149 * Should be called with interrupts off.
3150 */
3151
3152static void
3153evalbackcmd(union node *n, struct backcmd *result)
3154{
3155 int pip[2];
3156 struct job *jp;
3157 struct stackmark smark; /* unnecessary */
3158
3159 setstackmark(&smark);
3160 result->fd = -1;
3161 result->buf = NULL;
3162 result->nleft = 0;
3163 result->jp = NULL;
3164 if (n == NULL) {
3165 exitstatus = 0;
3166 goto out;
3167 }
3168 exitstatus = 0;
3169 if (pipe(pip) < 0)
3170 error("Pipe call failed");
3171 jp = makejob(n, 1);
3172 if (forkshell(jp, n, FORK_NOJOB) == 0) {
3173 FORCEINTON;
3174 close(pip[0]);
3175 if (pip[1] != 1) {
3176 close(1);
3177 dup_as_newfd(pip[1], 1);
3178 close(pip[1]);
3179 }
3180 eflag = 0;
3181 evaltree(n, EV_EXIT);
3182 }
3183 close(pip[1]);
3184 result->fd = pip[0];
3185 result->jp = jp;
3186out:
3187 popstackmark(&smark);
3188 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
3189 result->fd, result->buf, result->nleft, result->jp));
3190}
3191
3192
3193/*
3194 * Execute a simple command.
3195 */
3196
3197/*
3150 * Search for a command. This is called before we fork so that the 3198 * Search for a command. This is called before we fork so that the
3151 * location of the command will be available in the parent as well as 3199 * location of the command will be available in the parent as well as
3152 * the child. The check for "goodname" is an overly conservative 3200 * the child. The check for "goodname" is an overly conservative
@@ -3166,7 +3214,6 @@ prehash(n)
3166} 3214}
3167 3215
3168 3216
3169
3170/* 3217/*
3171 * Builtin commands. Builtin commands whose functions are closely 3218 * Builtin commands. Builtin commands whose functions are closely
3172 * tied to evaluation are implemented here. 3219 * tied to evaluation are implemented here.
@@ -3244,7 +3291,6 @@ returncmd(argc, argv)
3244 3291
3245 3292
3246#ifndef BB_TRUE_FALSE 3293#ifndef BB_TRUE_FALSE
3247#ifdef ASH_BBAPPS_AS_BUILTINS
3248static int 3294static int
3249false_main(argc, argv) 3295false_main(argc, argv)
3250 int argc; 3296 int argc;
@@ -3262,7 +3308,6 @@ true_main(argc, argv)
3262 return 0; 3308 return 0;
3263} 3309}
3264#endif 3310#endif
3265#endif
3266 3311
3267/* 3312/*
3268 * Controls whether the shell is interactive or not. 3313 * Controls whether the shell is interactive or not.
@@ -3326,43 +3371,6 @@ eprintlist(struct strlist *sp)
3326 out2fmt(" %s",sp->text); 3371 out2fmt(" %s",sp->text);
3327 } 3372 }
3328} 3373}
3329/*
3330 * When commands are first encountered, they are entered in a hash table.
3331 * This ensures that a full path search will not have to be done for them
3332 * on each invocation.
3333 *
3334 * We should investigate converting to a linear search, even though that
3335 * would make the command name "hash" a misnomer.
3336 */
3337#define CMDTABLESIZE 31 /* should be prime */
3338#define ARB 1 /* actual size determined at run time */
3339
3340
3341
3342struct tblentry {
3343 struct tblentry *next; /* next entry in hash chain */
3344 union param param; /* definition of builtin function */
3345 short cmdtype; /* index identifying command */
3346 char rehash; /* if set, cd done since entry created */
3347 char cmdname[ARB]; /* name of command */
3348};
3349
3350
3351static struct tblentry *cmdtable[CMDTABLESIZE];
3352static int builtinloc = -1; /* index in path of %builtin, or -1 */
3353static int exerrno = 0; /* Last exec error */
3354
3355
3356static void tryexec (char *, char **, char **);
3357static void printentry (struct tblentry *, int);
3358static void clearcmdentry (int);
3359static struct tblentry *cmdlookup (const char *, int);
3360static void delete_cmd_entry (void);
3361#ifdef ASH_TYPE
3362static int describe_command (char *, int);
3363#endif
3364static int path_change (const char *, int *);
3365
3366 3374
3367/* 3375/*
3368 * Exec a program. Never returns. If you change this routine, you may 3376 * Exec a program. Never returns. If you change this routine, you may
@@ -3492,7 +3500,6 @@ initshellproc(void) {
3492 3500
3493static int preadbuffer(void); 3501static int preadbuffer(void);
3494static void pushfile (void); 3502static void pushfile (void);
3495static int preadfd (void);
3496 3503
3497/* 3504/*
3498 * Read a character from the script, returning PEOF on end of file. 3505 * Read a character from the script, returning PEOF on end of file.
@@ -3632,11 +3639,8 @@ setinputfile(const char *fname, int push)
3632 3639
3633 3640
3634static void 3641static void
3635tryexec(cmd, argv, envp) 3642tryexec(char *cmd, char **argv, char **envp)
3636 char *cmd; 3643{
3637 char **argv;
3638 char **envp;
3639 {
3640 int e; 3644 int e;
3641 3645
3642#ifdef BB_FEATURE_SH_STANDALONE_SHELL 3646#ifdef BB_FEATURE_SH_STANDALONE_SHELL
@@ -3650,7 +3654,7 @@ tryexec(cmd, argv, envp)
3650 for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++) 3654 for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++)
3651 putenv(*argv_l); 3655 putenv(*argv_l);
3652 argv_l=argv; 3656 argv_l=argv;
3653 for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++); 3657 for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++)
3654 optind = 1; 3658 optind = 1;
3655 run_applet_by_name(name, argc_l, argv); 3659 run_applet_by_name(name, argc_l, argv);
3656#endif 3660#endif
@@ -3718,6 +3722,25 @@ padvance(const char **path, const char *name)
3718 return stalloc(len); 3722 return stalloc(len);
3719} 3723}
3720 3724
3725/*
3726 * Wrapper around strcmp for qsort/bsearch/...
3727 */
3728static int
3729pstrcmp(const void *a, const void *b)
3730{
3731 return strcmp((const char *) a, *(const char *const *) b);
3732}
3733
3734/*
3735 * Find a keyword is in a sorted array.
3736 */
3737
3738static const char *const *
3739findkwd(const char *s)
3740{
3741 return bsearch(s, parsekwd, sizeof(parsekwd) / sizeof(const char *),
3742 sizeof(const char *), pstrcmp);
3743}
3721 3744
3722 3745
3723/*** Command hashing code ***/ 3746/*** Command hashing code ***/
@@ -3734,14 +3757,17 @@ hashcmd(argc, argv)
3734 int verbose; 3757 int verbose;
3735 struct cmdentry entry; 3758 struct cmdentry entry;
3736 char *name; 3759 char *name;
3760#ifdef ASH_ALIAS
3761 const struct alias *ap;
3762#endif
3737 3763
3738 verbose = 0; 3764 verbose = 0;
3739 while ((c = nextopt("rv")) != '\0') { 3765 while ((c = nextopt("rvV")) != '\0') {
3740 if (c == 'r') { 3766 if (c == 'r') {
3741 clearcmdentry(0); 3767 clearcmdentry(0);
3742 return 0; 3768 return 0;
3743 } else if (c == 'v') { 3769 } else if (c == 'v' || c == 'V') {
3744 verbose++; 3770 verbose = c;
3745 } 3771 }
3746 } 3772 }
3747 if (*argptr == NULL) { 3773 if (*argptr == NULL) {
@@ -3755,24 +3781,41 @@ hashcmd(argc, argv)
3755 return 0; 3781 return 0;
3756 } 3782 }
3757 c = 0; 3783 c = 0;
3758 while ((name = *argptr) != NULL) { 3784 while ((name = *argptr++) != NULL) {
3759 if ((cmdp = cmdlookup(name, 0)) != NULL 3785 if ((cmdp = cmdlookup(name, 0)) != NULL
3760 && (cmdp->cmdtype == CMDNORMAL 3786 && (cmdp->cmdtype == CMDNORMAL
3761 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))) 3787 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
3762 delete_cmd_entry(); 3788 delete_cmd_entry();
3789#ifdef ASH_ALIAS
3790 /* Then look at the aliases */
3791 if ((ap = lookupalias(name, 0)) != NULL) {
3792 if (verbose=='v')
3793 printf("%s is an alias for %s\n", name, ap->val);
3794 else
3795 printalias(ap);
3796 continue;
3797 }
3798#endif
3799 /* First look at the keywords */
3800 if (findkwd(name)!=0) {
3801 if (verbose=='v')
3802 printf("%s is a shell keyword\n", name);
3803 else
3804 printf(snlfmt, name);
3805 continue;
3806 }
3807
3763 find_command(name, &entry, DO_ERR, pathval()); 3808 find_command(name, &entry, DO_ERR, pathval());
3764 if (entry.cmdtype == CMDUNKNOWN) c = 1; 3809 if (entry.cmdtype == CMDUNKNOWN) c = 1;
3765 else if (verbose) { 3810 else if (verbose) {
3766 cmdp = cmdlookup(name, 0); 3811 cmdp = cmdlookup(name, 0);
3767 if (cmdp) printentry(cmdp, verbose); 3812 if (cmdp) printentry(cmdp, verbose=='v');
3768 flushall(); 3813 flushall();
3769 } 3814 }
3770 argptr++;
3771 } 3815 }
3772 return c; 3816 return c;
3773} 3817}
3774 3818
3775
3776static void 3819static void
3777printentry(cmdp, verbose) 3820printentry(cmdp, verbose)
3778 struct tblentry *cmdp; 3821 struct tblentry *cmdp;
@@ -3782,6 +3825,7 @@ printentry(cmdp, verbose)
3782 const char *path; 3825 const char *path;
3783 char *name; 3826 char *name;
3784 3827
3828 printf("%s%s", cmdp->cmdname, (verbose ? " is " : ""));
3785 if (cmdp->cmdtype == CMDNORMAL) { 3829 if (cmdp->cmdtype == CMDNORMAL) {
3786 idx = cmdp->param.index; 3830 idx = cmdp->param.index;
3787 path = pathval(); 3831 path = pathval();
@@ -3789,15 +3833,17 @@ printentry(cmdp, verbose)
3789 name = padvance(&path, cmdp->cmdname); 3833 name = padvance(&path, cmdp->cmdname);
3790 stunalloc(name); 3834 stunalloc(name);
3791 } while (--idx >= 0); 3835 } while (--idx >= 0);
3792 out1str(name); 3836 if(verbose)
3837 out1str(name);
3793 } else if (cmdp->cmdtype == CMDBUILTIN) { 3838 } else if (cmdp->cmdtype == CMDBUILTIN) {
3794 out1fmt("builtin %s", cmdp->cmdname); 3839 if(verbose)
3840 out1str("a shell builtin");
3795 } else if (cmdp->cmdtype == CMDFUNCTION) { 3841 } else if (cmdp->cmdtype == CMDFUNCTION) {
3796 out1fmt("function %s", cmdp->cmdname);
3797 if (verbose) { 3842 if (verbose) {
3798 INTOFF; 3843 INTOFF;
3844 out1str("a function\n");
3799 name = commandtext(cmdp->param.func); 3845 name = commandtext(cmdp->param.func);
3800 out1fmt(" %s", name); 3846 printf("%s() {\n %s\n}", cmdp->cmdname, name);
3801 ckfree(name); 3847 ckfree(name);
3802 INTON; 3848 INTON;
3803 } 3849 }
@@ -3806,7 +3852,7 @@ printentry(cmdp, verbose)
3806 error("internal error: cmdtype %d", cmdp->cmdtype); 3852 error("internal error: cmdtype %d", cmdp->cmdtype);
3807#endif 3853#endif
3808 } 3854 }
3809 out1fmt(snlfmt, cmdp->rehash ? "*" : nullstr); 3855 printf(snlfmt, cmdp->rehash ? "*" : nullstr);
3810} 3856}
3811 3857
3812 3858
@@ -3817,15 +3863,11 @@ printentry(cmdp, verbose)
3817static int helpcmd(int argc, char** argv) 3863static int helpcmd(int argc, char** argv)
3818{ 3864{
3819 int col, i; 3865 int col, i;
3820 const struct builtincmd *x;
3821 3866
3822 printf("\nBuilt-in commands:\n"); 3867 printf("\nBuilt-in commands:\n-------------------\n");
3823 printf("-------------------\n"); 3868 for (col=0, i=0; i < NUMBUILTINS; i++) {
3824 for (col=0, i=0, x = builtincmds; i < NUMBUILTINS; x++, i++) { 3869 col += printf("%c%s", ((col == 0) ? '\t' : ' '),
3825 if (!x->name || ! (x->name+1)) 3870 builtincmds[i].name+1);
3826 continue;
3827 col += printf("%s%s", ((col == 0) ? "\t" : " "),
3828 (x->name+1));
3829 if (col > 60) { 3871 if (col > 60) {
3830 printf("\n"); 3872 printf("\n");
3831 col = 0; 3873 col = 0;
@@ -3833,16 +3875,13 @@ static int helpcmd(int argc, char** argv)
3833 } 3875 }
3834#ifdef BB_FEATURE_SH_STANDALONE_SHELL 3876#ifdef BB_FEATURE_SH_STANDALONE_SHELL
3835 { 3877 {
3836 const struct BB_applet *applet;
3837 extern const struct BB_applet applets[]; 3878 extern const struct BB_applet applets[];
3838 extern const size_t NUM_APPLETS; 3879 extern const size_t NUM_APPLETS;
3839 3880
3840 for (i=0, applet = applets; i < NUM_APPLETS; applet++, i++) { 3881 for (i=0; i < NUM_APPLETS; i++) {
3841 if (!applet->name) 3882
3842 continue; 3883 col += printf("%c%s", ((col == 0) ? '\t' : ' '),
3843 3884 applets[i].name);
3844 col += printf("%s%s", ((col == 0) ? "\t" : " "),
3845 applet->name);
3846 if (col > 60) { 3885 if (col > 60) {
3847 printf("\n"); 3886 printf("\n");
3848 col = 0; 3887 col = 0;
@@ -3854,8 +3893,6 @@ static int helpcmd(int argc, char** argv)
3854 return EXIT_SUCCESS; 3893 return EXIT_SUCCESS;
3855} 3894}
3856 3895
3857
3858
3859/* 3896/*
3860 * Resolve a command name. If you change this routine, you may have to 3897 * Resolve a command name. If you change this routine, you may have to
3861 * change the shellexec routine as well. 3898 * change the shellexec routine as well.
@@ -3875,7 +3912,7 @@ find_command(const char *name, struct cmdentry *entry, int act, const char *path
3875 int bltin; 3912 int bltin;
3876 int firstchange; 3913 int firstchange;
3877 int updatetbl; 3914 int updatetbl;
3878 bool regular; 3915 int regular;
3879 struct builtincmd *bcmd; 3916 struct builtincmd *bcmd;
3880 3917
3881 /* If name contains a slash, don't use the hash table */ 3918 /* If name contains a slash, don't use the hash table */
@@ -4138,17 +4175,6 @@ clearcmdentry(firstchange)
4138 INTON; 4175 INTON;
4139} 4176}
4140 4177
4141/*
4142 * Free a parse tree.
4143 */
4144
4145static void
4146freefunc(union node *n)
4147{
4148 if (n)
4149 ckfree(n);
4150}
4151
4152 4178
4153/* 4179/*
4154 * Delete all functions. 4180 * Delete all functions.
@@ -4238,42 +4264,37 @@ delete_cmd_entry() {
4238 4264
4239 4265
4240 4266
4241/*
4242 * Add a new command entry, replacing any existing command entry for
4243 * the same name.
4244 */
4245 4267
4246static void
4247addcmdentry(char *name, struct cmdentry *entry)
4248{
4249 struct tblentry *cmdp;
4250 4268
4251 INTOFF; 4269static const short nodesize[26] = {
4252 cmdp = cmdlookup(name, 1); 4270 ALIGN(sizeof (struct nbinary)),
4253 if (cmdp->cmdtype == CMDFUNCTION) { 4271 ALIGN(sizeof (struct ncmd)),
4254 freefunc(cmdp->param.func); 4272 ALIGN(sizeof (struct npipe)),
4255 } 4273 ALIGN(sizeof (struct nredir)),
4256 cmdp->cmdtype = entry->cmdtype; 4274 ALIGN(sizeof (struct nredir)),
4257 cmdp->param = entry->u; 4275 ALIGN(sizeof (struct nredir)),
4258 INTON; 4276 ALIGN(sizeof (struct nbinary)),
4259} 4277 ALIGN(sizeof (struct nbinary)),
4260 4278 ALIGN(sizeof (struct nif)),
4261 4279 ALIGN(sizeof (struct nbinary)),
4262/* 4280 ALIGN(sizeof (struct nbinary)),
4263 * Define a shell function. 4281 ALIGN(sizeof (struct nfor)),
4264 */ 4282 ALIGN(sizeof (struct ncase)),
4265 4283 ALIGN(sizeof (struct nclist)),
4266static union node *copyfunc(union node *); 4284 ALIGN(sizeof (struct narg)),
4267 4285 ALIGN(sizeof (struct narg)),
4268static void 4286 ALIGN(sizeof (struct nfile)),
4269defun(char *name, union node *func) 4287 ALIGN(sizeof (struct nfile)),
4270{ 4288 ALIGN(sizeof (struct nfile)),
4271 struct cmdentry entry; 4289 ALIGN(sizeof (struct nfile)),
4290 ALIGN(sizeof (struct nfile)),
4291 ALIGN(sizeof (struct ndup)),
4292 ALIGN(sizeof (struct ndup)),
4293 ALIGN(sizeof (struct nhere)),
4294 ALIGN(sizeof (struct nhere)),
4295 ALIGN(sizeof (struct nnot)),
4296};
4272 4297
4273 entry.cmdtype = CMDFUNCTION;
4274 entry.u.func = copyfunc(func);
4275 addcmdentry(name, &entry);
4276}
4277 4298
4278 4299
4279/* 4300/*
@@ -4291,141 +4312,29 @@ unsetfunc(char *name)
4291 } 4312 }
4292} 4313}
4293 4314
4294/*
4295 * Wrapper around strcmp for qsort/bsearch/...
4296 */
4297static int
4298pstrcmp(const void *a, const void *b)
4299{
4300 return strcmp((const char *) a, *(const char *const *) b);
4301}
4302 4315
4303/* 4316/*
4304 * Find a keyword is in a sorted array.
4305 */
4306
4307static const char *const *
4308findkwd(const char *s)
4309{
4310 return bsearch(s, parsekwd, sizeof(parsekwd) / sizeof(const char *),
4311 sizeof(const char *), pstrcmp);
4312}
4313
4314#ifdef ASH_TYPE
4315/*
4316 * Locate and print what a word is... 4317 * Locate and print what a word is...
4317 */ 4318 */
4318 4319
4319static int 4320static int
4320typecmd(argc, argv) 4321typecmd(int argc, char **argv)
4321 int argc;
4322 char **argv;
4323{ 4322{
4324 int i; 4323 int i;
4325 int err = 0; 4324 int err = 0;
4325 char *argv_a[2];
4326
4327 argv_a[1] = 0;
4326 4328
4327 for (i = 1; i < argc; i++) { 4329 for (i = 1; i < argc; i++) {
4328 err |= describe_command(argv[i], 1); 4330 argv_a[0] = argv[i];
4331 argptr = argv_a;
4332 optptr = "v";
4333 err |= hashcmd(argc, argv);
4329 } 4334 }
4330 return err; 4335 return err;
4331} 4336}
4332 4337
4333static int
4334describe_command(char *command, int verbose)
4335{
4336 struct cmdentry entry;
4337 struct tblentry *cmdp;
4338#ifdef ASH_ALIAS
4339 const struct alias *ap;
4340#endif
4341 const char *path = pathval();
4342
4343 if (verbose) {
4344 out1str(command);
4345 }
4346
4347 /* First look at the keywords */
4348 if (findkwd(command)) {
4349 out1str(verbose ? " is a shell keyword" : command);
4350 goto out;
4351 }
4352
4353#ifdef ASH_ALIAS
4354 /* Then look at the aliases */
4355 if ((ap = lookupalias(command, 0)) != NULL) {
4356 if (verbose) {
4357 out1fmt(" is an alias for %s", ap->val);
4358 } else {
4359 printalias(ap);
4360 }
4361 goto out;
4362 }
4363#endif
4364 /* Then check if it is a tracked alias */
4365 if ((cmdp = cmdlookup(command, 0)) != NULL) {
4366 entry.cmdtype = cmdp->cmdtype;
4367 entry.u = cmdp->param;
4368 } else {
4369 /* Finally use brute force */
4370 find_command(command, &entry, DO_ABS, path);
4371 }
4372
4373 switch (entry.cmdtype) {
4374 case CMDNORMAL: {
4375 int j = entry.u.index;
4376 char *p;
4377 if (j == -1) {
4378 p = command;
4379 } else {
4380 do {
4381 p = padvance(&path, command);
4382 stunalloc(p);
4383 } while (--j >= 0);
4384 }
4385 if (verbose) {
4386 out1fmt(
4387 " is%s %s",
4388 cmdp ? " a tracked alias for" : nullstr, p
4389 );
4390 } else {
4391 out1str(p);
4392 }
4393 break;
4394 }
4395
4396 case CMDFUNCTION:
4397 if (verbose) {
4398 out1str(" is a shell function");
4399 } else {
4400 out1str(command);
4401 }
4402 break;
4403
4404 case CMDBUILTIN:
4405 if (verbose) {
4406 out1fmt(
4407 " is a %sshell builtin",
4408 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
4409 "special " : nullstr
4410 );
4411 } else {
4412 out1str(command);
4413 }
4414 break;
4415
4416 default:
4417 if (verbose) {
4418 out1str(": not found\n");
4419 }
4420 return 127;
4421 }
4422
4423out:
4424 putchar('\n');
4425 return 0;
4426}
4427#endif
4428
4429#ifdef ASH_CMDCMD 4338#ifdef ASH_CMDCMD
4430static int 4339static int
4431commandcmd(argc, argv) 4340commandcmd(argc, argv)
@@ -4448,26 +4357,25 @@ commandcmd(argc, argv)
4448 case 'V': 4357 case 'V':
4449 verbose_verify_only = 1; 4358 verbose_verify_only = 1;
4450 break; 4359 break;
4451 default:
4452 out2fmt(
4453"command: nextopt returned character code 0%o\n", c);
4454 return EX_SOFTWARE;
4455 } 4360 }
4456 4361
4457 if (default_path + verify_only + verbose_verify_only > 1 || 4362 if (default_path + verify_only + verbose_verify_only > 1 ||
4458 !*argptr) { 4363 !*argptr) {
4459 out2fmt( 4364 out2str(
4460"command [-p] command [arg ...]\n"); 4365 "command [-p] command [arg ...]\n"
4461 out2fmt( 4366 "command {-v|-V} command\n");
4462"command {-v|-V} command\n");
4463 return EX_USAGE; 4367 return EX_USAGE;
4464 } 4368 }
4465 4369
4466#ifdef ASH_TYPE
4467 if (verify_only || verbose_verify_only) { 4370 if (verify_only || verbose_verify_only) {
4468 return describe_command(*argptr, verbose_verify_only); 4371 char *argv_a[2];
4372
4373 argv_a[1] = 0;
4374 argv_a[0] = *argptr;
4375 argptr = argv_a;
4376 optptr = verbose_verify_only ? "v" : "V"; /* reverse special */
4377 return hashcmd(argc, argv);
4469 } 4378 }
4470#endif
4471 4379
4472 return 0; 4380 return 0;
4473} 4381}
@@ -4541,7 +4449,6 @@ static void argstr (char *, int);
4541static char *exptilde (char *, int); 4449static char *exptilde (char *, int);
4542static void expbackq (union node *, int, int); 4450static void expbackq (union node *, int, int);
4543static int subevalvar (char *, char *, int, int, int, int, int); 4451static int subevalvar (char *, char *, int, int, int, int, int);
4544static char *evalvar (char *, int);
4545static int varisset (char *, int); 4452static int varisset (char *, int);
4546static void strtodest (const char *, const char *, int); 4453static void strtodest (const char *, const char *, int);
4547static void varvalue (char *, int, int); 4454static void varvalue (char *, int, int);
@@ -4550,21 +4457,21 @@ static void removerecordregions (int);
4550static void ifsbreakup (char *, struct arglist *); 4457static void ifsbreakup (char *, struct arglist *);
4551static void ifsfree (void); 4458static void ifsfree (void);
4552static void expandmeta (struct strlist *, int); 4459static void expandmeta (struct strlist *, int);
4553#if defined(__GLIBC__) && !defined(FNMATCH_BROKEN) 4460#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
4554#define preglob(p) _rmescapes((p), RMESCAPE_ALLOC | RMESCAPE_GLOB) 4461#define preglob(p) _rmescapes((p), RMESCAPE_ALLOC | RMESCAPE_GLOB)
4555#if !defined(GLOB_BROKEN) 4462#if !defined(GLOB_BROKEN)
4556static void addglob (const glob_t *); 4463static void addglob (const glob_t *);
4557#endif 4464#endif
4558#endif 4465#endif
4559#if !(defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)) 4466#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
4560static void expmeta (char *, char *); 4467static void expmeta (char *, char *);
4561#endif 4468#endif
4562#if !(defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)) 4469#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
4563static struct strlist *expsort (struct strlist *); 4470static struct strlist *expsort (struct strlist *);
4564static struct strlist *msort (struct strlist *, int); 4471static struct strlist *msort (struct strlist *, int);
4565#endif 4472#endif
4566#if defined(__GLIBC__) && !defined(FNMATCH_BROKEN)
4567static int patmatch (char *, char *, int); 4473static int patmatch (char *, char *, int);
4474#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
4568static int patmatch2 (char *, char *, int); 4475static int patmatch2 (char *, char *, int);
4569#else 4476#else
4570static int pmatch (char *, char *, int); 4477static int pmatch (char *, char *, int);
@@ -4577,7 +4484,7 @@ static char *cvtnum (int, char *);
4577 */ 4484 */
4578 4485
4579/* arg: the document, fd: where to write the expanded version */ 4486/* arg: the document, fd: where to write the expanded version */
4580static void 4487static inline void
4581expandhere(union node *arg, int fd) 4488expandhere(union node *arg, int fd)
4582{ 4489{
4583 herefd = fd; 4490 herefd = fd;
@@ -4638,6 +4545,168 @@ expandarg(arg, arglist, flag)
4638} 4545}
4639 4546
4640 4547
4548/*
4549 * Expand a variable, and return a pointer to the next character in the
4550 * input string.
4551 */
4552
4553static inline char *
4554evalvar(p, flag)
4555 char *p;
4556 int flag;
4557{
4558 int subtype;
4559 int varflags;
4560 char *var;
4561 const char *val;
4562 int patloc;
4563 int c;
4564 int set;
4565 int special;
4566 int startloc;
4567 int varlen;
4568 int easy;
4569 int quotes = flag & (EXP_FULL | EXP_CASE);
4570
4571 varflags = *p++;
4572 subtype = varflags & VSTYPE;
4573 var = p;
4574 special = 0;
4575 if (! is_name(*p))
4576 special = 1;
4577 p = strchr(p, '=') + 1;
4578again: /* jump here after setting a variable with ${var=text} */
4579 if (special) {
4580 set = varisset(var, varflags & VSNUL);
4581 val = NULL;
4582 } else {
4583 val = lookupvar(var);
4584 if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
4585 val = NULL;
4586 set = 0;
4587 } else
4588 set = 1;
4589 }
4590 varlen = 0;
4591 startloc = expdest - stackblock();
4592 if (set && subtype != VSPLUS) {
4593 /* insert the value of the variable */
4594 if (special) {
4595 varvalue(var, varflags & VSQUOTE, flag);
4596 if (subtype == VSLENGTH) {
4597 varlen = expdest - stackblock() - startloc;
4598 STADJUST(-varlen, expdest);
4599 }
4600 } else {
4601 if (subtype == VSLENGTH) {
4602 varlen = strlen(val);
4603 } else {
4604 strtodest(
4605 val,
4606 varflags & VSQUOTE ?
4607 DQSYNTAX : BASESYNTAX,
4608 quotes
4609 );
4610 }
4611 }
4612 }
4613
4614 if (subtype == VSPLUS)
4615 set = ! set;
4616
4617 easy = ((varflags & VSQUOTE) == 0 ||
4618 (*var == '@' && shellparam.nparam != 1));
4619
4620
4621 switch (subtype) {
4622 case VSLENGTH:
4623 expdest = cvtnum(varlen, expdest);
4624 goto record;
4625
4626 case VSNORMAL:
4627 if (!easy)
4628 break;
4629record:
4630 recordregion(startloc, expdest - stackblock(),
4631 varflags & VSQUOTE);
4632 break;
4633
4634 case VSPLUS:
4635 case VSMINUS:
4636 if (!set) {
4637 argstr(p, flag);
4638 break;
4639 }
4640 if (easy)
4641 goto record;
4642 break;
4643
4644 case VSTRIMLEFT:
4645 case VSTRIMLEFTMAX:
4646 case VSTRIMRIGHT:
4647 case VSTRIMRIGHTMAX:
4648 if (!set)
4649 break;
4650 /*
4651 * Terminate the string and start recording the pattern
4652 * right after it
4653 */
4654 STPUTC('\0', expdest);
4655 patloc = expdest - stackblock();
4656 if (subevalvar(p, NULL, patloc, subtype,
4657 startloc, varflags, quotes) == 0) {
4658 int amount = (expdest - stackblock() - patloc) + 1;
4659 STADJUST(-amount, expdest);
4660 }
4661 /* Remove any recorded regions beyond start of variable */
4662 removerecordregions(startloc);
4663 goto record;
4664
4665 case VSASSIGN:
4666 case VSQUESTION:
4667 if (!set) {
4668 if (subevalvar(p, var, 0, subtype, startloc,
4669 varflags, quotes)) {
4670 varflags &= ~VSNUL;
4671 /*
4672 * Remove any recorded regions beyond
4673 * start of variable
4674 */
4675 removerecordregions(startloc);
4676 goto again;
4677 }
4678 break;
4679 }
4680 if (easy)
4681 goto record;
4682 break;
4683
4684#ifdef DEBUG
4685 default:
4686 abort();
4687#endif
4688 }
4689
4690 if (subtype != VSNORMAL) { /* skip to end of alternative */
4691 int nesting = 1;
4692 for (;;) {
4693 if ((c = *p++) == CTLESC)
4694 p++;
4695 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
4696 if (set)
4697 argbackq = argbackq->next;
4698 } else if (c == CTLVAR) {
4699 if ((*p++ & VSTYPE) != VSNORMAL)
4700 nesting++;
4701 } else if (c == CTLENDVAR) {
4702 if (--nesting == 0)
4703 break;
4704 }
4705 }
4706 }
4707 return p;
4708}
4709
4641 4710
4642/* 4711/*
4643 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC 4712 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
@@ -5091,168 +5160,6 @@ recordright:
5091 5160
5092 5161
5093/* 5162/*
5094 * Expand a variable, and return a pointer to the next character in the
5095 * input string.
5096 */
5097
5098static char *
5099evalvar(p, flag)
5100 char *p;
5101 int flag;
5102{
5103 int subtype;
5104 int varflags;
5105 char *var;
5106 char *val;
5107 int patloc;
5108 int c;
5109 int set;
5110 int special;
5111 int startloc;
5112 int varlen;
5113 int easy;
5114 int quotes = flag & (EXP_FULL | EXP_CASE);
5115
5116 varflags = *p++;
5117 subtype = varflags & VSTYPE;
5118 var = p;
5119 special = 0;
5120 if (! is_name(*p))
5121 special = 1;
5122 p = strchr(p, '=') + 1;
5123again: /* jump here after setting a variable with ${var=text} */
5124 if (special) {
5125 set = varisset(var, varflags & VSNUL);
5126 val = NULL;
5127 } else {
5128 val = lookupvar(var);
5129 if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
5130 val = NULL;
5131 set = 0;
5132 } else
5133 set = 1;
5134 }
5135 varlen = 0;
5136 startloc = expdest - stackblock();
5137 if (set && subtype != VSPLUS) {
5138 /* insert the value of the variable */
5139 if (special) {
5140 varvalue(var, varflags & VSQUOTE, flag);
5141 if (subtype == VSLENGTH) {
5142 varlen = expdest - stackblock() - startloc;
5143 STADJUST(-varlen, expdest);
5144 }
5145 } else {
5146 if (subtype == VSLENGTH) {
5147 varlen = strlen(val);
5148 } else {
5149 strtodest(
5150 val,
5151 varflags & VSQUOTE ?
5152 DQSYNTAX : BASESYNTAX,
5153 quotes
5154 );
5155 }
5156 }
5157 }
5158
5159 if (subtype == VSPLUS)
5160 set = ! set;
5161
5162 easy = ((varflags & VSQUOTE) == 0 ||
5163 (*var == '@' && shellparam.nparam != 1));
5164
5165
5166 switch (subtype) {
5167 case VSLENGTH:
5168 expdest = cvtnum(varlen, expdest);
5169 goto record;
5170
5171 case VSNORMAL:
5172 if (!easy)
5173 break;
5174record:
5175 recordregion(startloc, expdest - stackblock(),
5176 varflags & VSQUOTE);
5177 break;
5178
5179 case VSPLUS:
5180 case VSMINUS:
5181 if (!set) {
5182 argstr(p, flag);
5183 break;
5184 }
5185 if (easy)
5186 goto record;
5187 break;
5188
5189 case VSTRIMLEFT:
5190 case VSTRIMLEFTMAX:
5191 case VSTRIMRIGHT:
5192 case VSTRIMRIGHTMAX:
5193 if (!set)
5194 break;
5195 /*
5196 * Terminate the string and start recording the pattern
5197 * right after it
5198 */
5199 STPUTC('\0', expdest);
5200 patloc = expdest - stackblock();
5201 if (subevalvar(p, NULL, patloc, subtype,
5202 startloc, varflags, quotes) == 0) {
5203 int amount = (expdest - stackblock() - patloc) + 1;
5204 STADJUST(-amount, expdest);
5205 }
5206 /* Remove any recorded regions beyond start of variable */
5207 removerecordregions(startloc);
5208 goto record;
5209
5210 case VSASSIGN:
5211 case VSQUESTION:
5212 if (!set) {
5213 if (subevalvar(p, var, 0, subtype, startloc,
5214 varflags, quotes)) {
5215 varflags &= ~VSNUL;
5216 /*
5217 * Remove any recorded regions beyond
5218 * start of variable
5219 */
5220 removerecordregions(startloc);
5221 goto again;
5222 }
5223 break;
5224 }
5225 if (easy)
5226 goto record;
5227 break;
5228
5229#ifdef DEBUG
5230 default:
5231 abort();
5232#endif
5233 }
5234
5235 if (subtype != VSNORMAL) { /* skip to end of alternative */
5236 int nesting = 1;
5237 for (;;) {
5238 if ((c = *p++) == CTLESC)
5239 p++;
5240 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
5241 if (set)
5242 argbackq = argbackq->next;
5243 } else if (c == CTLVAR) {
5244 if ((*p++ & VSTYPE) != VSNORMAL)
5245 nesting++;
5246 } else if (c == CTLENDVAR) {
5247 if (--nesting == 0)
5248 break;
5249 }
5250 }
5251 }
5252 return p;
5253}
5254
5255/*
5256 * Test whether a specialized variable is set. 5163 * Test whether a specialized variable is set.
5257 */ 5164 */
5258 5165
@@ -5542,7 +5449,7 @@ addfname(const char *name)
5542 * should be escapes. The results are stored in the list exparg. 5449 * should be escapes. The results are stored in the list exparg.
5543 */ 5450 */
5544 5451
5545#if defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) 5452#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)
5546static void 5453static void
5547expandmeta(str, flag) 5454expandmeta(str, flag)
5548 struct strlist *str; 5455 struct strlist *str;
@@ -5787,7 +5694,7 @@ expmeta(enddir, name)
5787 5694
5788 5695
5789 5696
5790#if !(defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)) 5697#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
5791/* 5698/*
5792 * Sort the results of file name expansion. It calculates the number of 5699 * Sort the results of file name expansion. It calculates the number of
5793 * strings to sort and then calls msort (short for merge sort) to do the 5700 * strings to sort and then calls msort (short for merge sort) to do the
@@ -5857,7 +5764,7 @@ msort(list, len)
5857 * Returns true if the pattern matches the string. 5764 * Returns true if the pattern matches the string.
5858 */ 5765 */
5859 5766
5860#if defined(__GLIBC__) && !defined(FNMATCH_BROKEN) 5767#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
5861/* squoted: string might have quote chars */ 5768/* squoted: string might have quote chars */
5862static int 5769static int
5863patmatch(char *pattern, char *string, int squoted) 5770patmatch(char *pattern, char *string, int squoted)
@@ -6015,7 +5922,7 @@ breakloop:
6015 * Remove any CTLESC characters from a string. 5922 * Remove any CTLESC characters from a string.
6016 */ 5923 */
6017 5924
6018#if defined(__GLIBC__) && !defined(FNMATCH_BROKEN) 5925#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
6019static char * 5926static char *
6020_rmescapes(char *str, int flag) 5927_rmescapes(char *str, int flag)
6021{ 5928{
@@ -6032,12 +5939,8 @@ _rmescapes(char *str, int flag)
6032 size_t len = p - str; 5939 size_t len = p - str;
6033 q = r = stalloc(strlen(p) + len + 1); 5940 q = r = stalloc(strlen(p) + len + 1);
6034 if (len > 0) { 5941 if (len > 0) {
6035#ifdef _GNU_SOURCE
6036 q = mempcpy(q, str, len);
6037#else
6038 memcpy(q, str, len); 5942 memcpy(q, str, len);
6039 q += len; 5943 q += len;
6040#endif
6041 } 5944 }
6042 } 5945 }
6043 while (*p) { 5946 while (*p) {
@@ -6135,12 +6038,10 @@ static int histcmd(argc, argv)
6135} 6038}
6136 6039
6137 6040
6138static int whichprompt; /* 1 == PS1, 2 == PS2 */
6139
6140
6141struct redirtab { 6041struct redirtab {
6142 struct redirtab *next; 6042 struct redirtab *next;
6143 short renamed[10]; 6043 /* short renamed[10]; *//* Current ash support only 0-9 descriptors */
6044 char renamed[10];
6144}; 6045};
6145 6046
6146static struct redirtab *redirlist; 6047static struct redirtab *redirlist;
@@ -6273,7 +6174,7 @@ static inline int pgetc2() { return pgetc_macro(); }
6273 * Read a line from the script. 6174 * Read a line from the script.
6274 */ 6175 */
6275 6176
6276static char * 6177static inline char *
6277pfgets(char *line, int len) 6178pfgets(char *line, int len)
6278{ 6179{
6279 char *p = line; 6180 char *p = line;
@@ -6295,7 +6196,7 @@ pfgets(char *line, int len)
6295 return line; 6196 return line;
6296} 6197}
6297 6198
6298static int 6199static inline int
6299preadfd(void) 6200preadfd(void)
6300{ 6201{
6301 int nr; 6202 int nr;
@@ -6480,16 +6381,13 @@ pushstring(char *s, int len, void *ap)
6480} 6381}
6481 6382
6482 6383
6483
6484
6485/* 6384/*
6486 * Like setinputfile, but takes input from a string. 6385 * Like setinputfile, but takes input from a string.
6487 */ 6386 */
6488 6387
6489static void 6388static void
6490setinputstring(string) 6389setinputstring(char *string)
6491 char *string; 6390{
6492 {
6493 INTOFF; 6391 INTOFF;
6494 pushfile(); 6392 pushfile();
6495 parsenextc = string; 6393 parsenextc = string;
@@ -6528,7 +6426,6 @@ static void restartjob (struct job *);
6528static void freejob (struct job *); 6426static void freejob (struct job *);
6529static struct job *getjob (const char *); 6427static struct job *getjob (const char *);
6530static int dowait (int, struct job *); 6428static int dowait (int, struct job *);
6531static int waitproc (int, int *);
6532static void waitonint(int); 6429static void waitonint(int);
6533 6430
6534 6431
@@ -6545,12 +6442,7 @@ fd0_redirected_p () {
6545 return fd0_redirected != 0; 6442 return fd0_redirected != 0;
6546} 6443}
6547 6444
6548static int openredirect (union node *); 6445static void dupredirect (const union node *, int, int fd1dup);
6549static void dupredirect (union node *, int, char[10 ]);
6550static int openhere (union node *);
6551static int noclobberopen (const char *);
6552
6553
6554 6446
6555#ifdef JOBS 6447#ifdef JOBS
6556/* 6448/*
@@ -6656,6 +6548,7 @@ static char *signal_names[NSIG + 2] = {
6656 "SIGIO", 6548 "SIGIO",
6657 "SIGPWR", 6549 "SIGPWR",
6658 "SIGSYS", 6550 "SIGSYS",
6551#ifdef SIGRTMIN
6659 "SIGRTMIN", 6552 "SIGRTMIN",
6660 "SIGRTMIN+1", 6553 "SIGRTMIN+1",
6661 "SIGRTMIN+2", 6554 "SIGRTMIN+2",
@@ -6688,6 +6581,7 @@ static char *signal_names[NSIG + 2] = {
6688 "SIGRTMAX-2", 6581 "SIGRTMAX-2",
6689 "SIGRTMAX-1", 6582 "SIGRTMAX-1",
6690 "SIGRTMAX", 6583 "SIGRTMAX",
6584#endif
6691 "DEBUG", 6585 "DEBUG",
6692 (char *)0x0, 6586 (char *)0x0,
6693}; 6587};
@@ -6754,7 +6648,7 @@ usage:
6754 if (!*argptr) { 6648 if (!*argptr) {
6755 out1str("0\n"); 6649 out1str("0\n");
6756 for (i = 1; i < NSIG; i++) { 6650 for (i = 1; i < NSIG; i++) {
6757 out1fmt(snlfmt, signal_names[i] + 3); 6651 printf(snlfmt, signal_names[i] + 3);
6758 } 6652 }
6759 return 0; 6653 return 0;
6760 } 6654 }
@@ -6762,7 +6656,7 @@ usage:
6762 if (signo > 128) 6656 if (signo > 128)
6763 signo -= 128; 6657 signo -= 128;
6764 if (0 < signo && signo < NSIG) 6658 if (0 < signo && signo < NSIG)
6765 out1fmt(snlfmt, signal_names[signo] + 3); 6659 printf(snlfmt, signal_names[signo] + 3);
6766 else 6660 else
6767 error("invalid signal number or exit status: %s", 6661 error("invalid signal number or exit status: %s",
6768 *argptr); 6662 *argptr);
@@ -6926,7 +6820,7 @@ showjobs(change)
6926 } 6820 }
6927 out1str(s); 6821 out1str(s);
6928 col += strlen(s); 6822 col += strlen(s);
6929 out1fmt( 6823 printf(
6930 "%*c%s\n", 30 - col >= 0 ? 30 - col : 0, ' ', 6824 "%*c%s\n", 30 - col >= 0 ? 30 - col : 0, ' ',
6931 ps->cmd 6825 ps->cmd
6932 ); 6826 );
@@ -6946,10 +6840,9 @@ showjobs(change)
6946 */ 6840 */
6947 6841
6948static void 6842static void
6949freejob(jp) 6843freejob(struct job *jp)
6950 struct job *jp; 6844{
6951 { 6845 const struct procstat *ps;
6952 struct procstat *ps;
6953 int i; 6846 int i;
6954 6847
6955 INTOFF; 6848 INTOFF;
@@ -7084,9 +6977,7 @@ currentjob:
7084 */ 6977 */
7085 6978
7086static struct job * 6979static struct job *
7087makejob(node, nprocs) 6980makejob(const union node *node, int nprocs)
7088 union node *node;
7089 int nprocs;
7090{ 6981{
7091 int i; 6982 int i;
7092 struct job *jp; 6983 struct job *jp;
@@ -7152,10 +7043,12 @@ makejob(node, nprocs)
7152 7043
7153 7044
7154static int 7045static int
7155forkshell(struct job *jp, union node *n, int mode) 7046forkshell(struct job *jp, const union node *n, int mode)
7156{ 7047{
7157 int pid; 7048 int pid;
7049#ifdef JOBS
7158 int pgrp; 7050 int pgrp;
7051#endif
7159 const char *devnull = _PATH_DEVNULL; 7052 const char *devnull = _PATH_DEVNULL;
7160 const char *nullerr = "Can't open %s"; 7053 const char *nullerr = "Can't open %s";
7161 7054
@@ -7231,6 +7124,7 @@ forkshell(struct job *jp, union node *n, int mode)
7231 } 7124 }
7232 return pid; 7125 return pid;
7233 } 7126 }
7127#ifdef JOBS
7234 if (rootshell && mode != FORK_NOJOB && mflag) { 7128 if (rootshell && mode != FORK_NOJOB && mflag) {
7235 if (jp == NULL || jp->nprocs == 0) 7129 if (jp == NULL || jp->nprocs == 0)
7236 pgrp = pid; 7130 pgrp = pid;
@@ -7238,6 +7132,7 @@ forkshell(struct job *jp, union node *n, int mode)
7238 pgrp = jp->ps[0].pid; 7132 pgrp = jp->ps[0].pid;
7239 setpgid(pid, pgrp); 7133 setpgid(pid, pgrp);
7240 } 7134 }
7135#endif
7241 if (mode == FORK_BG) 7136 if (mode == FORK_BG)
7242 backgndpid = pid; /* set $! */ 7137 backgndpid = pid; /* set $! */
7243 if (jp) { 7138 if (jp) {
@@ -7275,9 +7170,8 @@ forkshell(struct job *jp, union node *n, int mode)
7275 */ 7170 */
7276 7171
7277static int 7172static int
7278waitforjob(jp) 7173waitforjob(struct job *jp)
7279 struct job *jp; 7174{
7280 {
7281#ifdef JOBS 7175#ifdef JOBS
7282 int mypgrp = getpgrp(); 7176 int mypgrp = getpgrp();
7283#endif 7177#endif
@@ -7358,10 +7252,47 @@ waitforjob(jp)
7358 * Wait for a process to terminate. 7252 * Wait for a process to terminate.
7359 */ 7253 */
7360 7254
7255/*
7256 * Do a wait system call. If job control is compiled in, we accept
7257 * stopped processes. If block is zero, we return a value of zero
7258 * rather than blocking.
7259 *
7260 * System V doesn't have a non-blocking wait system call. It does
7261 * have a SIGCLD signal that is sent to a process when one of it's
7262 * children dies. The obvious way to use SIGCLD would be to install
7263 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7264 * was received, and have waitproc bump another counter when it got
7265 * the status of a process. Waitproc would then know that a wait
7266 * system call would not block if the two counters were different.
7267 * This approach doesn't work because if a process has children that
7268 * have not been waited for, System V will send it a SIGCLD when it
7269 * installs a signal handler for SIGCLD. What this means is that when
7270 * a child exits, the shell will be sent SIGCLD signals continuously
7271 * until is runs out of stack space, unless it does a wait call before
7272 * restoring the signal handler. The code below takes advantage of
7273 * this (mis)feature by installing a signal handler for SIGCLD and
7274 * then checking to see whether it was called. If there are any
7275 * children to be waited for, it will be.
7276 *
7277 */
7278
7279static inline int
7280waitproc(int block, int *status)
7281{
7282 int flags;
7283
7284 flags = 0;
7285#ifdef JOBS
7286 if (jobctl)
7287 flags |= WUNTRACED;
7288#endif
7289 if (block == 0)
7290 flags |= WNOHANG;
7291 return wait3(status, flags, (struct rusage *)NULL);
7292}
7293
7361static int 7294static int
7362dowait(block, job) 7295dowait(int block, struct job *job)
7363 int block;
7364 struct job *job;
7365{ 7296{
7366 int pid; 7297 int pid;
7367 int status; 7298 int status;
@@ -7451,46 +7382,6 @@ dowait(block, job)
7451 7382
7452 7383
7453 7384
7454/*
7455 * Do a wait system call. If job control is compiled in, we accept
7456 * stopped processes. If block is zero, we return a value of zero
7457 * rather than blocking.
7458 *
7459 * System V doesn't have a non-blocking wait system call. It does
7460 * have a SIGCLD signal that is sent to a process when one of it's
7461 * children dies. The obvious way to use SIGCLD would be to install
7462 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7463 * was received, and have waitproc bump another counter when it got
7464 * the status of a process. Waitproc would then know that a wait
7465 * system call would not block if the two counters were different.
7466 * This approach doesn't work because if a process has children that
7467 * have not been waited for, System V will send it a SIGCLD when it
7468 * installs a signal handler for SIGCLD. What this means is that when
7469 * a child exits, the shell will be sent SIGCLD signals continuously
7470 * until is runs out of stack space, unless it does a wait call before
7471 * restoring the signal handler. The code below takes advantage of
7472 * this (mis)feature by installing a signal handler for SIGCLD and
7473 * then checking to see whether it was called. If there are any
7474 * children to be waited for, it will be.
7475 *
7476 */
7477
7478static int
7479waitproc(block, status)
7480 int block;
7481 int *status;
7482{
7483 int flags;
7484
7485 flags = 0;
7486#ifdef JOBS
7487 if (jobctl)
7488 flags |= WUNTRACED;
7489#endif
7490 if (block == 0)
7491 flags |= WNOHANG;
7492 return wait3(status, flags, (struct rusage *)NULL);
7493}
7494 7385
7495/* 7386/*
7496 * return 1 if there are stopped jobs, otherwise 0 7387 * return 1 if there are stopped jobs, otherwise 0
@@ -7778,10 +7669,8 @@ extern int etext();
7778#endif 7669#endif
7779 7670
7780static void read_profile (const char *); 7671static void read_profile (const char *);
7781static char *find_dot_file (char *);
7782static void cmdloop (int); 7672static void cmdloop (int);
7783static void options (int); 7673static void options (int);
7784static void minus_o (char *, int);
7785static void setoption (int, int); 7674static void setoption (int, int);
7786static void procargs (int, char **); 7675static void procargs (int, char **);
7787 7676
@@ -7802,9 +7691,8 @@ shell_main(argc, argv)
7802 struct jmploc jmploc; 7691 struct jmploc jmploc;
7803 struct stackmark smark; 7692 struct stackmark smark;
7804 volatile int state; 7693 volatile int state;
7805 char *shinit; 7694 const char *shinit;
7806 7695
7807 DOTCMD = find_builtin(".");
7808 BLTINCMD = find_builtin("builtin"); 7696 BLTINCMD = find_builtin("builtin");
7809 EXECCMD = find_builtin("exec"); 7697 EXECCMD = find_builtin("exec");
7810 EVALCMD = find_builtin("eval"); 7698 EVALCMD = find_builtin("eval");
@@ -8045,7 +7933,7 @@ readcmdfile(const char *name)
8045 */ 7933 */
8046 7934
8047 7935
8048static char * 7936static inline char *
8049find_dot_file(mybasename) 7937find_dot_file(mybasename)
8050 char *mybasename; 7938 char *mybasename;
8051{ 7939{
@@ -8114,6 +8002,7 @@ exitcmd(argc, argv)
8114 exitshell(exitstatus); 8002 exitshell(exitstatus);
8115 /* NOTREACHED */ 8003 /* NOTREACHED */
8116} 8004}
8005
8117static pointer 8006static pointer
8118stalloc(int nbytes) 8007stalloc(int nbytes)
8119{ 8008{
@@ -8314,13 +8203,13 @@ ungrabstackstr(char *s, char *p)
8314 8203
8315#undef rflag 8204#undef rflag
8316 8205
8317#ifdef __GLIBC__ 8206//#ifdef __GLIBC__
8318static mode_t getmode(const void *, mode_t); 8207static mode_t getmode(const void *, mode_t);
8319static void *setmode(const char *); 8208static void *setmode(const char *);
8209//#endif
8320 8210
8321#if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1 8211#if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
8322typedef enum __rlimit_resource rlim_t; 8212typedef long rlim_t;
8323#endif
8324#endif 8213#endif
8325 8214
8326 8215
@@ -8429,7 +8318,7 @@ umaskcmd(argc, argv)
8429 int i; 8318 int i;
8430 int symbolic_mode = 0; 8319 int symbolic_mode = 0;
8431 8320
8432 while ((i = nextopt("S")) != '\0') { 8321 while (nextopt("S") != '\0') {
8433 symbolic_mode = 1; 8322 symbolic_mode = 1;
8434 } 8323 }
8435 8324
@@ -8469,12 +8358,12 @@ umaskcmd(argc, argv)
8469 o[i++] = 'x'; 8358 o[i++] = 'x';
8470 o[i] = '\0'; 8359 o[i] = '\0';
8471 8360
8472 out1fmt("u=%s,g=%s,o=%s\n", u, g, o); 8361 printf("u=%s,g=%s,o=%s\n", u, g, o);
8473 } else { 8362 } else {
8474 out1fmt("%.4o\n", mask); 8363 printf("%.4o\n", mask);
8475 } 8364 }
8476 } else { 8365 } else {
8477 if (isdigit((unsigned char)*ap)) { 8366 if (is_digit((unsigned char)*ap)) {
8478 mask = 0; 8367 mask = 0;
8479 do { 8368 do {
8480 if (*ap >= '8' || *ap < '0') 8369 if (*ap >= '8' || *ap < '0')
@@ -8619,13 +8508,13 @@ ulimitcmd(argc, argv)
8619 else if (how & HARD) 8508 else if (how & HARD)
8620 val = limit.rlim_max; 8509 val = limit.rlim_max;
8621 8510
8622 out1fmt("%-20s ", l->name); 8511 printf("%-20s ", l->name);
8623 if (val == RLIM_INFINITY) 8512 if (val == RLIM_INFINITY)
8624 out1fmt("unlimited\n"); 8513 printf("unlimited\n");
8625 else 8514 else
8626 { 8515 {
8627 val /= l->factor; 8516 val /= l->factor;
8628 out1fmt("%lld\n", (long long) val); 8517 printf("%lld\n", (long long) val);
8629 } 8518 }
8630 } 8519 }
8631 return 0; 8520 return 0;
@@ -8646,11 +8535,11 @@ ulimitcmd(argc, argv)
8646 val = limit.rlim_max; 8535 val = limit.rlim_max;
8647 8536
8648 if (val == RLIM_INFINITY) 8537 if (val == RLIM_INFINITY)
8649 out1fmt("unlimited\n"); 8538 printf("unlimited\n");
8650 else 8539 else
8651 { 8540 {
8652 val /= l->factor; 8541 val /= l->factor;
8653 out1fmt("%lld\n", (long long) val); 8542 printf("%lld\n", (long long) val);
8654 } 8543 }
8655 } 8544 }
8656 return 0; 8545 return 0;
@@ -8660,10 +8549,8 @@ ulimitcmd(argc, argv)
8660 */ 8549 */
8661 8550
8662static int 8551static int
8663prefix(pfx, string) 8552prefix(char const *pfx, char const *string)
8664 char const *pfx; 8553{
8665 char const *string;
8666 {
8667 while (*pfx) { 8554 while (*pfx) {
8668 if (*pfx++ != *string++) 8555 if (*pfx++ != *string++)
8669 return 0; 8556 return 0;
@@ -8741,12 +8628,8 @@ single_quote(const char *s) {
8741 8628
8742 if (len1) { 8629 if (len1) {
8743 *p = '\''; 8630 *p = '\'';
8744#ifdef _GNU_SOURCE
8745 q = mempcpy(p + 1, s, len1);
8746#else
8747 q = p + 1 + len1; 8631 q = p + 1 + len1;
8748 memcpy(p + 1, s, len1); 8632 memcpy(p + 1, s, len1);
8749#endif
8750 *q++ = '\''; 8633 *q++ = '\'';
8751 s += len1; 8634 s += len1;
8752 } 8635 }
@@ -8761,13 +8644,9 @@ single_quote(const char *s) {
8761 break; 8644 break;
8762 default: 8645 default:
8763 *q = '"'; 8646 *q = '"';
8764#ifdef _GNU_SOURCE
8765 *(char *) mempcpy(q + 1, s, len2) = '"';
8766#else
8767 q += 1 + len2; 8647 q += 1 + len2;
8768 memcpy(q + 1, s, len2); 8648 memcpy(q + 1, s, len2);
8769 *q = '"'; 8649 *q = '"';
8770#endif
8771 s += len2; 8650 s += len2;
8772 } 8651 }
8773 8652
@@ -8792,79 +8671,16 @@ sstrdup(const char *p)
8792 8671
8793 8672
8794/* 8673/*
8795 * This file was generated by the mknodes program.
8796 */
8797
8798/*
8799 * Routine for dealing with parsed shell commands. 8674 * Routine for dealing with parsed shell commands.
8800 */ 8675 */
8801 8676
8802 8677
8803static int funcblocksize; /* size of structures in function */ 8678static void sizenodelist (const struct nodelist *);
8804static int funcstringsize; /* size of strings in node */ 8679static struct nodelist *copynodelist (const struct nodelist *);
8805static pointer funcblock; /* block to allocate function from */ 8680static char *nodesavestr (const char *);
8806static char *funcstring; /* block to allocate strings from */
8807
8808static const short nodesize[26] = {
8809 ALIGN(sizeof (struct nbinary)),
8810 ALIGN(sizeof (struct ncmd)),
8811 ALIGN(sizeof (struct npipe)),
8812 ALIGN(sizeof (struct nredir)),
8813 ALIGN(sizeof (struct nredir)),
8814 ALIGN(sizeof (struct nredir)),
8815 ALIGN(sizeof (struct nbinary)),
8816 ALIGN(sizeof (struct nbinary)),
8817 ALIGN(sizeof (struct nif)),
8818 ALIGN(sizeof (struct nbinary)),
8819 ALIGN(sizeof (struct nbinary)),
8820 ALIGN(sizeof (struct nfor)),
8821 ALIGN(sizeof (struct ncase)),
8822 ALIGN(sizeof (struct nclist)),
8823 ALIGN(sizeof (struct narg)),
8824 ALIGN(sizeof (struct narg)),
8825 ALIGN(sizeof (struct nfile)),
8826 ALIGN(sizeof (struct nfile)),
8827 ALIGN(sizeof (struct nfile)),
8828 ALIGN(sizeof (struct nfile)),
8829 ALIGN(sizeof (struct nfile)),
8830 ALIGN(sizeof (struct ndup)),
8831 ALIGN(sizeof (struct ndup)),
8832 ALIGN(sizeof (struct nhere)),
8833 ALIGN(sizeof (struct nhere)),
8834 ALIGN(sizeof (struct nnot)),
8835};
8836
8837
8838static void calcsize (union node *);
8839static void sizenodelist (struct nodelist *);
8840static union node *copynode (union node *);
8841static struct nodelist *copynodelist (struct nodelist *);
8842static char *nodesavestr (char *);
8843
8844
8845
8846/*
8847 * Make a copy of a parse tree.
8848 */
8849
8850static union node *
8851copyfunc(union node *n)
8852{
8853 if (n == NULL)
8854 return NULL;
8855 funcblocksize = 0;
8856 funcstringsize = 0;
8857 calcsize(n);
8858 funcblock = ckmalloc(funcblocksize + funcstringsize);
8859 funcstring = (char *) funcblock + funcblocksize;
8860 return copynode(n);
8861}
8862
8863
8864 8681
8865static void 8682static void
8866calcsize(n) 8683calcsize(const union node *n)
8867 union node *n;
8868{ 8684{
8869 if (n == NULL) 8685 if (n == NULL)
8870 return; 8686 return;
@@ -8941,11 +8757,8 @@ calcsize(n)
8941 }; 8757 };
8942} 8758}
8943 8759
8944
8945
8946static void 8760static void
8947sizenodelist(lp) 8761sizenodelist(const struct nodelist *lp)
8948 struct nodelist *lp;
8949{ 8762{
8950 while (lp) { 8763 while (lp) {
8951 funcblocksize += ALIGN(sizeof(struct nodelist)); 8764 funcblocksize += ALIGN(sizeof(struct nodelist));
@@ -8955,12 +8768,10 @@ sizenodelist(lp)
8955} 8768}
8956 8769
8957 8770
8958
8959static union node * 8771static union node *
8960copynode(n) 8772copynode(const union node *n)
8961 union node *n;
8962{ 8773{
8963 union node *new; 8774 union node *new;
8964 8775
8965 if (n == NULL) 8776 if (n == NULL)
8966 return NULL; 8777 return NULL;
@@ -9043,13 +8854,12 @@ copynode(n)
9043 break; 8854 break;
9044 }; 8855 };
9045 new->type = n->type; 8856 new->type = n->type;
9046 return new; 8857 return new;
9047} 8858}
9048 8859
9049 8860
9050static struct nodelist * 8861static struct nodelist *
9051copynodelist(lp) 8862copynodelist(const struct nodelist *lp)
9052 struct nodelist *lp;
9053{ 8863{
9054 struct nodelist *start; 8864 struct nodelist *start;
9055 struct nodelist **lpp; 8865 struct nodelist **lpp;
@@ -9067,10 +8877,8 @@ copynodelist(lp)
9067} 8877}
9068 8878
9069 8879
9070
9071static char * 8880static char *
9072nodesavestr(s) 8881nodesavestr(const char *s)
9073 char *s;
9074{ 8882{
9075#ifdef _GNU_SOURCE 8883#ifdef _GNU_SOURCE
9076 char *rtn = funcstring; 8884 char *rtn = funcstring;
@@ -9078,8 +8886,8 @@ nodesavestr(s)
9078 funcstring = stpcpy(funcstring, s) + 1; 8886 funcstring = stpcpy(funcstring, s) + 1;
9079 return rtn; 8887 return rtn;
9080#else 8888#else
9081 register char *p = s; 8889 const char *p = s;
9082 register char *q = funcstring; 8890 char *q = funcstring;
9083 char *rtn = funcstring; 8891 char *rtn = funcstring;
9084 8892
9085 while ((*q++ = *p++) != '\0') 8893 while ((*q++ = *p++) != '\0')
@@ -9149,9 +8957,29 @@ procargs(argc, argv)
9149 * to the argument list; we advance it past the options. 8957 * to the argument list; we advance it past the options.
9150 */ 8958 */
9151 8959
8960static inline void
8961minus_o(const char *name, int val)
8962{
8963 int i;
8964
8965 if (name == NULL) {
8966 out1str("Current option settings\n");
8967 for (i = 0; i < NOPTS; i++)
8968 printf("%-16s%s\n", optent_name(optlist[i]),
8969 optent_val(i) ? "on" : "off");
8970 } else {
8971 for (i = 0; i < NOPTS; i++)
8972 if (equal(name, optent_name(optlist[i]))) {
8973 setoption(optent_letter(optlist[i]), val);
8974 return;
8975 }
8976 error("Illegal option -o %s", name);
8977 }
8978}
8979
8980
9152static void 8981static void
9153options(cmdline) 8982options(int cmdline)
9154 int cmdline;
9155{ 8983{
9156 char *p; 8984 char *p;
9157 int val; 8985 int val;
@@ -9204,28 +9032,6 @@ options(cmdline)
9204 } 9032 }
9205} 9033}
9206 9034
9207static void
9208minus_o(name, val)
9209 char *name;
9210 int val;
9211{
9212 int i;
9213
9214 if (name == NULL) {
9215 out1str("Current option settings\n");
9216 for (i = 0; i < NOPTS; i++)
9217 out1fmt("%-16s%s\n", optent_name(optlist[i]),
9218 optent_val(i) ? "on" : "off");
9219 } else {
9220 for (i = 0; i < NOPTS; i++)
9221 if (equal(name, optent_name(optlist[i]))) {
9222 setoption(optent_letter(optlist[i]), val);
9223 return;
9224 }
9225 error("Illegal option -o %s", name);
9226 }
9227}
9228
9229 9035
9230static void 9036static void
9231setoption(int flag, int val) 9037setoption(int flag, int val)
@@ -9528,7 +9334,6 @@ out:
9528 if (err) { 9334 if (err) {
9529 *myoptind = 1; 9335 *myoptind = 1;
9530 *optoff = -1; 9336 *optoff = -1;
9531 flushall();
9532 exraise(EXERROR); 9337 exraise(EXERROR);
9533 } 9338 }
9534 return done; 9339 return done;
@@ -9547,9 +9352,8 @@ out:
9547 */ 9352 */
9548 9353
9549static int 9354static int
9550nextopt(optstring) 9355nextopt(const char *optstring)
9551 const char *optstring; 9356{
9552 {
9553 char *p; 9357 char *p;
9554 const char *q; 9358 const char *q;
9555 char c; 9359 char c;
@@ -9596,16 +9400,6 @@ out2fmt(const char *fmt, ...)
9596 va_end(ap); 9400 va_end(ap);
9597} 9401}
9598 9402
9599
9600static void
9601out1fmt(const char *fmt, ...)
9602{
9603 va_list ap;
9604 va_start(ap, fmt);
9605 vfprintf(stdout, fmt, ap);
9606 va_end(ap);
9607}
9608
9609/* 9403/*
9610 * Version of write which resumes after a signal is caught. 9404 * Version of write which resumes after a signal is caught.
9611 */ 9405 */
@@ -11121,26 +10915,21 @@ synerror(const char *msg)
11121 * called by editline -- any expansions to the prompt 10915 * called by editline -- any expansions to the prompt
11122 * should be added here. 10916 * should be added here.
11123 */ 10917 */
11124static inline const char * 10918static void
11125getprompt(void *unused) 10919setprompt(int whichprompt)
11126{ 10920{
11127 switch (whichprompt) { 10921 char *prompt;
11128 case 0: 10922 switch (whichprompt) {
11129 return "";
11130 case 1: 10923 case 1:
11131 return ps1val(); 10924 prompt = ps1val();
10925 break;
11132 case 2: 10926 case 2:
11133 return ps2val(); 10927 prompt = ps2val();
11134 default: 10928 break;
11135 return "<internal prompt error>"; 10929 default: /* 0 */
11136 } 10930 prompt = "";
11137} 10931 }
11138 10932 putprompt(prompt);
11139static void
11140setprompt(int which)
11141{
11142 whichprompt = which;
11143 putprompt(getprompt(NULL));
11144} 10933}
11145 10934
11146 10935
@@ -11156,90 +10945,109 @@ setprompt(int which)
11156#endif 10945#endif
11157 10946
11158 10947
11159
11160/* 10948/*
11161 * Process a list of redirection commands. If the REDIR_PUSH flag is set, 10949 * Open a file in noclobber mode.
11162 * old file descriptors are stashed away so that the redirection can be 10950 * The code was copied from bash.
11163 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11164 * standard output, and the standard error if it becomes a duplicate of
11165 * stdout.
11166 */ 10951 */
10952static inline int
10953noclobberopen(const char *fname)
10954{
10955 int r, fd;
10956 struct stat finfo, finfo2;
11167 10957
11168static void 10958 /*
11169redirect(redir, flags) 10959 * If the file exists and is a regular file, return an error
11170 union node *redir; 10960 * immediately.
11171 int flags; 10961 */
11172 { 10962 r = stat(fname, &finfo);
11173 union node *n; 10963 if (r == 0 && S_ISREG(finfo.st_mode)) {
11174 struct redirtab *sv = NULL; 10964 errno = EEXIST;
11175 int i; 10965 return -1;
11176 int fd;
11177 int newfd;
11178 int try;
11179 char memory[10]; /* file descriptors to write to memory */
11180
11181 for (i = 10 ; --i >= 0 ; )
11182 memory[i] = 0;
11183 memory[1] = flags & REDIR_BACKQ;
11184 if (flags & REDIR_PUSH) {
11185 sv = ckmalloc(sizeof (struct redirtab));
11186 for (i = 0 ; i < 10 ; i++)
11187 sv->renamed[i] = EMPTY;
11188 sv->next = redirlist;
11189 redirlist = sv;
11190 } 10966 }
11191 for (n = redir ; n ; n = n->nfile.next) {
11192 fd = n->nfile.fd;
11193 try = 0;
11194 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
11195 n->ndup.dupfd == fd)
11196 continue; /* redirect from/to same file descriptor */
11197 10967
11198 INTOFF; 10968 /*
11199 newfd = openredirect(n); 10969 * If the file was not present (r != 0), make sure we open it
11200 if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) { 10970 * exclusively so that if it is created before we open it, our open
11201 if (newfd == fd) { 10971 * will fail. Make sure that we do not truncate an existing file.
11202 try++; 10972 * Note that we don't turn on O_EXCL unless the stat failed -- if the
11203 } else if ((i = fcntl(fd, F_DUPFD, 10)) == -1) { 10973 * file was not a regular file, we leave O_EXCL off.
11204 switch (errno) { 10974 */
11205 case EBADF: 10975 if (r != 0)
11206 if (!try) { 10976 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
11207 dupredirect(n, newfd, memory); 10977 fd = open(fname, O_WRONLY|O_CREAT, 0666);
11208 try++; 10978
11209 break; 10979 /* If the open failed, return the file descriptor right away. */
11210 } 10980 if (fd < 0)
11211 /* FALLTHROUGH*/ 10981 return fd;
11212 default: 10982
11213 if (newfd >= 0) { 10983 /*
11214 close(newfd); 10984 * OK, the open succeeded, but the file may have been changed from a
11215 } 10985 * non-regular file to a regular file between the stat and the open.
11216 INTON; 10986 * We are assuming that the O_EXCL open handles the case where FILENAME
11217 error("%d: %m", fd); 10987 * did not exist and is symlinked to an existing file between the stat
11218 /* NOTREACHED */ 10988 * and open.
11219 } 10989 */
11220 } 10990
11221 if (!try) { 10991 /*
11222 close(fd); 10992 * If we can open it and fstat the file descriptor, and neither check
11223 if (flags & REDIR_PUSH) { 10993 * revealed that it was a regular file, and the file has not been
11224 sv->renamed[fd] = i; 10994 * replaced, return the file descriptor.
11225 } 10995 */
11226 } 10996 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
11227 } else if (fd != newfd) { 10997 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
11228 close(fd); 10998 return fd;
10999
11000 /* The file has been replaced. badness. */
11001 close(fd);
11002 errno = EEXIST;
11003 return -1;
11004}
11005
11006/*
11007 * Handle here documents. Normally we fork off a process to write the
11008 * data to a pipe. If the document is short, we can stuff the data in
11009 * the pipe without forking.
11010 */
11011
11012static inline int
11013openhere(const union node *redir)
11014{
11015 int pip[2];
11016 int len = 0;
11017
11018 if (pipe(pip) < 0)
11019 error("Pipe call failed");
11020 if (redir->type == NHERE) {
11021 len = strlen(redir->nhere.doc->narg.text);
11022 if (len <= PIPESIZE) {
11023 xwrite(pip[1], redir->nhere.doc->narg.text, len);
11024 goto out;
11229 } 11025 }
11230 if (fd == 0)
11231 fd0_redirected++;
11232 if (!try)
11233 dupredirect(n, newfd, memory);
11234 INTON;
11235 } 11026 }
11027 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
11028 close(pip[0]);
11029 signal(SIGINT, SIG_IGN);
11030 signal(SIGQUIT, SIG_IGN);
11031 signal(SIGHUP, SIG_IGN);
11032#ifdef SIGTSTP
11033 signal(SIGTSTP, SIG_IGN);
11034#endif
11035 signal(SIGPIPE, SIG_DFL);
11036 if (redir->type == NHERE)
11037 xwrite(pip[1], redir->nhere.doc->narg.text, len);
11038 else
11039 expandhere(redir->nhere.doc, pip[1]);
11040 _exit(0);
11041 }
11042out:
11043 close(pip[1]);
11044 return pip[0];
11236} 11045}
11237 11046
11238 11047
11239static int 11048static inline int
11240openredirect(redir) 11049openredirect(const union node *redir)
11241 union node *redir; 11050{
11242 {
11243 char *fname; 11051 char *fname;
11244 int f; 11052 int f;
11245 11053
@@ -11307,17 +11115,90 @@ eopen:
11307} 11115}
11308 11116
11309 11117
11118/*
11119 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11120 * old file descriptors are stashed away so that the redirection can be
11121 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11122 * standard output, and the standard error if it becomes a duplicate of
11123 * stdout.
11124 */
11125
11126static void
11127redirect(union node *redir, int flags)
11128{
11129 union node *n;
11130 struct redirtab *sv = NULL;
11131 int i;
11132 int fd;
11133 int newfd;
11134 int try;
11135 int fd1dup = flags & REDIR_BACKQ;; /* stdout `cmd` redir to pipe */
11136
11137 if (flags & REDIR_PUSH) {
11138 sv = ckmalloc(sizeof (struct redirtab));
11139 for (i = 0 ; i < 10 ; i++)
11140 sv->renamed[i] = EMPTY;
11141 sv->next = redirlist;
11142 redirlist = sv;
11143 }
11144 for (n = redir ; n ; n = n->nfile.next) {
11145 fd = n->nfile.fd;
11146 try = 0;
11147 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
11148 n->ndup.dupfd == fd)
11149 continue; /* redirect from/to same file descriptor */
11150
11151 INTOFF;
11152 newfd = openredirect(n);
11153 if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
11154 if (newfd == fd) {
11155 try++;
11156 } else if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
11157 switch (errno) {
11158 case EBADF:
11159 if (!try) {
11160 dupredirect(n, newfd, fd1dup);
11161 try++;
11162 break;
11163 }
11164 /* FALLTHROUGH*/
11165 default:
11166 if (newfd >= 0) {
11167 close(newfd);
11168 }
11169 INTON;
11170 error("%d: %m", fd);
11171 /* NOTREACHED */
11172 }
11173 }
11174 if (!try) {
11175 close(fd);
11176 if (flags & REDIR_PUSH) {
11177 sv->renamed[fd] = i;
11178 }
11179 }
11180 } else if (fd != newfd) {
11181 close(fd);
11182 }
11183 if (fd == 0)
11184 fd0_redirected++;
11185 if (!try)
11186 dupredirect(n, newfd, fd1dup);
11187 INTON;
11188 }
11189}
11190
11191
11310static void 11192static void
11311dupredirect(union node *redir, int f, char memory[10]) 11193dupredirect(const union node *redir, int f, int fd1dup)
11312{ 11194{
11313 int fd = redir->nfile.fd; 11195 int fd = redir->nfile.fd;
11314 11196
11315 memory[fd] = 0; 11197 if(fd==1)
11198 fd1dup = 0;
11316 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) { 11199 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
11317 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */ 11200 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
11318 if (memory[redir->ndup.dupfd]) 11201 if (redir->ndup.dupfd!=1 || fd1dup!=1)
11319 memory[fd] = 1;
11320 else
11321 dup_as_newfd(redir->ndup.dupfd, fd); 11202 dup_as_newfd(redir->ndup.dupfd, fd);
11322 } 11203 }
11323 return; 11204 return;
@@ -11331,48 +11212,6 @@ dupredirect(union node *redir, int f, char memory[10])
11331} 11212}
11332 11213
11333 11214
11334/*
11335 * Handle here documents. Normally we fork off a process to write the
11336 * data to a pipe. If the document is short, we can stuff the data in
11337 * the pipe without forking.
11338 */
11339
11340static int
11341openhere(redir)
11342 union node *redir;
11343 {
11344 int pip[2];
11345 int len = 0;
11346
11347 if (pipe(pip) < 0)
11348 error("Pipe call failed");
11349 if (redir->type == NHERE) {
11350 len = strlen(redir->nhere.doc->narg.text);
11351 if (len <= PIPESIZE) {
11352 xwrite(pip[1], redir->nhere.doc->narg.text, len);
11353 goto out;
11354 }
11355 }
11356 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
11357 close(pip[0]);
11358 signal(SIGINT, SIG_IGN);
11359 signal(SIGQUIT, SIG_IGN);
11360 signal(SIGHUP, SIG_IGN);
11361#ifdef SIGTSTP
11362 signal(SIGTSTP, SIG_IGN);
11363#endif
11364 signal(SIGPIPE, SIG_DFL);
11365 if (redir->type == NHERE)
11366 xwrite(pip[1], redir->nhere.doc->narg.text, len);
11367 else
11368 expandhere(redir->nhere.doc, pip[1]);
11369 _exit(0);
11370 }
11371out:
11372 close(pip[1]);
11373 return pip[0];
11374}
11375
11376 11215
11377/* 11216/*
11378 * Undo the effects of the last redirection. 11217 * Undo the effects of the last redirection.
@@ -11444,70 +11283,17 @@ dup_as_newfd(from, to)
11444 return newfd; 11283 return newfd;
11445} 11284}
11446 11285
11447/*
11448 * Open a file in noclobber mode.
11449 * The code was copied from bash.
11450 */
11451static int
11452noclobberopen(const char *fname)
11453{
11454 int r, fd;
11455 struct stat finfo, finfo2;
11456
11457 /*
11458 * If the file exists and is a regular file, return an error
11459 * immediately.
11460 */
11461 r = stat(fname, &finfo);
11462 if (r == 0 && S_ISREG(finfo.st_mode)) {
11463 errno = EEXIST;
11464 return -1;
11465 }
11466
11467 /*
11468 * If the file was not present (r != 0), make sure we open it
11469 * exclusively so that if it is created before we open it, our open
11470 * will fail. Make sure that we do not truncate an existing file.
11471 * Note that we don't turn on O_EXCL unless the stat failed -- if the
11472 * file was not a regular file, we leave O_EXCL off.
11473 */
11474 if (r != 0)
11475 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
11476 fd = open(fname, O_WRONLY|O_CREAT, 0666);
11477
11478 /* If the open failed, return the file descriptor right away. */
11479 if (fd < 0)
11480 return fd;
11481
11482 /*
11483 * OK, the open succeeded, but the file may have been changed from a
11484 * non-regular file to a regular file between the stat and the open.
11485 * We are assuming that the O_EXCL open handles the case where FILENAME
11486 * did not exist and is symlinked to an existing file between the stat
11487 * and open.
11488 */
11489
11490 /*
11491 * If we can open it and fstat the file descriptor, and neither check
11492 * revealed that it was a regular file, and the file has not been
11493 * replaced, return the file descriptor.
11494 */
11495 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
11496 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
11497 return fd;
11498
11499 /* The file has been replaced. badness. */
11500 close(fd);
11501 errno = EEXIST;
11502 return -1;
11503}
11504/*#ifdef __weak_alias 11286/*#ifdef __weak_alias
11505__weak_alias(getmode,_getmode) 11287__weak_alias(getmode,_getmode)
11506__weak_alias(setmode,_setmode) 11288__weak_alias(setmode,_setmode)
11507#endif*/ 11289#endif*/
11508 11290
11509#ifdef __GLIBC__ 11291#ifndef S_ISTXT
11292#if defined(__GLIBC__) && __GLIBC__ >= 2
11510#define S_ISTXT __S_ISVTX 11293#define S_ISTXT __S_ISVTX
11294#else
11295#define S_ISTXT S_ISVTX
11296#endif
11511#endif 11297#endif
11512 11298
11513#define SET_LEN 6 /* initial # of bitcmd struct to malloc */ 11299#define SET_LEN 6 /* initial # of bitcmd struct to malloc */
@@ -11665,7 +11451,7 @@ setmode(p)
11665 * If an absolute number, get it and return; disallow non-octal digits 11451 * If an absolute number, get it and return; disallow non-octal digits
11666 * or illegal bits. 11452 * or illegal bits.
11667 */ 11453 */
11668 if (isdigit((unsigned char)*p)) { 11454 if (is_digit((unsigned char)*p)) {
11669 perm = (mode_t)strtol(p, &ep, 8); 11455 perm = (mode_t)strtol(p, &ep, 8);
11670 if (*ep || perm & ~(STANDARD_BITS|S_ISTXT)) { 11456 if (*ep || perm & ~(STANDARD_BITS|S_ISTXT)) {
11671 free(saveset); 11457 free(saveset);
@@ -12320,7 +12106,7 @@ trapcmd(argc, argv)
12320 char *p; 12106 char *p;
12321 12107
12322 p = single_quote(trap[signo]); 12108 p = single_quote(trap[signo]);
12323 out1fmt("trap -- %s %s\n", p, 12109 printf("trap -- %s %s\n", p,
12324 signal_names[signo] + (signo ? 3 : 0) 12110 signal_names[signo] + (signo ? 3 : 0)
12325 ); 12111 );
12326 stunalloc(p); 12112 stunalloc(p);
@@ -12734,7 +12520,7 @@ listsetvar(mylist)
12734 * Find the value of a variable. Returns NULL if not set. 12520 * Find the value of a variable. Returns NULL if not set.
12735 */ 12521 */
12736 12522
12737static char * 12523static const char *
12738lookupvar(name) 12524lookupvar(name)
12739 const char *name; 12525 const char *name;
12740 { 12526 {
@@ -12752,11 +12538,10 @@ lookupvar(name)
12752 * Search the environment of a builtin command. 12538 * Search the environment of a builtin command.
12753 */ 12539 */
12754 12540
12755static char * 12541static const char *
12756bltinlookup(name) 12542bltinlookup(const char *name)
12757 const char *name;
12758{ 12543{
12759 struct strlist *sp; 12544 const struct strlist *sp;
12760 12545
12761 for (sp = cmdenviron ; sp ; sp = sp->next) { 12546 for (sp = cmdenviron ; sp ; sp = sp->next) {
12762 if (varequal(sp->text, name)) 12547 if (varequal(sp->text, name))
@@ -13038,9 +12823,8 @@ unsetcmd(argc, argv)
13038 */ 12823 */
13039 12824
13040static int 12825static int
13041unsetvar(s) 12826unsetvar(const char *s)
13042 const char *s; 12827{
13043 {
13044 struct var **vpp; 12828 struct var **vpp;
13045 struct var *vp; 12829 struct var *vp;
13046 12830
@@ -13074,9 +12858,8 @@ unsetvar(s)
13074 */ 12858 */
13075 12859
13076static struct var ** 12860static struct var **
13077hashvar(p) 12861hashvar(const char *p)
13078 const char *p; 12862{
13079 {
13080 unsigned int hashval; 12863 unsigned int hashval;
13081 12864
13082 hashval = ((unsigned char) *p) << 4; 12865 hashval = ((unsigned char) *p) << 4;
@@ -13094,9 +12877,8 @@ hashvar(p)
13094 */ 12877 */
13095 12878
13096static int 12879static int
13097varequal(p, q) 12880varequal(const char *p, const char *q)
13098 const char *p, *q; 12881{
13099 {
13100 while (*p == *q++) { 12882 while (*p == *q++) {
13101 if (*p++ == '=') 12883 if (*p++ == '=')
13102 return 1; 12884 return 1;
@@ -13123,10 +12905,8 @@ showvars(const char *myprefix, int mask, int xor)
13123 len = p - vp->text; 12905 len = p - vp->text;
13124 p = single_quote(p); 12906 p = single_quote(p);
13125 12907
13126 out1fmt( 12908 printf("%s%s%.*s%s\n", myprefix, sep, len,
13127 "%s%s%.*s%s\n", myprefix, sep, len, 12909 vp->text, p);
13128 vp->text, p
13129 );
13130 stunalloc(p); 12910 stunalloc(p);
13131 } 12911 }
13132 } 12912 }
@@ -13147,7 +12927,7 @@ findvar(struct var **vpp, const char *name)
13147/* 12927/*
13148 * Copyright (c) 1999 Herbert Xu <herbert@debian.org> 12928 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
13149 * This file contains code for the times builtin. 12929 * This file contains code for the times builtin.
13150 * $Id: ash.c,v 1.7 2001/07/07 00:05:55 andersen Exp $ 12930 * $Id: ash.c,v 1.8 2001/07/10 06:09:16 andersen Exp $
13151 */ 12931 */
13152static int timescmd (int argc, char **argv) 12932static int timescmd (int argc, char **argv)
13153{ 12933{