diff options
author | Eric Andersen <andersen@codepoet.org> | 2001-07-10 06:09:16 +0000 |
---|---|---|
committer | Eric Andersen <andersen@codepoet.org> | 2001-07-10 06:09:16 +0000 |
commit | 6248355c6f64cf2828ec0080930d3926e38d4c97 (patch) | |
tree | f51e43c461d7f6d0610f4e48967e844cd634720d | |
parent | 5a4a46a2519af1e79d931a856ee1a3b70e60d168 (diff) | |
download | busybox-w32-6248355c6f64cf2828ec0080930d3926e38d4c97.tar.gz busybox-w32-6248355c6f64cf2828ec0080930d3926e38d4c97.tar.bz2 busybox-w32-6248355c6f64cf2828ec0080930d3926e38d4c97.zip |
vodz' latest update to ash.c
-rw-r--r-- | ash.c | 2104 | ||||
-rw-r--r-- | shell/ash.c | 2104 |
2 files changed, 1884 insertions, 2324 deletions
@@ -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 | |||
664 | struct 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 | |||
673 | static struct tblentry *cmdtable[CMDTABLESIZE]; | ||
674 | static int builtinloc = -1; /* index in path of %builtin, or -1 */ | ||
675 | static int exerrno = 0; /* Last exec error */ | ||
676 | |||
677 | |||
678 | static void tryexec (char *, char **, char **); | ||
679 | static void printentry (struct tblentry *, int); | ||
680 | static void clearcmdentry (int); | ||
681 | static struct tblentry *cmdlookup (const char *, int); | ||
682 | static void delete_cmd_entry (void); | ||
683 | static int path_change (const char *, int *); | ||
684 | |||
685 | |||
665 | static void flushall (void); | 686 | static void flushall (void); |
666 | static void out2fmt (const char *, ...) | 687 | static void out2fmt (const char *, ...) |
667 | __attribute__((__format__(__printf__,1,2))); | 688 | __attribute__((__format__(__printf__,1,2))); |
668 | static void out1fmt (const char *, ...) | ||
669 | __attribute__((__format__(__printf__,1,2))); | ||
670 | static int xwrite (int, const char *, int); | 689 | static int xwrite (int, const char *, int); |
671 | 690 | ||
672 | static void outstr (const char *p, FILE *file) { fputs(p, file); } | 691 | static void outstr (const char *p, FILE *file) { fputs(p, file); } |
673 | static void out1str(const char *p) { outstr(p, stdout); } | 692 | static void out1str(const char *p) { outstr(p, stdout); } |
674 | static void out2str(const char *p) { outstr(p, stderr); } | 693 | static 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 | ||
698 | static 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 */ |
679 | static const char basesyntax[257] = { | 702 | static 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) |
1198 | static char *_rmescapes (char *, int); | 1221 | static char *_rmescapes (char *, int); |
1199 | #else | 1222 | #else |
@@ -1316,8 +1339,8 @@ static void initvar (void); | |||
1316 | static void setvar (const char *, const char *, int); | 1339 | static void setvar (const char *, const char *, int); |
1317 | static void setvareq (char *, int); | 1340 | static void setvareq (char *, int); |
1318 | static void listsetvar (struct strlist *); | 1341 | static void listsetvar (struct strlist *); |
1319 | static char *lookupvar (const char *); | 1342 | static const char *lookupvar (const char *); |
1320 | static char *bltinlookup (const char *); | 1343 | static const char *bltinlookup (const char *); |
1321 | static char **environment (void); | 1344 | static char **environment (void); |
1322 | static int showvarscmd (int, char **); | 1345 | static int showvarscmd (int, char **); |
1323 | static void mklocal (char *); | 1346 | static 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 |
1628 | static int expcmd (int, char **); | 1651 | static int expcmd (int, char **); |
1629 | #endif | 1652 | #endif |
1630 | #ifdef ASH_TYPE | ||
1631 | static int typecmd (int, char **); | 1653 | static int typecmd (int, char **); |
1632 | #endif | ||
1633 | #ifdef ASH_GETOPTS | 1654 | #ifdef ASH_GETOPTS |
1634 | static int getoptscmd (int, char **); | 1655 | static 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 | ||
1639 | static int true_main (int, char **); | 1659 | static int true_main (int, char **); |
1640 | static int false_main (int, char **); | 1660 | static int false_main (int, char **); |
1641 | # endif | ||
1642 | #endif | 1661 | #endif |
1643 | 1662 | ||
1644 | static void setpwd (const char *, int); | 1663 | static void setpwd (const char *, int); |
@@ -1669,7 +1688,7 @@ struct builtincmd { | |||
1669 | * have been warned. | 1688 | * have been warned. |
1670 | */ | 1689 | */ |
1671 | static const struct builtincmd builtincmds[] = { | 1690 | static 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 |
1797 | static int intreceived; | 1808 | static int intreceived; |
1798 | 1809 | ||
1799 | static struct job *makejob (union node *, int); | 1810 | static struct job *makejob (const union node *, int); |
1800 | static int forkshell (struct job *, union node *, int); | 1811 | static int forkshell (struct job *, const union node *, int); |
1801 | static int waitforjob (struct job *); | 1812 | static int waitforjob (struct job *); |
1802 | 1813 | ||
1803 | static int docd (char *, int); | 1814 | static 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 | ||
2222 | struct errname { | 2233 | struct 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 */ | |||
2337 | static int funcnest; /* depth of function calls */ | 2348 | static int funcnest; /* depth of function calls */ |
2338 | 2349 | ||
2339 | 2350 | ||
2340 | |||
2341 | static struct strlist *cmdenviron; /* environment for builtin command */ | 2351 | static struct strlist *cmdenviron; /* environment for builtin command */ |
2342 | static int exitstatus; /* exit status of last command */ | 2352 | static int exitstatus; /* exit status of last command */ |
2343 | static int oexitstatus; /* saved exit status */ | 2353 | static int oexitstatus; /* saved exit status */ |
2344 | 2354 | ||
2345 | 2355 | static void evalsubshell (const union node *, int); | |
2346 | static void evalloop (union node *, int); | ||
2347 | static void evalfor (union node *, int); | ||
2348 | static void evalcase (union node *, int); | ||
2349 | static void evalsubshell (union node *, int); | ||
2350 | static void expredir (union node *); | 2356 | static void expredir (union node *); |
2351 | static void evalpipe (union node *); | ||
2352 | static void evalcommand (union node *, int); | ||
2353 | static void prehash (union node *); | 2357 | static void prehash (union node *); |
2354 | static void eprintlist (struct strlist *); | 2358 | static 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 | ||
2426 | static struct builtincmd *find_builtin (const char *); | ||
2427 | static void expandarg (union node *, struct arglist *, int); | ||
2428 | static void calcsize (const union node *); | ||
2429 | static union node *copynode (const union node *); | ||
2430 | |||
2431 | /* | ||
2432 | * Make a copy of a parse tree. | ||
2433 | */ | ||
2434 | |||
2435 | static int funcblocksize; /* size of structures in function */ | ||
2436 | static int funcstringsize; /* size of strings in node */ | ||
2437 | static pointer funcblock; /* block to allocate function from */ | ||
2438 | static char *funcstring; /* block to allocate strings from */ | ||
2439 | |||
2440 | |||
2441 | static inline union node * | ||
2442 | copyfunc(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 | */ |
2426 | static struct builtincmd *find_builtin (const char *); | ||
2427 | static void defun (char *, union node *); | ||
2428 | 2457 | ||
2429 | static void | 2458 | static void |
2430 | evaltree(n, flags) | 2459 | freefunc(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; | 2471 | static inline void |
2519 | break; | 2472 | addcmdentry(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 | } |
2526 | out: | 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 | 2486 | static inline void | |
2537 | static void | 2487 | evalloop(const union node *n, int flags) |
2538 | evalloop(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 | ||
2573 | static void expandarg (union node *, struct arglist *, int); | ||
2574 | static void fixredir(union node *n, const char *text, int err); | ||
2575 | |||
2576 | static void | 2520 | static void |
2577 | evalfor(n, flags) | 2521 | evalfor(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 | 2558 | static inline void | |
2617 | static void | 2559 | evalcase(const union node *n, int flags) |
2618 | evalcase(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 | |||
2649 | static void | ||
2650 | evalsubshell(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 | |||
2677 | static void | ||
2678 | expredir(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 | ||
2714 | static void | 2591 | static inline void |
2715 | evalpipe(n) | 2592 | evalpipe(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 | |||
2785 | static void | ||
2786 | evalbackcmd(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; | ||
2819 | out: | ||
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 | |||
2831 | static void find_command (const char *, struct cmdentry *, int, const char *); | 2653 | static void find_command (const char *, struct cmdentry *, int, const char *); |
2832 | 2654 | ||
2833 | static int | 2655 | static int |
@@ -2841,6 +2663,7 @@ isassignment(const char *word) { | |||
2841 | return *word == '='; | 2663 | return *word == '='; |
2842 | } | 2664 | } |
2843 | 2665 | ||
2666 | |||
2844 | static void | 2667 | static void |
2845 | evalcommand(union node *cmd, int flags) | 2668 | evalcommand(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 | */ | ||
2974 | static void | ||
2975 | evaltree(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 | } | ||
3074 | out: | ||
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 | |||
3088 | static void | ||
3089 | evalsubshell(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 | |||
3113 | static void fixredir(union node *n, const char *text, int err); | ||
3114 | |||
3115 | static void | ||
3116 | expredir(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 | |||
3152 | static void | ||
3153 | evalbackcmd(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; | ||
3186 | out: | ||
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 | ||
3248 | static int | 3294 | static int |
3249 | false_main(argc, argv) | 3295 | false_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 | |||
3342 | struct 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 | |||
3351 | static struct tblentry *cmdtable[CMDTABLESIZE]; | ||
3352 | static int builtinloc = -1; /* index in path of %builtin, or -1 */ | ||
3353 | static int exerrno = 0; /* Last exec error */ | ||
3354 | |||
3355 | |||
3356 | static void tryexec (char *, char **, char **); | ||
3357 | static void printentry (struct tblentry *, int); | ||
3358 | static void clearcmdentry (int); | ||
3359 | static struct tblentry *cmdlookup (const char *, int); | ||
3360 | static void delete_cmd_entry (void); | ||
3361 | #ifdef ASH_TYPE | ||
3362 | static int describe_command (char *, int); | ||
3363 | #endif | ||
3364 | static 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 | ||
3493 | static int preadbuffer(void); | 3501 | static int preadbuffer(void); |
3494 | static void pushfile (void); | 3502 | static void pushfile (void); |
3495 | static 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 | ||
3634 | static void | 3641 | static void |
3635 | tryexec(cmd, argv, envp) | 3642 | tryexec(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 | */ | ||
3728 | static int | ||
3729 | pstrcmp(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 | |||
3738 | static const char *const * | ||
3739 | findkwd(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 | |||
3776 | static void | 3819 | static void |
3777 | printentry(cmdp, verbose) | 3820 | printentry(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) | |||
3817 | static int helpcmd(int argc, char** argv) | 3863 | static 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 | |||
4145 | static void | ||
4146 | freefunc(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 | ||
4246 | static void | ||
4247 | addcmdentry(char *name, struct cmdentry *entry) | ||
4248 | { | ||
4249 | struct tblentry *cmdp; | ||
4250 | 4268 | ||
4251 | INTOFF; | 4269 | static 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)), | |
4266 | static union node *copyfunc(union node *); | 4284 | ALIGN(sizeof (struct narg)), |
4267 | 4285 | ALIGN(sizeof (struct narg)), | |
4268 | static void | 4286 | ALIGN(sizeof (struct nfile)), |
4269 | defun(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 | */ | ||
4297 | static int | ||
4298 | pstrcmp(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 | |||
4307 | static const char *const * | ||
4308 | findkwd(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 | ||
4319 | static int | 4320 | static int |
4320 | typecmd(argc, argv) | 4321 | typecmd(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 | ||
4333 | static int | ||
4334 | describe_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 | |||
4423 | out: | ||
4424 | putchar('\n'); | ||
4425 | return 0; | ||
4426 | } | ||
4427 | #endif | ||
4428 | |||
4429 | #ifdef ASH_CMDCMD | 4338 | #ifdef ASH_CMDCMD |
4430 | static int | 4339 | static int |
4431 | commandcmd(argc, argv) | 4340 | commandcmd(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); | |||
4541 | static char *exptilde (char *, int); | 4449 | static char *exptilde (char *, int); |
4542 | static void expbackq (union node *, int, int); | 4450 | static void expbackq (union node *, int, int); |
4543 | static int subevalvar (char *, char *, int, int, int, int, int); | 4451 | static int subevalvar (char *, char *, int, int, int, int, int); |
4544 | static char *evalvar (char *, int); | ||
4545 | static int varisset (char *, int); | 4452 | static int varisset (char *, int); |
4546 | static void strtodest (const char *, const char *, int); | 4453 | static void strtodest (const char *, const char *, int); |
4547 | static void varvalue (char *, int, int); | 4454 | static void varvalue (char *, int, int); |
@@ -4550,21 +4457,21 @@ static void removerecordregions (int); | |||
4550 | static void ifsbreakup (char *, struct arglist *); | 4457 | static void ifsbreakup (char *, struct arglist *); |
4551 | static void ifsfree (void); | 4458 | static void ifsfree (void); |
4552 | static void expandmeta (struct strlist *, int); | 4459 | static 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) |
4556 | static void addglob (const glob_t *); | 4463 | static 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)) |
4560 | static void expmeta (char *, char *); | 4467 | static 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)) |
4563 | static struct strlist *expsort (struct strlist *); | 4470 | static struct strlist *expsort (struct strlist *); |
4564 | static struct strlist *msort (struct strlist *, int); | 4471 | static struct strlist *msort (struct strlist *, int); |
4565 | #endif | 4472 | #endif |
4566 | #if defined(__GLIBC__) && !defined(FNMATCH_BROKEN) | ||
4567 | static int patmatch (char *, char *, int); | 4473 | static int patmatch (char *, char *, int); |
4474 | #if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) | ||
4568 | static int patmatch2 (char *, char *, int); | 4475 | static int patmatch2 (char *, char *, int); |
4569 | #else | 4476 | #else |
4570 | static int pmatch (char *, char *, int); | 4477 | static 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 */ |
4580 | static void | 4487 | static inline void |
4581 | expandhere(union node *arg, int fd) | 4488 | expandhere(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 | |||
4553 | static inline char * | ||
4554 | evalvar(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; | ||
4578 | again: /* 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; | ||
4629 | record: | ||
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 | |||
5098 | static char * | ||
5099 | evalvar(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; | ||
5123 | again: /* 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; | ||
5174 | record: | ||
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) |
5546 | static void | 5453 | static void |
5547 | expandmeta(str, flag) | 5454 | expandmeta(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 */ |
5862 | static int | 5769 | static int |
5863 | patmatch(char *pattern, char *string, int squoted) | 5770 | patmatch(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) |
6019 | static char * | 5926 | static 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 | ||
6138 | static int whichprompt; /* 1 == PS1, 2 == PS2 */ | ||
6139 | |||
6140 | |||
6141 | struct redirtab { | 6041 | struct 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 | ||
6146 | static struct redirtab *redirlist; | 6047 | static 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 | ||
6276 | static char * | 6177 | static inline char * |
6277 | pfgets(char *line, int len) | 6178 | pfgets(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 | ||
6298 | static int | 6199 | static inline int |
6299 | preadfd(void) | 6200 | preadfd(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 | ||
6489 | static void | 6388 | static void |
6490 | setinputstring(string) | 6389 | setinputstring(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 *); | |||
6528 | static void freejob (struct job *); | 6426 | static void freejob (struct job *); |
6529 | static struct job *getjob (const char *); | 6427 | static struct job *getjob (const char *); |
6530 | static int dowait (int, struct job *); | 6428 | static int dowait (int, struct job *); |
6531 | static int waitproc (int, int *); | ||
6532 | static void waitonint(int); | 6429 | static 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 | ||
6548 | static int openredirect (union node *); | 6445 | static void dupredirect (const union node *, int, int fd1dup); |
6549 | static void dupredirect (union node *, int, char[10 ]); | ||
6550 | static int openhere (union node *); | ||
6551 | static 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 | ||
6948 | static void | 6842 | static void |
6949 | freejob(jp) | 6843 | freejob(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 | ||
7086 | static struct job * | 6979 | static struct job * |
7087 | makejob(node, nprocs) | 6980 | makejob(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 | ||
7154 | static int | 7045 | static int |
7155 | forkshell(struct job *jp, union node *n, int mode) | 7046 | forkshell(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 | ||
7277 | static int | 7172 | static int |
7278 | waitforjob(jp) | 7173 | waitforjob(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 | |||
7279 | static inline int | ||
7280 | waitproc(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 | |||
7361 | static int | 7294 | static int |
7362 | dowait(block, job) | 7295 | dowait(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 | |||
7478 | static int | ||
7479 | waitproc(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 | ||
7780 | static void read_profile (const char *); | 7671 | static void read_profile (const char *); |
7781 | static char *find_dot_file (char *); | ||
7782 | static void cmdloop (int); | 7672 | static void cmdloop (int); |
7783 | static void options (int); | 7673 | static void options (int); |
7784 | static void minus_o (char *, int); | ||
7785 | static void setoption (int, int); | 7674 | static void setoption (int, int); |
7786 | static void procargs (int, char **); | 7675 | static 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 | ||
8048 | static char * | 7936 | static inline char * |
8049 | find_dot_file(mybasename) | 7937 | find_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 | |||
8117 | static pointer | 8006 | static pointer |
8118 | stalloc(int nbytes) | 8007 | stalloc(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__ |
8318 | static mode_t getmode(const void *, mode_t); | 8207 | static mode_t getmode(const void *, mode_t); |
8319 | static void *setmode(const char *); | 8208 | static 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 |
8322 | typedef enum __rlimit_resource rlim_t; | 8212 | typedef 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 | ||
8662 | static int | 8551 | static int |
8663 | prefix(pfx, string) | 8552 | prefix(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 | ||
8803 | static int funcblocksize; /* size of structures in function */ | 8678 | static void sizenodelist (const struct nodelist *); |
8804 | static int funcstringsize; /* size of strings in node */ | 8679 | static struct nodelist *copynodelist (const struct nodelist *); |
8805 | static pointer funcblock; /* block to allocate function from */ | 8680 | static char *nodesavestr (const char *); |
8806 | static char *funcstring; /* block to allocate strings from */ | ||
8807 | |||
8808 | static 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 | |||
8838 | static void calcsize (union node *); | ||
8839 | static void sizenodelist (struct nodelist *); | ||
8840 | static union node *copynode (union node *); | ||
8841 | static struct nodelist *copynodelist (struct nodelist *); | ||
8842 | static char *nodesavestr (char *); | ||
8843 | |||
8844 | |||
8845 | |||
8846 | /* | ||
8847 | * Make a copy of a parse tree. | ||
8848 | */ | ||
8849 | |||
8850 | static union node * | ||
8851 | copyfunc(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 | ||
8865 | static void | 8682 | static void |
8866 | calcsize(n) | 8683 | calcsize(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 | |||
8946 | static void | 8760 | static void |
8947 | sizenodelist(lp) | 8761 | sizenodelist(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 | |||
8959 | static union node * | 8771 | static union node * |
8960 | copynode(n) | 8772 | copynode(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 | ||
9050 | static struct nodelist * | 8861 | static struct nodelist * |
9051 | copynodelist(lp) | 8862 | copynodelist(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 | |||
9071 | static char * | 8880 | static char * |
9072 | nodesavestr(s) | 8881 | nodesavestr(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 | ||
8960 | static inline void | ||
8961 | minus_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 | |||
9152 | static void | 8981 | static void |
9153 | options(cmdline) | 8982 | options(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 | ||
9207 | static void | ||
9208 | minus_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 | ||
9230 | static void | 9036 | static void |
9231 | setoption(int flag, int val) | 9037 | setoption(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 | ||
9549 | static int | 9354 | static int |
9550 | nextopt(optstring) | 9355 | nextopt(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 | |||
9600 | static void | ||
9601 | out1fmt(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 | */ |
11124 | static inline const char * | 10918 | static void |
11125 | getprompt(void *unused) | 10919 | setprompt(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); | |
11139 | static void | ||
11140 | setprompt(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 | */ |
10952 | static inline int | ||
10953 | noclobberopen(const char *fname) | ||
10954 | { | ||
10955 | int r, fd; | ||
10956 | struct stat finfo, finfo2; | ||
11167 | 10957 | ||
11168 | static void | 10958 | /* |
11169 | redirect(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 | |||
11012 | static inline int | ||
11013 | openhere(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 | } | ||
11042 | out: | ||
11043 | close(pip[1]); | ||
11044 | return pip[0]; | ||
11236 | } | 11045 | } |
11237 | 11046 | ||
11238 | 11047 | ||
11239 | static int | 11048 | static inline int |
11240 | openredirect(redir) | 11049 | openredirect(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 | |||
11126 | static void | ||
11127 | redirect(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 | |||
11310 | static void | 11192 | static void |
11311 | dupredirect(union node *redir, int f, char memory[10]) | 11193 | dupredirect(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 | |||
11340 | static int | ||
11341 | openhere(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 | } | ||
11371 | out: | ||
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 | */ | ||
11451 | static int | ||
11452 | noclobberopen(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 | ||
12737 | static char * | 12523 | static const char * |
12738 | lookupvar(name) | 12524 | lookupvar(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 | ||
12755 | static char * | 12541 | static const char * |
12756 | bltinlookup(name) | 12542 | bltinlookup(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 | ||
13040 | static int | 12825 | static int |
13041 | unsetvar(s) | 12826 | unsetvar(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 | ||
13076 | static struct var ** | 12860 | static struct var ** |
13077 | hashvar(p) | 12861 | hashvar(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 | ||
13096 | static int | 12879 | static int |
13097 | varequal(p, q) | 12880 | varequal(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 | */ |
13152 | static int timescmd (int argc, char **argv) | 12932 | static 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 | |||
664 | struct 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 | |||
673 | static struct tblentry *cmdtable[CMDTABLESIZE]; | ||
674 | static int builtinloc = -1; /* index in path of %builtin, or -1 */ | ||
675 | static int exerrno = 0; /* Last exec error */ | ||
676 | |||
677 | |||
678 | static void tryexec (char *, char **, char **); | ||
679 | static void printentry (struct tblentry *, int); | ||
680 | static void clearcmdentry (int); | ||
681 | static struct tblentry *cmdlookup (const char *, int); | ||
682 | static void delete_cmd_entry (void); | ||
683 | static int path_change (const char *, int *); | ||
684 | |||
685 | |||
665 | static void flushall (void); | 686 | static void flushall (void); |
666 | static void out2fmt (const char *, ...) | 687 | static void out2fmt (const char *, ...) |
667 | __attribute__((__format__(__printf__,1,2))); | 688 | __attribute__((__format__(__printf__,1,2))); |
668 | static void out1fmt (const char *, ...) | ||
669 | __attribute__((__format__(__printf__,1,2))); | ||
670 | static int xwrite (int, const char *, int); | 689 | static int xwrite (int, const char *, int); |
671 | 690 | ||
672 | static void outstr (const char *p, FILE *file) { fputs(p, file); } | 691 | static void outstr (const char *p, FILE *file) { fputs(p, file); } |
673 | static void out1str(const char *p) { outstr(p, stdout); } | 692 | static void out1str(const char *p) { outstr(p, stdout); } |
674 | static void out2str(const char *p) { outstr(p, stderr); } | 693 | static 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 | ||
698 | static 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 */ |
679 | static const char basesyntax[257] = { | 702 | static 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) |
1198 | static char *_rmescapes (char *, int); | 1221 | static char *_rmescapes (char *, int); |
1199 | #else | 1222 | #else |
@@ -1316,8 +1339,8 @@ static void initvar (void); | |||
1316 | static void setvar (const char *, const char *, int); | 1339 | static void setvar (const char *, const char *, int); |
1317 | static void setvareq (char *, int); | 1340 | static void setvareq (char *, int); |
1318 | static void listsetvar (struct strlist *); | 1341 | static void listsetvar (struct strlist *); |
1319 | static char *lookupvar (const char *); | 1342 | static const char *lookupvar (const char *); |
1320 | static char *bltinlookup (const char *); | 1343 | static const char *bltinlookup (const char *); |
1321 | static char **environment (void); | 1344 | static char **environment (void); |
1322 | static int showvarscmd (int, char **); | 1345 | static int showvarscmd (int, char **); |
1323 | static void mklocal (char *); | 1346 | static 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 |
1628 | static int expcmd (int, char **); | 1651 | static int expcmd (int, char **); |
1629 | #endif | 1652 | #endif |
1630 | #ifdef ASH_TYPE | ||
1631 | static int typecmd (int, char **); | 1653 | static int typecmd (int, char **); |
1632 | #endif | ||
1633 | #ifdef ASH_GETOPTS | 1654 | #ifdef ASH_GETOPTS |
1634 | static int getoptscmd (int, char **); | 1655 | static 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 | ||
1639 | static int true_main (int, char **); | 1659 | static int true_main (int, char **); |
1640 | static int false_main (int, char **); | 1660 | static int false_main (int, char **); |
1641 | # endif | ||
1642 | #endif | 1661 | #endif |
1643 | 1662 | ||
1644 | static void setpwd (const char *, int); | 1663 | static void setpwd (const char *, int); |
@@ -1669,7 +1688,7 @@ struct builtincmd { | |||
1669 | * have been warned. | 1688 | * have been warned. |
1670 | */ | 1689 | */ |
1671 | static const struct builtincmd builtincmds[] = { | 1690 | static 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 |
1797 | static int intreceived; | 1808 | static int intreceived; |
1798 | 1809 | ||
1799 | static struct job *makejob (union node *, int); | 1810 | static struct job *makejob (const union node *, int); |
1800 | static int forkshell (struct job *, union node *, int); | 1811 | static int forkshell (struct job *, const union node *, int); |
1801 | static int waitforjob (struct job *); | 1812 | static int waitforjob (struct job *); |
1802 | 1813 | ||
1803 | static int docd (char *, int); | 1814 | static 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 | ||
2222 | struct errname { | 2233 | struct 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 */ | |||
2337 | static int funcnest; /* depth of function calls */ | 2348 | static int funcnest; /* depth of function calls */ |
2338 | 2349 | ||
2339 | 2350 | ||
2340 | |||
2341 | static struct strlist *cmdenviron; /* environment for builtin command */ | 2351 | static struct strlist *cmdenviron; /* environment for builtin command */ |
2342 | static int exitstatus; /* exit status of last command */ | 2352 | static int exitstatus; /* exit status of last command */ |
2343 | static int oexitstatus; /* saved exit status */ | 2353 | static int oexitstatus; /* saved exit status */ |
2344 | 2354 | ||
2345 | 2355 | static void evalsubshell (const union node *, int); | |
2346 | static void evalloop (union node *, int); | ||
2347 | static void evalfor (union node *, int); | ||
2348 | static void evalcase (union node *, int); | ||
2349 | static void evalsubshell (union node *, int); | ||
2350 | static void expredir (union node *); | 2356 | static void expredir (union node *); |
2351 | static void evalpipe (union node *); | ||
2352 | static void evalcommand (union node *, int); | ||
2353 | static void prehash (union node *); | 2357 | static void prehash (union node *); |
2354 | static void eprintlist (struct strlist *); | 2358 | static 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 | ||
2426 | static struct builtincmd *find_builtin (const char *); | ||
2427 | static void expandarg (union node *, struct arglist *, int); | ||
2428 | static void calcsize (const union node *); | ||
2429 | static union node *copynode (const union node *); | ||
2430 | |||
2431 | /* | ||
2432 | * Make a copy of a parse tree. | ||
2433 | */ | ||
2434 | |||
2435 | static int funcblocksize; /* size of structures in function */ | ||
2436 | static int funcstringsize; /* size of strings in node */ | ||
2437 | static pointer funcblock; /* block to allocate function from */ | ||
2438 | static char *funcstring; /* block to allocate strings from */ | ||
2439 | |||
2440 | |||
2441 | static inline union node * | ||
2442 | copyfunc(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 | */ |
2426 | static struct builtincmd *find_builtin (const char *); | ||
2427 | static void defun (char *, union node *); | ||
2428 | 2457 | ||
2429 | static void | 2458 | static void |
2430 | evaltree(n, flags) | 2459 | freefunc(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; | 2471 | static inline void |
2519 | break; | 2472 | addcmdentry(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 | } |
2526 | out: | 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 | 2486 | static inline void | |
2537 | static void | 2487 | evalloop(const union node *n, int flags) |
2538 | evalloop(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 | ||
2573 | static void expandarg (union node *, struct arglist *, int); | ||
2574 | static void fixredir(union node *n, const char *text, int err); | ||
2575 | |||
2576 | static void | 2520 | static void |
2577 | evalfor(n, flags) | 2521 | evalfor(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 | 2558 | static inline void | |
2617 | static void | 2559 | evalcase(const union node *n, int flags) |
2618 | evalcase(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 | |||
2649 | static void | ||
2650 | evalsubshell(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 | |||
2677 | static void | ||
2678 | expredir(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 | ||
2714 | static void | 2591 | static inline void |
2715 | evalpipe(n) | 2592 | evalpipe(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 | |||
2785 | static void | ||
2786 | evalbackcmd(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; | ||
2819 | out: | ||
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 | |||
2831 | static void find_command (const char *, struct cmdentry *, int, const char *); | 2653 | static void find_command (const char *, struct cmdentry *, int, const char *); |
2832 | 2654 | ||
2833 | static int | 2655 | static int |
@@ -2841,6 +2663,7 @@ isassignment(const char *word) { | |||
2841 | return *word == '='; | 2663 | return *word == '='; |
2842 | } | 2664 | } |
2843 | 2665 | ||
2666 | |||
2844 | static void | 2667 | static void |
2845 | evalcommand(union node *cmd, int flags) | 2668 | evalcommand(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 | */ | ||
2974 | static void | ||
2975 | evaltree(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 | } | ||
3074 | out: | ||
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 | |||
3088 | static void | ||
3089 | evalsubshell(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 | |||
3113 | static void fixredir(union node *n, const char *text, int err); | ||
3114 | |||
3115 | static void | ||
3116 | expredir(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 | |||
3152 | static void | ||
3153 | evalbackcmd(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; | ||
3186 | out: | ||
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 | ||
3248 | static int | 3294 | static int |
3249 | false_main(argc, argv) | 3295 | false_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 | |||
3342 | struct 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 | |||
3351 | static struct tblentry *cmdtable[CMDTABLESIZE]; | ||
3352 | static int builtinloc = -1; /* index in path of %builtin, or -1 */ | ||
3353 | static int exerrno = 0; /* Last exec error */ | ||
3354 | |||
3355 | |||
3356 | static void tryexec (char *, char **, char **); | ||
3357 | static void printentry (struct tblentry *, int); | ||
3358 | static void clearcmdentry (int); | ||
3359 | static struct tblentry *cmdlookup (const char *, int); | ||
3360 | static void delete_cmd_entry (void); | ||
3361 | #ifdef ASH_TYPE | ||
3362 | static int describe_command (char *, int); | ||
3363 | #endif | ||
3364 | static 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 | ||
3493 | static int preadbuffer(void); | 3501 | static int preadbuffer(void); |
3494 | static void pushfile (void); | 3502 | static void pushfile (void); |
3495 | static 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 | ||
3634 | static void | 3641 | static void |
3635 | tryexec(cmd, argv, envp) | 3642 | tryexec(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 | */ | ||
3728 | static int | ||
3729 | pstrcmp(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 | |||
3738 | static const char *const * | ||
3739 | findkwd(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 | |||
3776 | static void | 3819 | static void |
3777 | printentry(cmdp, verbose) | 3820 | printentry(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) | |||
3817 | static int helpcmd(int argc, char** argv) | 3863 | static 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 | |||
4145 | static void | ||
4146 | freefunc(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 | ||
4246 | static void | ||
4247 | addcmdentry(char *name, struct cmdentry *entry) | ||
4248 | { | ||
4249 | struct tblentry *cmdp; | ||
4250 | 4268 | ||
4251 | INTOFF; | 4269 | static 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)), | |
4266 | static union node *copyfunc(union node *); | 4284 | ALIGN(sizeof (struct narg)), |
4267 | 4285 | ALIGN(sizeof (struct narg)), | |
4268 | static void | 4286 | ALIGN(sizeof (struct nfile)), |
4269 | defun(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 | */ | ||
4297 | static int | ||
4298 | pstrcmp(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 | |||
4307 | static const char *const * | ||
4308 | findkwd(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 | ||
4319 | static int | 4320 | static int |
4320 | typecmd(argc, argv) | 4321 | typecmd(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 | ||
4333 | static int | ||
4334 | describe_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 | |||
4423 | out: | ||
4424 | putchar('\n'); | ||
4425 | return 0; | ||
4426 | } | ||
4427 | #endif | ||
4428 | |||
4429 | #ifdef ASH_CMDCMD | 4338 | #ifdef ASH_CMDCMD |
4430 | static int | 4339 | static int |
4431 | commandcmd(argc, argv) | 4340 | commandcmd(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); | |||
4541 | static char *exptilde (char *, int); | 4449 | static char *exptilde (char *, int); |
4542 | static void expbackq (union node *, int, int); | 4450 | static void expbackq (union node *, int, int); |
4543 | static int subevalvar (char *, char *, int, int, int, int, int); | 4451 | static int subevalvar (char *, char *, int, int, int, int, int); |
4544 | static char *evalvar (char *, int); | ||
4545 | static int varisset (char *, int); | 4452 | static int varisset (char *, int); |
4546 | static void strtodest (const char *, const char *, int); | 4453 | static void strtodest (const char *, const char *, int); |
4547 | static void varvalue (char *, int, int); | 4454 | static void varvalue (char *, int, int); |
@@ -4550,21 +4457,21 @@ static void removerecordregions (int); | |||
4550 | static void ifsbreakup (char *, struct arglist *); | 4457 | static void ifsbreakup (char *, struct arglist *); |
4551 | static void ifsfree (void); | 4458 | static void ifsfree (void); |
4552 | static void expandmeta (struct strlist *, int); | 4459 | static 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) |
4556 | static void addglob (const glob_t *); | 4463 | static 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)) |
4560 | static void expmeta (char *, char *); | 4467 | static 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)) |
4563 | static struct strlist *expsort (struct strlist *); | 4470 | static struct strlist *expsort (struct strlist *); |
4564 | static struct strlist *msort (struct strlist *, int); | 4471 | static struct strlist *msort (struct strlist *, int); |
4565 | #endif | 4472 | #endif |
4566 | #if defined(__GLIBC__) && !defined(FNMATCH_BROKEN) | ||
4567 | static int patmatch (char *, char *, int); | 4473 | static int patmatch (char *, char *, int); |
4474 | #if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) | ||
4568 | static int patmatch2 (char *, char *, int); | 4475 | static int patmatch2 (char *, char *, int); |
4569 | #else | 4476 | #else |
4570 | static int pmatch (char *, char *, int); | 4477 | static 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 */ |
4580 | static void | 4487 | static inline void |
4581 | expandhere(union node *arg, int fd) | 4488 | expandhere(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 | |||
4553 | static inline char * | ||
4554 | evalvar(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; | ||
4578 | again: /* 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; | ||
4629 | record: | ||
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 | |||
5098 | static char * | ||
5099 | evalvar(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; | ||
5123 | again: /* 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; | ||
5174 | record: | ||
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) |
5546 | static void | 5453 | static void |
5547 | expandmeta(str, flag) | 5454 | expandmeta(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 */ |
5862 | static int | 5769 | static int |
5863 | patmatch(char *pattern, char *string, int squoted) | 5770 | patmatch(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) |
6019 | static char * | 5926 | static 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 | ||
6138 | static int whichprompt; /* 1 == PS1, 2 == PS2 */ | ||
6139 | |||
6140 | |||
6141 | struct redirtab { | 6041 | struct 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 | ||
6146 | static struct redirtab *redirlist; | 6047 | static 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 | ||
6276 | static char * | 6177 | static inline char * |
6277 | pfgets(char *line, int len) | 6178 | pfgets(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 | ||
6298 | static int | 6199 | static inline int |
6299 | preadfd(void) | 6200 | preadfd(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 | ||
6489 | static void | 6388 | static void |
6490 | setinputstring(string) | 6389 | setinputstring(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 *); | |||
6528 | static void freejob (struct job *); | 6426 | static void freejob (struct job *); |
6529 | static struct job *getjob (const char *); | 6427 | static struct job *getjob (const char *); |
6530 | static int dowait (int, struct job *); | 6428 | static int dowait (int, struct job *); |
6531 | static int waitproc (int, int *); | ||
6532 | static void waitonint(int); | 6429 | static 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 | ||
6548 | static int openredirect (union node *); | 6445 | static void dupredirect (const union node *, int, int fd1dup); |
6549 | static void dupredirect (union node *, int, char[10 ]); | ||
6550 | static int openhere (union node *); | ||
6551 | static 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 | ||
6948 | static void | 6842 | static void |
6949 | freejob(jp) | 6843 | freejob(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 | ||
7086 | static struct job * | 6979 | static struct job * |
7087 | makejob(node, nprocs) | 6980 | makejob(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 | ||
7154 | static int | 7045 | static int |
7155 | forkshell(struct job *jp, union node *n, int mode) | 7046 | forkshell(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 | ||
7277 | static int | 7172 | static int |
7278 | waitforjob(jp) | 7173 | waitforjob(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 | |||
7279 | static inline int | ||
7280 | waitproc(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 | |||
7361 | static int | 7294 | static int |
7362 | dowait(block, job) | 7295 | dowait(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 | |||
7478 | static int | ||
7479 | waitproc(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 | ||
7780 | static void read_profile (const char *); | 7671 | static void read_profile (const char *); |
7781 | static char *find_dot_file (char *); | ||
7782 | static void cmdloop (int); | 7672 | static void cmdloop (int); |
7783 | static void options (int); | 7673 | static void options (int); |
7784 | static void minus_o (char *, int); | ||
7785 | static void setoption (int, int); | 7674 | static void setoption (int, int); |
7786 | static void procargs (int, char **); | 7675 | static 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 | ||
8048 | static char * | 7936 | static inline char * |
8049 | find_dot_file(mybasename) | 7937 | find_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 | |||
8117 | static pointer | 8006 | static pointer |
8118 | stalloc(int nbytes) | 8007 | stalloc(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__ |
8318 | static mode_t getmode(const void *, mode_t); | 8207 | static mode_t getmode(const void *, mode_t); |
8319 | static void *setmode(const char *); | 8208 | static 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 |
8322 | typedef enum __rlimit_resource rlim_t; | 8212 | typedef 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 | ||
8662 | static int | 8551 | static int |
8663 | prefix(pfx, string) | 8552 | prefix(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 | ||
8803 | static int funcblocksize; /* size of structures in function */ | 8678 | static void sizenodelist (const struct nodelist *); |
8804 | static int funcstringsize; /* size of strings in node */ | 8679 | static struct nodelist *copynodelist (const struct nodelist *); |
8805 | static pointer funcblock; /* block to allocate function from */ | 8680 | static char *nodesavestr (const char *); |
8806 | static char *funcstring; /* block to allocate strings from */ | ||
8807 | |||
8808 | static 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 | |||
8838 | static void calcsize (union node *); | ||
8839 | static void sizenodelist (struct nodelist *); | ||
8840 | static union node *copynode (union node *); | ||
8841 | static struct nodelist *copynodelist (struct nodelist *); | ||
8842 | static char *nodesavestr (char *); | ||
8843 | |||
8844 | |||
8845 | |||
8846 | /* | ||
8847 | * Make a copy of a parse tree. | ||
8848 | */ | ||
8849 | |||
8850 | static union node * | ||
8851 | copyfunc(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 | ||
8865 | static void | 8682 | static void |
8866 | calcsize(n) | 8683 | calcsize(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 | |||
8946 | static void | 8760 | static void |
8947 | sizenodelist(lp) | 8761 | sizenodelist(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 | |||
8959 | static union node * | 8771 | static union node * |
8960 | copynode(n) | 8772 | copynode(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 | ||
9050 | static struct nodelist * | 8861 | static struct nodelist * |
9051 | copynodelist(lp) | 8862 | copynodelist(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 | |||
9071 | static char * | 8880 | static char * |
9072 | nodesavestr(s) | 8881 | nodesavestr(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 | ||
8960 | static inline void | ||
8961 | minus_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 | |||
9152 | static void | 8981 | static void |
9153 | options(cmdline) | 8982 | options(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 | ||
9207 | static void | ||
9208 | minus_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 | ||
9230 | static void | 9036 | static void |
9231 | setoption(int flag, int val) | 9037 | setoption(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 | ||
9549 | static int | 9354 | static int |
9550 | nextopt(optstring) | 9355 | nextopt(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 | |||
9600 | static void | ||
9601 | out1fmt(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 | */ |
11124 | static inline const char * | 10918 | static void |
11125 | getprompt(void *unused) | 10919 | setprompt(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); | |
11139 | static void | ||
11140 | setprompt(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 | */ |
10952 | static inline int | ||
10953 | noclobberopen(const char *fname) | ||
10954 | { | ||
10955 | int r, fd; | ||
10956 | struct stat finfo, finfo2; | ||
11167 | 10957 | ||
11168 | static void | 10958 | /* |
11169 | redirect(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 | |||
11012 | static inline int | ||
11013 | openhere(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 | } | ||
11042 | out: | ||
11043 | close(pip[1]); | ||
11044 | return pip[0]; | ||
11236 | } | 11045 | } |
11237 | 11046 | ||
11238 | 11047 | ||
11239 | static int | 11048 | static inline int |
11240 | openredirect(redir) | 11049 | openredirect(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 | |||
11126 | static void | ||
11127 | redirect(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 | |||
11310 | static void | 11192 | static void |
11311 | dupredirect(union node *redir, int f, char memory[10]) | 11193 | dupredirect(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 | |||
11340 | static int | ||
11341 | openhere(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 | } | ||
11371 | out: | ||
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 | */ | ||
11451 | static int | ||
11452 | noclobberopen(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 | ||
12737 | static char * | 12523 | static const char * |
12738 | lookupvar(name) | 12524 | lookupvar(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 | ||
12755 | static char * | 12541 | static const char * |
12756 | bltinlookup(name) | 12542 | bltinlookup(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 | ||
13040 | static int | 12825 | static int |
13041 | unsetvar(s) | 12826 | unsetvar(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 | ||
13076 | static struct var ** | 12860 | static struct var ** |
13077 | hashvar(p) | 12861 | hashvar(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 | ||
13096 | static int | 12879 | static int |
13097 | varequal(p, q) | 12880 | varequal(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 | */ |
13152 | static int timescmd (int argc, char **argv) | 12932 | static int timescmd (int argc, char **argv) |
13153 | { | 12933 | { |