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 /shell | |
| parent | 5a4a46a2519af1e79d931a856ee1a3b70e60d168 (diff) | |
| download | busybox-w32-6248355c6f64cf2828ec0080930d3926e38d4c97.tar.gz busybox-w32-6248355c6f64cf2828ec0080930d3926e38d4c97.tar.bz2 busybox-w32-6248355c6f64cf2828ec0080930d3926e38d4c97.zip | |
vodz' latest update to ash.c
Diffstat (limited to 'shell')
| -rw-r--r-- | shell/ash.c | 2104 |
1 files changed, 942 insertions, 1162 deletions
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 | { |
