aboutsummaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
authorvda <vda@69ca8d6d-28ef-0310-b511-8ec308f3f277>2007-02-23 21:08:58 +0000
committervda <vda@69ca8d6d-28ef-0310-b511-8ec308f3f277>2007-02-23 21:08:58 +0000
commit96dd882fef3ec81174c00f2ec05267cbe67a144c (patch)
treecd4e3fa13064adaee22081ba312266b31bc4fa95 /shell
parenta02e9ff74128cf5dc6bcba7142687e6c94447670 (diff)
downloadbusybox-w32-96dd882fef3ec81174c00f2ec05267cbe67a144c.tar.gz
busybox-w32-96dd882fef3ec81174c00f2ec05267cbe67a144c.tar.bz2
busybox-w32-96dd882fef3ec81174c00f2ec05267cbe67a144c.zip
ash: starting second round of cleanups. #1
git-svn-id: svn://busybox.net/trunk/busybox@17963 69ca8d6d-28ef-0310-b511-8ec308f3f277
Diffstat (limited to 'shell')
-rw-r--r--shell/ash.c2676
1 files changed, 1327 insertions, 1349 deletions
diff --git a/shell/ash.c b/shell/ash.c
index 0e039322b..664a6fa16 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -408,6 +408,39 @@ out2str(const char *p)
408 408
409/* ============ Parsing structures */ 409/* ============ Parsing structures */
410 410
411/* control characters in argument strings */
412#define CTLESC '\201' /* escape next character */
413#define CTLVAR '\202' /* variable defn */
414#define CTLENDVAR '\203'
415#define CTLBACKQ '\204'
416#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
417/* CTLBACKQ | CTLQUOTE == '\205' */
418#define CTLARI '\206' /* arithmetic expression */
419#define CTLENDARI '\207'
420#define CTLQUOTEMARK '\210'
421
422/* variable substitution byte (follows CTLVAR) */
423#define VSTYPE 0x0f /* type of variable substitution */
424#define VSNUL 0x10 /* colon--treat the empty string as unset */
425#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
426
427/* values of VSTYPE field */
428#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
429#define VSMINUS 0x2 /* ${var-text} */
430#define VSPLUS 0x3 /* ${var+text} */
431#define VSQUESTION 0x4 /* ${var?message} */
432#define VSASSIGN 0x5 /* ${var=text} */
433#define VSTRIMRIGHT 0x6 /* ${var%pattern} */
434#define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
435#define VSTRIMLEFT 0x8 /* ${var#pattern} */
436#define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
437#define VSLENGTH 0xa /* ${#var} */
438
439/* values of checkkwd variable */
440#define CHKALIAS 0x1
441#define CHKKWD 0x2
442#define CHKNL 0x4
443
411#define NCMD 0 444#define NCMD 0
412#define NPIPE 1 445#define NPIPE 1
413#define NREDIR 2 446#define NREDIR 2
@@ -551,6 +584,16 @@ struct funcnode {
551 union node n; 584 union node n;
552}; 585};
553 586
587/*
588 * Free a parse tree.
589 */
590static void
591freefunc(struct funcnode *f)
592{
593 if (f && --f->count < 0)
594 free(f);
595}
596
554 597
555/* ============ Debugging output */ 598/* ============ Debugging output */
556 599
@@ -886,11 +929,11 @@ showtree(union node *n)
886#endif /* DEBUG */ 929#endif /* DEBUG */
887 930
888 931
889/* ============ Parser data 932/* ============ Parser data */
890 * 933
934/*
891 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up. 935 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
892 */ 936 */
893
894struct strlist { 937struct strlist {
895 struct strlist *next; 938 struct strlist *next;
896 char *text; 939 char *text;
@@ -1431,7 +1474,7 @@ single_quote(const char *s)
1431} 1474}
1432 1475
1433 1476
1434/* ============ ... */ 1477/* ============ nextopt */
1435 1478
1436static char **argptr; /* argument list for builtin commands */ 1479static char **argptr; /* argument list for builtin commands */
1437static char *optionarg; /* set by nextopt (like getopt) */ 1480static char *optionarg; /* set by nextopt (like getopt) */
@@ -2348,47 +2391,7 @@ pwdcmd(int argc, char **argv)
2348} 2391}
2349 2392
2350 2393
2351/* ============ Unsorted yet */ 2394/* ============ ... */
2352
2353
2354/* parser.h */
2355
2356/* control characters in argument strings */
2357#define CTL_FIRST '\201' /* first 'special' character */
2358#define CTLESC '\201' /* escape next character */
2359#define CTLVAR '\202' /* variable defn */
2360#define CTLENDVAR '\203'
2361#define CTLBACKQ '\204'
2362#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
2363/* CTLBACKQ | CTLQUOTE == '\205' */
2364#define CTLARI '\206' /* arithmetic expression */
2365#define CTLENDARI '\207'
2366#define CTLQUOTEMARK '\210'
2367#define CTL_LAST '\210' /* last 'special' character */
2368
2369/* variable substitution byte (follows CTLVAR) */
2370#define VSTYPE 0x0f /* type of variable substitution */
2371#define VSNUL 0x10 /* colon--treat the empty string as unset */
2372#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
2373
2374/* values of VSTYPE field */
2375#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
2376#define VSMINUS 0x2 /* ${var-text} */
2377#define VSPLUS 0x3 /* ${var+text} */
2378#define VSQUESTION 0x4 /* ${var?message} */
2379#define VSASSIGN 0x5 /* ${var=text} */
2380#define VSTRIMRIGHT 0x6 /* ${var%pattern} */
2381#define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
2382#define VSTRIMLEFT 0x8 /* ${var#pattern} */
2383#define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
2384#define VSLENGTH 0xa /* ${#var} */
2385
2386/* values of checkkwd variable */
2387#define CHKALIAS 0x1
2388#define CHKKWD 0x2
2389#define CHKNL 0x4
2390
2391#define IBUFSIZ (BUFSIZ + 1)
2392 2395
2393/* 2396/*
2394 * NEOF is returned by parsecmd when it encounters an end of file. It 2397 * NEOF is returned by parsecmd when it encounters an end of file. It
@@ -2404,6 +2407,7 @@ static int parselleft; /* copy of parsefile->lleft */
2404/* next character in input buffer */ 2407/* next character in input buffer */
2405static char *parsenextc; /* copy of parsefile->nextc */ 2408static char *parsenextc; /* copy of parsefile->nextc */
2406 2409
2410#define IBUFSIZ (BUFSIZ + 1)
2407#define basebuf bb_common_bufsiz1 /* buffer for top level input file */ 2411#define basebuf bb_common_bufsiz1 /* buffer for top level input file */
2408 2412
2409static int tokpushback; /* last token pushed back */ 2413static int tokpushback; /* last token pushed back */
@@ -2431,98 +2435,6 @@ static const char dolatstr[] = { CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' };
2431 2435
2432#define xlikely(x) __builtin_expect((x),1) 2436#define xlikely(x) __builtin_expect((x),1)
2433 2437
2434#define TEOF 0
2435#define TNL 1
2436#define TREDIR 2
2437#define TWORD 3
2438#define TSEMI 4
2439#define TBACKGND 5
2440#define TAND 6
2441#define TOR 7
2442#define TPIPE 8
2443#define TLP 9
2444#define TRP 10
2445#define TENDCASE 11
2446#define TENDBQUOTE 12
2447#define TNOT 13
2448#define TCASE 14
2449#define TDO 15
2450#define TDONE 16
2451#define TELIF 17
2452#define TELSE 18
2453#define TESAC 19
2454#define TFI 20
2455#define TFOR 21
2456#define TIF 22
2457#define TIN 23
2458#define TTHEN 24
2459#define TUNTIL 25
2460#define TWHILE 26
2461#define TBEGIN 27
2462#define TEND 28
2463
2464/* first char is indicating which tokens mark the end of a list */
2465static const char *const tokname_array[] = {
2466 "\1end of file",
2467 "\0newline",
2468 "\0redirection",
2469 "\0word",
2470 "\0;",
2471 "\0&",
2472 "\0&&",
2473 "\0||",
2474 "\0|",
2475 "\0(",
2476 "\1)",
2477 "\1;;",
2478 "\1`",
2479#define KWDOFFSET 13
2480 /* the following are keywords */
2481 "\0!",
2482 "\0case",
2483 "\1do",
2484 "\1done",
2485 "\1elif",
2486 "\1else",
2487 "\1esac",
2488 "\1fi",
2489 "\0for",
2490 "\0if",
2491 "\0in",
2492 "\1then",
2493 "\0until",
2494 "\0while",
2495 "\0{",
2496 "\1}",
2497};
2498
2499static const char *
2500tokname(int tok)
2501{
2502 static char buf[16];
2503
2504 if (tok >= TSEMI)
2505 buf[0] = '"';
2506 sprintf(buf + (tok >= TSEMI), "%s%c",
2507 tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0));
2508 return buf;
2509}
2510
2511/* Wrapper around strcmp for qsort/bsearch/... */
2512static int
2513pstrcmp(const void *a, const void *b)
2514{
2515 return strcmp((const char *) a, (*(const char *const *) b) + 1);
2516}
2517
2518static const char *const *
2519findkwd(const char *s)
2520{
2521 return bsearch(s, tokname_array + KWDOFFSET,
2522 (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
2523 sizeof(const char *), pstrcmp);
2524}
2525
2526/* Syntax classes */ 2438/* Syntax classes */
2527#define CWORD 0 /* character is nothing special */ 2439#define CWORD 0 /* character is nothing special */
2528#define CNL 1 /* newline character */ 2440#define CNL 1 /* newline character */
@@ -2966,99 +2878,8 @@ static const char syntax_index_table[258] = {
2966#endif /* USE_SIT_FUNCTION */ 2878#endif /* USE_SIT_FUNCTION */
2967 2879
2968 2880
2969/* alias.c */
2970
2971#define ATABSIZE 39
2972
2973static int funcblocksize; /* size of structures in function */
2974static int funcstringsize; /* size of strings in node */
2975static void *funcblock; /* block to allocate function from */
2976static char *funcstring; /* block to allocate strings from */
2977
2978static const short nodesize[26] = {
2979 SHELL_ALIGN(sizeof(struct ncmd)),
2980 SHELL_ALIGN(sizeof(struct npipe)),
2981 SHELL_ALIGN(sizeof(struct nredir)),
2982 SHELL_ALIGN(sizeof(struct nredir)),
2983 SHELL_ALIGN(sizeof(struct nredir)),
2984 SHELL_ALIGN(sizeof(struct nbinary)),
2985 SHELL_ALIGN(sizeof(struct nbinary)),
2986 SHELL_ALIGN(sizeof(struct nbinary)),
2987 SHELL_ALIGN(sizeof(struct nif)),
2988 SHELL_ALIGN(sizeof(struct nbinary)),
2989 SHELL_ALIGN(sizeof(struct nbinary)),
2990 SHELL_ALIGN(sizeof(struct nfor)),
2991 SHELL_ALIGN(sizeof(struct ncase)),
2992 SHELL_ALIGN(sizeof(struct nclist)),
2993 SHELL_ALIGN(sizeof(struct narg)),
2994 SHELL_ALIGN(sizeof(struct narg)),
2995 SHELL_ALIGN(sizeof(struct nfile)),
2996 SHELL_ALIGN(sizeof(struct nfile)),
2997 SHELL_ALIGN(sizeof(struct nfile)),
2998 SHELL_ALIGN(sizeof(struct nfile)),
2999 SHELL_ALIGN(sizeof(struct nfile)),
3000 SHELL_ALIGN(sizeof(struct ndup)),
3001 SHELL_ALIGN(sizeof(struct ndup)),
3002 SHELL_ALIGN(sizeof(struct nhere)),
3003 SHELL_ALIGN(sizeof(struct nhere)),
3004 SHELL_ALIGN(sizeof(struct nnot)),
3005};
3006
3007static void calcsize(union node *);
3008static void sizenodelist(struct nodelist *);
3009static union node *copynode(union node *);
3010static struct nodelist *copynodelist(struct nodelist *);
3011static char *nodeckstrdup(char *);
3012
3013static int evalskip; /* set if we are skipping commands */
3014static int skipcount; /* number of levels to skip */
3015static int funcnest; /* depth of function calls */
3016
3017/* reasons for skipping commands (see comment on breakcmd routine) */
3018#define SKIPBREAK (1 << 0)
3019#define SKIPCONT (1 << 1)
3020#define SKIPFUNC (1 << 2)
3021#define SKIPFILE (1 << 3)
3022#define SKIPEVAL (1 << 4)
3023
3024
3025/* exec.h */ 2881/* exec.h */
3026 2882
3027/* values of cmdtype */
3028#define CMDUNKNOWN -1 /* no entry in table for command */
3029#define CMDNORMAL 0 /* command is an executable program */
3030#define CMDFUNCTION 1 /* command is a shell function */
3031#define CMDBUILTIN 2 /* command is a shell builtin */
3032
3033struct builtincmd {
3034 const char *name;
3035 int (*builtin)(int, char **);
3036 /* unsigned flags; */
3037};
3038
3039struct cmdentry {
3040 int cmdtype;
3041 union param {
3042 int index;
3043 const struct builtincmd *cmd;
3044 struct funcnode *func;
3045 } u;
3046};
3047
3048/* action to find_command() */
3049#define DO_ERR 0x01 /* prints errors */
3050#define DO_ABS 0x02 /* checks absolute paths */
3051#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
3052#define DO_ALTPATH 0x08 /* using alternate path */
3053#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
3054
3055static void shellexec(char **, const char *, int) ATTRIBUTE_NORETURN;
3056static char *padvance(const char **, const char *);
3057static void find_command(char *, struct cmdentry *, int, const char *);
3058static struct builtincmd *find_builtin(const char *);
3059static void defun(char *, union node *);
3060static void unsetfunc(const char *);
3061
3062#if ENABLE_ASH_MATH_SUPPORT_64 2883#if ENABLE_ASH_MATH_SUPPORT_64
3063typedef int64_t arith_t; 2884typedef int64_t arith_t;
3064#define arith_t_type long long 2885#define arith_t_type long long
@@ -3222,6 +3043,8 @@ static int is_safe_applet(char *name)
3222#define ALIASINUSE 1 3043#define ALIASINUSE 1
3223#define ALIASDEAD 2 3044#define ALIASDEAD 2
3224 3045
3046#define ATABSIZE 39
3047
3225struct alias { 3048struct alias {
3226 struct alias *next; 3049 struct alias *next;
3227 char *name; 3050 char *name;
@@ -4899,13 +4722,937 @@ casematch(union node *pattern, char *val)
4899} 4722}
4900 4723
4901 4724
4725/* ============ find_command */
4726
4727struct builtincmd {
4728 const char *name;
4729 int (*builtin)(int, char **);
4730 /* unsigned flags; */
4731};
4732#define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
4733#define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
4734#define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
4735
4736struct cmdentry {
4737 int cmdtype;
4738 union param {
4739 int index;
4740 const struct builtincmd *cmd;
4741 struct funcnode *func;
4742 } u;
4743};
4744/* values of cmdtype */
4745#define CMDUNKNOWN -1 /* no entry in table for command */
4746#define CMDNORMAL 0 /* command is an executable program */
4747#define CMDFUNCTION 1 /* command is a shell function */
4748#define CMDBUILTIN 2 /* command is a shell builtin */
4749
4750/* action to find_command() */
4751#define DO_ERR 0x01 /* prints errors */
4752#define DO_ABS 0x02 /* checks absolute paths */
4753#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
4754#define DO_ALTPATH 0x08 /* using alternate path */
4755#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
4756
4757static void find_command(char *, struct cmdentry *, int, const char *);
4758
4759
4760/* ============ Hashing commands */
4761
4762/*
4763 * When commands are first encountered, they are entered in a hash table.
4764 * This ensures that a full path search will not have to be done for them
4765 * on each invocation.
4766 *
4767 * We should investigate converting to a linear search, even though that
4768 * would make the command name "hash" a misnomer.
4769 */
4770
4771#define CMDTABLESIZE 31 /* should be prime */
4772#define ARB 1 /* actual size determined at run time */
4773
4774struct tblentry {
4775 struct tblentry *next; /* next entry in hash chain */
4776 union param param; /* definition of builtin function */
4777 short cmdtype; /* index identifying command */
4778 char rehash; /* if set, cd done since entry created */
4779 char cmdname[ARB]; /* name of command */
4780};
4781
4782static struct tblentry *cmdtable[CMDTABLESIZE];
4783static int builtinloc = -1; /* index in path of %builtin, or -1 */
4784
4785static void
4786tryexec(char *cmd, char **argv, char **envp)
4787{
4788 int repeated = 0;
4789 struct BB_applet *a;
4790 int argc = 0;
4791 char **c;
4792
4793 if (strchr(cmd, '/') == NULL
4794 && (a = find_applet_by_name(cmd)) != NULL
4795 && is_safe_applet(cmd)
4796 ) {
4797 c = argv;
4798 while (*c != NULL) {
4799 c++; argc++;
4800 }
4801 applet_name = cmd;
4802 exit(a->main(argc, argv));
4803 }
4804#if ENABLE_FEATURE_SH_STANDALONE_SHELL
4805 if (find_applet_by_name(cmd) != NULL) {
4806 /* re-exec ourselves with the new arguments */
4807 execve(CONFIG_BUSYBOX_EXEC_PATH, argv, envp);
4808 /* If they called chroot or otherwise made the binary no longer
4809 * executable, fall through */
4810 }
4811#endif
4812
4813 repeat:
4814#ifdef SYSV
4815 do {
4816 execve(cmd, argv, envp);
4817 } while (errno == EINTR);
4818#else
4819 execve(cmd, argv, envp);
4820#endif
4821 if (repeated++) {
4822 free(argv);
4823 } else if (errno == ENOEXEC) {
4824 char **ap;
4825 char **new;
4826
4827 for (ap = argv; *ap; ap++)
4828 ;
4829 ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
4830 ap[1] = cmd;
4831 *ap = cmd = (char *)DEFAULT_SHELL;
4832 ap += 2;
4833 argv++;
4834 while ((*ap++ = *argv++))
4835 ;
4836 argv = new;
4837 goto repeat;
4838 }
4839}
4840
4841/*
4842 * Exec a program. Never returns. If you change this routine, you may
4843 * have to change the find_command routine as well.
4844 */
4845#define environment() listvars(VEXPORT, VUNSET, 0)
4846static void shellexec(char **, const char *, int) ATTRIBUTE_NORETURN;
4847static void
4848shellexec(char **argv, const char *path, int idx)
4849{
4850 char *cmdname;
4851 int e;
4852 char **envp;
4853 int exerrno;
4854
4855 clearredir(1);
4856 envp = environment();
4857 if (strchr(argv[0], '/') || is_safe_applet(argv[0])
4858#if ENABLE_FEATURE_SH_STANDALONE_SHELL
4859 || find_applet_by_name(argv[0])
4860#endif
4861 ) {
4862 tryexec(argv[0], argv, envp);
4863 e = errno;
4864 } else {
4865 e = ENOENT;
4866 while ((cmdname = padvance(&path, argv[0])) != NULL) {
4867 if (--idx < 0 && pathopt == NULL) {
4868 tryexec(cmdname, argv, envp);
4869 if (errno != ENOENT && errno != ENOTDIR)
4870 e = errno;
4871 }
4872 stunalloc(cmdname);
4873 }
4874 }
4875
4876 /* Map to POSIX errors */
4877 switch (e) {
4878 case EACCES:
4879 exerrno = 126;
4880 break;
4881 case ENOENT:
4882 exerrno = 127;
4883 break;
4884 default:
4885 exerrno = 2;
4886 break;
4887 }
4888 exitstatus = exerrno;
4889 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
4890 argv[0], e, suppressint ));
4891 ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found"));
4892 /* NOTREACHED */
4893}
4894
4895static void
4896printentry(struct tblentry *cmdp)
4897{
4898 int idx;
4899 const char *path;
4900 char *name;
4901
4902 idx = cmdp->param.index;
4903 path = pathval();
4904 do {
4905 name = padvance(&path, cmdp->cmdname);
4906 stunalloc(name);
4907 } while (--idx >= 0);
4908 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
4909}
4910
4911/*
4912 * Clear out command entries. The argument specifies the first entry in
4913 * PATH which has changed.
4914 */
4915static void
4916clearcmdentry(int firstchange)
4917{
4918 struct tblentry **tblp;
4919 struct tblentry **pp;
4920 struct tblentry *cmdp;
4921
4922 INT_OFF;
4923 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
4924 pp = tblp;
4925 while ((cmdp = *pp) != NULL) {
4926 if ((cmdp->cmdtype == CMDNORMAL &&
4927 cmdp->param.index >= firstchange)
4928 || (cmdp->cmdtype == CMDBUILTIN &&
4929 builtinloc >= firstchange)
4930 ) {
4931 *pp = cmdp->next;
4932 free(cmdp);
4933 } else {
4934 pp = &cmdp->next;
4935 }
4936 }
4937 }
4938 INT_ON;
4939}
4940
4941/*
4942 * Locate a command in the command hash table. If "add" is nonzero,
4943 * add the command to the table if it is not already present. The
4944 * variable "lastcmdentry" is set to point to the address of the link
4945 * pointing to the entry, so that delete_cmd_entry can delete the
4946 * entry.
4947 *
4948 * Interrupts must be off if called with add != 0.
4949 */
4950static struct tblentry **lastcmdentry;
4951
4952static struct tblentry *
4953cmdlookup(const char *name, int add)
4954{
4955 unsigned int hashval;
4956 const char *p;
4957 struct tblentry *cmdp;
4958 struct tblentry **pp;
4959
4960 p = name;
4961 hashval = (unsigned char)*p << 4;
4962 while (*p)
4963 hashval += (unsigned char)*p++;
4964 hashval &= 0x7FFF;
4965 pp = &cmdtable[hashval % CMDTABLESIZE];
4966 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
4967 if (strcmp(cmdp->cmdname, name) == 0)
4968 break;
4969 pp = &cmdp->next;
4970 }
4971 if (add && cmdp == NULL) {
4972 cmdp = *pp = ckmalloc(sizeof(struct tblentry) - ARB
4973 + strlen(name) + 1);
4974 cmdp->next = NULL;
4975 cmdp->cmdtype = CMDUNKNOWN;
4976 strcpy(cmdp->cmdname, name);
4977 }
4978 lastcmdentry = pp;
4979 return cmdp;
4980}
4981
4982/*
4983 * Delete the command entry returned on the last lookup.
4984 */
4985static void
4986delete_cmd_entry(void)
4987{
4988 struct tblentry *cmdp;
4989
4990 INT_OFF;
4991 cmdp = *lastcmdentry;
4992 *lastcmdentry = cmdp->next;
4993 if (cmdp->cmdtype == CMDFUNCTION)
4994 freefunc(cmdp->param.func);
4995 free(cmdp);
4996 INT_ON;
4997}
4998
4999/*
5000 * Add a new command entry, replacing any existing command entry for
5001 * the same name - except special builtins.
5002 */
5003static void
5004addcmdentry(char *name, struct cmdentry *entry)
5005{
5006 struct tblentry *cmdp;
5007
5008 cmdp = cmdlookup(name, 1);
5009 if (cmdp->cmdtype == CMDFUNCTION) {
5010 freefunc(cmdp->param.func);
5011 }
5012 cmdp->cmdtype = entry->cmdtype;
5013 cmdp->param = entry->u;
5014 cmdp->rehash = 0;
5015}
5016
5017static int
5018hashcmd(int argc, char **argv)
5019{
5020 struct tblentry **pp;
5021 struct tblentry *cmdp;
5022 int c;
5023 struct cmdentry entry;
5024 char *name;
5025
5026 while ((c = nextopt("r")) != '\0') {
5027 clearcmdentry(0);
5028 return 0;
5029 }
5030 if (*argptr == NULL) {
5031 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
5032 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
5033 if (cmdp->cmdtype == CMDNORMAL)
5034 printentry(cmdp);
5035 }
5036 }
5037 return 0;
5038 }
5039 c = 0;
5040 while ((name = *argptr) != NULL) {
5041 cmdp = cmdlookup(name, 0);
5042 if (cmdp != NULL
5043 && (cmdp->cmdtype == CMDNORMAL
5044 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
5045 delete_cmd_entry();
5046 find_command(name, &entry, DO_ERR, pathval());
5047 if (entry.cmdtype == CMDUNKNOWN)
5048 c = 1;
5049 argptr++;
5050 }
5051 return c;
5052}
5053
5054/*
5055 * Called when a cd is done. Marks all commands so the next time they
5056 * are executed they will be rehashed.
5057 */
5058static void
5059hashcd(void)
5060{
5061 struct tblentry **pp;
5062 struct tblentry *cmdp;
5063
5064 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
5065 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
5066 if (cmdp->cmdtype == CMDNORMAL || (
5067 cmdp->cmdtype == CMDBUILTIN &&
5068 !(IS_BUILTIN_REGULAR(cmdp->param.cmd)) &&
5069 builtinloc > 0
5070 ))
5071 cmdp->rehash = 1;
5072 }
5073 }
5074}
5075
5076/*
5077 * Fix command hash table when PATH changed.
5078 * Called before PATH is changed. The argument is the new value of PATH;
5079 * pathval() still returns the old value at this point.
5080 * Called with interrupts off.
5081 */
5082static void
5083changepath(const char *newval)
5084{
5085 const char *old, *new;
5086 int idx;
5087 int firstchange;
5088 int idx_bltin;
5089
5090 old = pathval();
5091 new = newval;
5092 firstchange = 9999; /* assume no change */
5093 idx = 0;
5094 idx_bltin = -1;
5095 for (;;) {
5096 if (*old != *new) {
5097 firstchange = idx;
5098 if ((*old == '\0' && *new == ':')
5099 || (*old == ':' && *new == '\0'))
5100 firstchange++;
5101 old = new; /* ignore subsequent differences */
5102 }
5103 if (*new == '\0')
5104 break;
5105 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
5106 idx_bltin = idx;
5107 if (*new == ':') {
5108 idx++;
5109 }
5110 new++, old++;
5111 }
5112 if (builtinloc < 0 && idx_bltin >= 0)
5113 builtinloc = idx_bltin; /* zap builtins */
5114 if (builtinloc >= 0 && idx_bltin < 0)
5115 firstchange = 0;
5116 clearcmdentry(firstchange);
5117 builtinloc = idx_bltin;
5118}
5119
5120#define TEOF 0
5121#define TNL 1
5122#define TREDIR 2
5123#define TWORD 3
5124#define TSEMI 4
5125#define TBACKGND 5
5126#define TAND 6
5127#define TOR 7
5128#define TPIPE 8
5129#define TLP 9
5130#define TRP 10
5131#define TENDCASE 11
5132#define TENDBQUOTE 12
5133#define TNOT 13
5134#define TCASE 14
5135#define TDO 15
5136#define TDONE 16
5137#define TELIF 17
5138#define TELSE 18
5139#define TESAC 19
5140#define TFI 20
5141#define TFOR 21
5142#define TIF 22
5143#define TIN 23
5144#define TTHEN 24
5145#define TUNTIL 25
5146#define TWHILE 26
5147#define TBEGIN 27
5148#define TEND 28
5149
5150/* first char is indicating which tokens mark the end of a list */
5151static const char *const tokname_array[] = {
5152 "\1end of file",
5153 "\0newline",
5154 "\0redirection",
5155 "\0word",
5156 "\0;",
5157 "\0&",
5158 "\0&&",
5159 "\0||",
5160 "\0|",
5161 "\0(",
5162 "\1)",
5163 "\1;;",
5164 "\1`",
5165#define KWDOFFSET 13
5166 /* the following are keywords */
5167 "\0!",
5168 "\0case",
5169 "\1do",
5170 "\1done",
5171 "\1elif",
5172 "\1else",
5173 "\1esac",
5174 "\1fi",
5175 "\0for",
5176 "\0if",
5177 "\0in",
5178 "\1then",
5179 "\0until",
5180 "\0while",
5181 "\0{",
5182 "\1}",
5183};
5184
5185static const char *
5186tokname(int tok)
5187{
5188 static char buf[16];
5189
5190 if (tok >= TSEMI)
5191 buf[0] = '"';
5192 sprintf(buf + (tok >= TSEMI), "%s%c",
5193 tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0));
5194 return buf;
5195}
5196
5197/* Wrapper around strcmp for qsort/bsearch/... */
5198static int
5199pstrcmp(const void *a, const void *b)
5200{
5201 return strcmp((const char *) a, (*(const char *const *) b) + 1);
5202}
5203
5204static const char *const *
5205findkwd(const char *s)
5206{
5207 return bsearch(s, tokname_array + KWDOFFSET,
5208 (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
5209 sizeof(const char *), pstrcmp);
5210}
5211
5212/*
5213 * Locate and print what a word is...
5214 */
5215#if ENABLE_ASH_CMDCMD
5216static int
5217describe_command(char *command, int describe_command_verbose)
5218#else
5219#define describe_command_verbose 1
5220static int
5221describe_command(char *command)
5222#endif
5223{
5224 struct cmdentry entry;
5225 struct tblentry *cmdp;
5226#if ENABLE_ASH_ALIAS
5227 const struct alias *ap;
5228#endif
5229 const char *path = pathval();
5230
5231 if (describe_command_verbose) {
5232 out1str(command);
5233 }
5234
5235 /* First look at the keywords */
5236 if (findkwd(command)) {
5237 out1str(describe_command_verbose ? " is a shell keyword" : command);
5238 goto out;
5239 }
5240
5241#if ENABLE_ASH_ALIAS
5242 /* Then look at the aliases */
5243 ap = lookupalias(command, 0);
5244 if (ap != NULL) {
5245 if (describe_command_verbose) {
5246 out1fmt(" is an alias for %s", ap->val);
5247 } else {
5248 out1str("alias ");
5249 printalias(ap);
5250 return 0;
5251 }
5252 goto out;
5253 }
5254#endif
5255 /* Then check if it is a tracked alias */
5256 cmdp = cmdlookup(command, 0);
5257 if (cmdp != NULL) {
5258 entry.cmdtype = cmdp->cmdtype;
5259 entry.u = cmdp->param;
5260 } else {
5261 /* Finally use brute force */
5262 find_command(command, &entry, DO_ABS, path);
5263 }
5264
5265 switch (entry.cmdtype) {
5266 case CMDNORMAL: {
5267 int j = entry.u.index;
5268 char *p;
5269 if (j == -1) {
5270 p = command;
5271 } else {
5272 do {
5273 p = padvance(&path, command);
5274 stunalloc(p);
5275 } while (--j >= 0);
5276 }
5277 if (describe_command_verbose) {
5278 out1fmt(" is%s %s",
5279 (cmdp ? " a tracked alias for" : nullstr), p
5280 );
5281 } else {
5282 out1str(p);
5283 }
5284 break;
5285 }
5286
5287 case CMDFUNCTION:
5288 if (describe_command_verbose) {
5289 out1str(" is a shell function");
5290 } else {
5291 out1str(command);
5292 }
5293 break;
5294
5295 case CMDBUILTIN:
5296 if (describe_command_verbose) {
5297 out1fmt(" is a %sshell builtin",
5298 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
5299 "special " : nullstr
5300 );
5301 } else {
5302 out1str(command);
5303 }
5304 break;
5305
5306 default:
5307 if (describe_command_verbose) {
5308 out1str(": not found\n");
5309 }
5310 return 127;
5311 }
5312 out:
5313 outstr("\n", stdout);
5314 return 0;
5315}
5316
5317static int
5318typecmd(int argc, char **argv)
5319{
5320 int i;
5321 int err = 0;
5322
5323 for (i = 1; i < argc; i++) {
5324#if ENABLE_ASH_CMDCMD
5325 err |= describe_command(argv[i], 1);
5326#else
5327 err |= describe_command(argv[i]);
5328#endif
5329 }
5330 return err;
5331}
5332
5333#if ENABLE_ASH_CMDCMD
5334static int
5335commandcmd(int argc, char **argv)
5336{
5337 int c;
5338 enum {
5339 VERIFY_BRIEF = 1,
5340 VERIFY_VERBOSE = 2,
5341 } verify = 0;
5342
5343 while ((c = nextopt("pvV")) != '\0')
5344 if (c == 'V')
5345 verify |= VERIFY_VERBOSE;
5346 else if (c == 'v')
5347 verify |= VERIFY_BRIEF;
5348#if DEBUG
5349 else if (c != 'p')
5350 abort();
5351#endif
5352 if (verify)
5353 return describe_command(*argptr, verify - VERIFY_BRIEF);
5354
5355 return 0;
5356}
5357#endif
5358
5359
4902/* ============ eval.c */ 5360/* ============ eval.c */
4903 5361
5362static int funcblocksize; /* size of structures in function */
5363static int funcstringsize; /* size of strings in node */
5364static void *funcblock; /* block to allocate function from */
5365static char *funcstring; /* block to allocate strings from */
5366
4904/* flags in argument to evaltree */ 5367/* flags in argument to evaltree */
4905#define EV_EXIT 01 /* exit after evaluating tree */ 5368#define EV_EXIT 01 /* exit after evaluating tree */
4906#define EV_TESTED 02 /* exit status is checked; ignore -e flag */ 5369#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
4907#define EV_BACKCMD 04 /* command executing within back quotes */ 5370#define EV_BACKCMD 04 /* command executing within back quotes */
4908 5371
5372static const short nodesize[26] = {
5373 SHELL_ALIGN(sizeof(struct ncmd)),
5374 SHELL_ALIGN(sizeof(struct npipe)),
5375 SHELL_ALIGN(sizeof(struct nredir)),
5376 SHELL_ALIGN(sizeof(struct nredir)),
5377 SHELL_ALIGN(sizeof(struct nredir)),
5378 SHELL_ALIGN(sizeof(struct nbinary)),
5379 SHELL_ALIGN(sizeof(struct nbinary)),
5380 SHELL_ALIGN(sizeof(struct nbinary)),
5381 SHELL_ALIGN(sizeof(struct nif)),
5382 SHELL_ALIGN(sizeof(struct nbinary)),
5383 SHELL_ALIGN(sizeof(struct nbinary)),
5384 SHELL_ALIGN(sizeof(struct nfor)),
5385 SHELL_ALIGN(sizeof(struct ncase)),
5386 SHELL_ALIGN(sizeof(struct nclist)),
5387 SHELL_ALIGN(sizeof(struct narg)),
5388 SHELL_ALIGN(sizeof(struct narg)),
5389 SHELL_ALIGN(sizeof(struct nfile)),
5390 SHELL_ALIGN(sizeof(struct nfile)),
5391 SHELL_ALIGN(sizeof(struct nfile)),
5392 SHELL_ALIGN(sizeof(struct nfile)),
5393 SHELL_ALIGN(sizeof(struct nfile)),
5394 SHELL_ALIGN(sizeof(struct ndup)),
5395 SHELL_ALIGN(sizeof(struct ndup)),
5396 SHELL_ALIGN(sizeof(struct nhere)),
5397 SHELL_ALIGN(sizeof(struct nhere)),
5398 SHELL_ALIGN(sizeof(struct nnot)),
5399};
5400
5401static void calcsize(union node *n);
5402
5403static void
5404sizenodelist(struct nodelist *lp)
5405{
5406 while (lp) {
5407 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
5408 calcsize(lp->n);
5409 lp = lp->next;
5410 }
5411}
5412
5413static void
5414calcsize(union node *n)
5415{
5416 if (n == NULL)
5417 return;
5418 funcblocksize += nodesize[n->type];
5419 switch (n->type) {
5420 case NCMD:
5421 calcsize(n->ncmd.redirect);
5422 calcsize(n->ncmd.args);
5423 calcsize(n->ncmd.assign);
5424 break;
5425 case NPIPE:
5426 sizenodelist(n->npipe.cmdlist);
5427 break;
5428 case NREDIR:
5429 case NBACKGND:
5430 case NSUBSHELL:
5431 calcsize(n->nredir.redirect);
5432 calcsize(n->nredir.n);
5433 break;
5434 case NAND:
5435 case NOR:
5436 case NSEMI:
5437 case NWHILE:
5438 case NUNTIL:
5439 calcsize(n->nbinary.ch2);
5440 calcsize(n->nbinary.ch1);
5441 break;
5442 case NIF:
5443 calcsize(n->nif.elsepart);
5444 calcsize(n->nif.ifpart);
5445 calcsize(n->nif.test);
5446 break;
5447 case NFOR:
5448 funcstringsize += strlen(n->nfor.var) + 1;
5449 calcsize(n->nfor.body);
5450 calcsize(n->nfor.args);
5451 break;
5452 case NCASE:
5453 calcsize(n->ncase.cases);
5454 calcsize(n->ncase.expr);
5455 break;
5456 case NCLIST:
5457 calcsize(n->nclist.body);
5458 calcsize(n->nclist.pattern);
5459 calcsize(n->nclist.next);
5460 break;
5461 case NDEFUN:
5462 case NARG:
5463 sizenodelist(n->narg.backquote);
5464 funcstringsize += strlen(n->narg.text) + 1;
5465 calcsize(n->narg.next);
5466 break;
5467 case NTO:
5468 case NCLOBBER:
5469 case NFROM:
5470 case NFROMTO:
5471 case NAPPEND:
5472 calcsize(n->nfile.fname);
5473 calcsize(n->nfile.next);
5474 break;
5475 case NTOFD:
5476 case NFROMFD:
5477 calcsize(n->ndup.vname);
5478 calcsize(n->ndup.next);
5479 break;
5480 case NHERE:
5481 case NXHERE:
5482 calcsize(n->nhere.doc);
5483 calcsize(n->nhere.next);
5484 break;
5485 case NNOT:
5486 calcsize(n->nnot.com);
5487 break;
5488 };
5489}
5490
5491static char *
5492nodeckstrdup(char *s)
5493{
5494 char *rtn = funcstring;
5495
5496 strcpy(funcstring, s);
5497 funcstring += strlen(s) + 1;
5498 return rtn;
5499}
5500
5501static union node *copynode(union node *);
5502
5503static struct nodelist *
5504copynodelist(struct nodelist *lp)
5505{
5506 struct nodelist *start;
5507 struct nodelist **lpp;
5508
5509 lpp = &start;
5510 while (lp) {
5511 *lpp = funcblock;
5512 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
5513 (*lpp)->n = copynode(lp->n);
5514 lp = lp->next;
5515 lpp = &(*lpp)->next;
5516 }
5517 *lpp = NULL;
5518 return start;
5519}
5520
5521static union node *
5522copynode(union node *n)
5523{
5524 union node *new;
5525
5526 if (n == NULL)
5527 return NULL;
5528 new = funcblock;
5529 funcblock = (char *) funcblock + nodesize[n->type];
5530
5531 switch (n->type) {
5532 case NCMD:
5533 new->ncmd.redirect = copynode(n->ncmd.redirect);
5534 new->ncmd.args = copynode(n->ncmd.args);
5535 new->ncmd.assign = copynode(n->ncmd.assign);
5536 break;
5537 case NPIPE:
5538 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
5539 new->npipe.backgnd = n->npipe.backgnd;
5540 break;
5541 case NREDIR:
5542 case NBACKGND:
5543 case NSUBSHELL:
5544 new->nredir.redirect = copynode(n->nredir.redirect);
5545 new->nredir.n = copynode(n->nredir.n);
5546 break;
5547 case NAND:
5548 case NOR:
5549 case NSEMI:
5550 case NWHILE:
5551 case NUNTIL:
5552 new->nbinary.ch2 = copynode(n->nbinary.ch2);
5553 new->nbinary.ch1 = copynode(n->nbinary.ch1);
5554 break;
5555 case NIF:
5556 new->nif.elsepart = copynode(n->nif.elsepart);
5557 new->nif.ifpart = copynode(n->nif.ifpart);
5558 new->nif.test = copynode(n->nif.test);
5559 break;
5560 case NFOR:
5561 new->nfor.var = nodeckstrdup(n->nfor.var);
5562 new->nfor.body = copynode(n->nfor.body);
5563 new->nfor.args = copynode(n->nfor.args);
5564 break;
5565 case NCASE:
5566 new->ncase.cases = copynode(n->ncase.cases);
5567 new->ncase.expr = copynode(n->ncase.expr);
5568 break;
5569 case NCLIST:
5570 new->nclist.body = copynode(n->nclist.body);
5571 new->nclist.pattern = copynode(n->nclist.pattern);
5572 new->nclist.next = copynode(n->nclist.next);
5573 break;
5574 case NDEFUN:
5575 case NARG:
5576 new->narg.backquote = copynodelist(n->narg.backquote);
5577 new->narg.text = nodeckstrdup(n->narg.text);
5578 new->narg.next = copynode(n->narg.next);
5579 break;
5580 case NTO:
5581 case NCLOBBER:
5582 case NFROM:
5583 case NFROMTO:
5584 case NAPPEND:
5585 new->nfile.fname = copynode(n->nfile.fname);
5586 new->nfile.fd = n->nfile.fd;
5587 new->nfile.next = copynode(n->nfile.next);
5588 break;
5589 case NTOFD:
5590 case NFROMFD:
5591 new->ndup.vname = copynode(n->ndup.vname);
5592 new->ndup.dupfd = n->ndup.dupfd;
5593 new->ndup.fd = n->ndup.fd;
5594 new->ndup.next = copynode(n->ndup.next);
5595 break;
5596 case NHERE:
5597 case NXHERE:
5598 new->nhere.doc = copynode(n->nhere.doc);
5599 new->nhere.fd = n->nhere.fd;
5600 new->nhere.next = copynode(n->nhere.next);
5601 break;
5602 case NNOT:
5603 new->nnot.com = copynode(n->nnot.com);
5604 break;
5605 };
5606 new->type = n->type;
5607 return new;
5608}
5609
5610/*
5611 * Make a copy of a parse tree.
5612 */
5613static struct funcnode *
5614copyfunc(union node *n)
5615{
5616 struct funcnode *f;
5617 size_t blocksize;
5618
5619 funcblocksize = offsetof(struct funcnode, n);
5620 funcstringsize = 0;
5621 calcsize(n);
5622 blocksize = funcblocksize;
5623 f = ckmalloc(blocksize + funcstringsize);
5624 funcblock = (char *) f + offsetof(struct funcnode, n);
5625 funcstring = (char *) f + blocksize;
5626 copynode(n);
5627 f->count = 0;
5628 return f;
5629}
5630
5631/*
5632 * Define a shell function.
5633 */
5634static void
5635defun(char *name, union node *func)
5636{
5637 struct cmdentry entry;
5638
5639 INT_OFF;
5640 entry.cmdtype = CMDFUNCTION;
5641 entry.u.func = copyfunc(func);
5642 addcmdentry(name, &entry);
5643 INT_ON;
5644}
5645
5646static int evalskip; /* set if we are skipping commands */
5647/* reasons for skipping commands (see comment on breakcmd routine) */
5648#define SKIPBREAK (1 << 0)
5649#define SKIPCONT (1 << 1)
5650#define SKIPFUNC (1 << 2)
5651#define SKIPFILE (1 << 3)
5652#define SKIPEVAL (1 << 4)
5653static int skipcount; /* number of levels to skip */
5654static int funcnest; /* depth of function calls */
5655
4909/* forward declarations - evaluation is fairly recursive business... */ 5656/* forward declarations - evaluation is fairly recursive business... */
4910static void evalloop(union node *, int); 5657static void evalloop(union node *, int);
4911static void evalfor(union node *, int); 5658static void evalfor(union node *, int);
@@ -4915,7 +5662,6 @@ static void expredir(union node *);
4915static void evalpipe(union node *, int); 5662static void evalpipe(union node *, int);
4916static void evalcommand(union node *, int); 5663static void evalcommand(union node *, int);
4917static int evalbltin(const struct builtincmd *, int, char **); 5664static int evalbltin(const struct builtincmd *, int, char **);
4918static int evalfun(struct funcnode *, int, char **, int);
4919static void prehash(union node *); 5665static void prehash(union node *);
4920 5666
4921/* 5667/*
@@ -5270,6 +6016,84 @@ evalpipe(union node *n, int flags)
5270 INT_ON; 6016 INT_ON;
5271} 6017}
5272 6018
6019static struct localvar *localvars;
6020
6021/*
6022 * Called after a function returns.
6023 * Interrupts must be off.
6024 */
6025static void
6026poplocalvars(void)
6027{
6028 struct localvar *lvp;
6029 struct var *vp;
6030
6031 while ((lvp = localvars) != NULL) {
6032 localvars = lvp->next;
6033 vp = lvp->vp;
6034 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
6035 if (vp == NULL) { /* $- saved */
6036 memcpy(optlist, lvp->text, sizeof(optlist));
6037 free((char*)lvp->text);
6038 optschanged();
6039 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
6040 unsetvar(vp->text);
6041 } else {
6042 if (vp->func)
6043 (*vp->func)(strchrnul(lvp->text, '=') + 1);
6044 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
6045 free((char*)vp->text);
6046 vp->flags = lvp->flags;
6047 vp->text = lvp->text;
6048 }
6049 free(lvp);
6050 }
6051}
6052
6053static int
6054evalfun(struct funcnode *func, int argc, char **argv, int flags)
6055{
6056 volatile struct shparam saveparam;
6057 struct localvar *volatile savelocalvars;
6058 struct jmploc *volatile savehandler;
6059 struct jmploc jmploc;
6060 int e;
6061
6062 saveparam = shellparam;
6063 savelocalvars = localvars;
6064 e = setjmp(jmploc.loc);
6065 if (e) {
6066 goto funcdone;
6067 }
6068 INT_OFF;
6069 savehandler = exception_handler;
6070 exception_handler = &jmploc;
6071 localvars = NULL;
6072 shellparam.malloc = 0;
6073 func->count++;
6074 funcnest++;
6075 INT_ON;
6076 shellparam.nparam = argc - 1;
6077 shellparam.p = argv + 1;
6078#if ENABLE_ASH_GETOPTS
6079 shellparam.optind = 1;
6080 shellparam.optoff = -1;
6081#endif
6082 evaltree(&func->n, flags & EV_TESTED);
6083funcdone:
6084 INT_OFF;
6085 funcnest--;
6086 freefunc(func);
6087 poplocalvars();
6088 localvars = savelocalvars;
6089 freeparam(&shellparam);
6090 shellparam = saveparam;
6091 exception_handler = savehandler;
6092 INT_ON;
6093 evalskip &= ~SKIPFUNC;
6094 return e;
6095}
6096
5273#if ENABLE_ASH_CMDCMD 6097#if ENABLE_ASH_CMDCMD
5274static char ** 6098static char **
5275parse_command_args(char **argv, const char **path) 6099parse_command_args(char **argv, const char **path)
@@ -5305,6 +6129,68 @@ parse_command_args(char **argv, const char **path)
5305} 6129}
5306#endif 6130#endif
5307 6131
6132/*
6133 * Make a variable a local variable. When a variable is made local, it's
6134 * value and flags are saved in a localvar structure. The saved values
6135 * will be restored when the shell function returns. We handle the name
6136 * "-" as a special case.
6137 */
6138static void
6139mklocal(char *name)
6140{
6141 struct localvar *lvp;
6142 struct var **vpp;
6143 struct var *vp;
6144
6145 INT_OFF;
6146 lvp = ckmalloc(sizeof(struct localvar));
6147 if (LONE_DASH(name)) {
6148 char *p;
6149 p = ckmalloc(sizeof(optlist));
6150 lvp->text = memcpy(p, optlist, sizeof(optlist));
6151 vp = NULL;
6152 } else {
6153 char *eq;
6154
6155 vpp = hashvar(name);
6156 vp = *findvar(vpp, name);
6157 eq = strchr(name, '=');
6158 if (vp == NULL) {
6159 if (eq)
6160 setvareq(name, VSTRFIXED);
6161 else
6162 setvar(name, NULL, VSTRFIXED);
6163 vp = *vpp; /* the new variable */
6164 lvp->flags = VUNSET;
6165 } else {
6166 lvp->text = vp->text;
6167 lvp->flags = vp->flags;
6168 vp->flags |= VSTRFIXED|VTEXTFIXED;
6169 if (eq)
6170 setvareq(name, 0);
6171 }
6172 }
6173 lvp->vp = vp;
6174 lvp->next = localvars;
6175 localvars = lvp;
6176 INT_ON;
6177}
6178
6179/*
6180 * The "local" command.
6181 */
6182static int
6183localcmd(int argc, char **argv)
6184{
6185 char *name;
6186
6187 argv = argptr;
6188 while ((name = *argv++) != NULL) {
6189 mklocal(name);
6190 }
6191 return 0;
6192}
6193
5308/* Forward declarations for builtintab[] */ 6194/* Forward declarations for builtintab[] */
5309#if JOBS 6195#if JOBS
5310static int fg_bgcmd(int, char **); 6196static int fg_bgcmd(int, char **);
@@ -5338,7 +6224,6 @@ static int jobscmd(int, char **);
5338#if ENABLE_ASH_MATH_SUPPORT 6224#if ENABLE_ASH_MATH_SUPPORT
5339static int letcmd(int, char **); 6225static int letcmd(int, char **);
5340#endif 6226#endif
5341static int localcmd(int, char **);
5342static int pwdcmd(int, char **); 6227static int pwdcmd(int, char **);
5343static int readcmd(int, char **); 6228static int readcmd(int, char **);
5344static int returncmd(int, char **); 6229static int returncmd(int, char **);
@@ -5356,19 +6241,15 @@ static int ulimitcmd(int, char **);
5356static int killcmd(int, char **); 6241static int killcmd(int, char **);
5357#endif 6242#endif
5358 6243
5359#define BUILTIN_NOSPEC "0" 6244#define BUILTIN_NOSPEC "0"
5360#define BUILTIN_SPECIAL "1" 6245#define BUILTIN_SPECIAL "1"
5361#define BUILTIN_REGULAR "2" 6246#define BUILTIN_REGULAR "2"
5362#define BUILTIN_SPEC_REG "3" 6247#define BUILTIN_SPEC_REG "3"
5363#define BUILTIN_ASSIGN "4" 6248#define BUILTIN_ASSIGN "4"
5364#define BUILTIN_SPEC_ASSG "5" 6249#define BUILTIN_SPEC_ASSG "5"
5365#define BUILTIN_REG_ASSG "6" 6250#define BUILTIN_REG_ASSG "6"
5366#define BUILTIN_SPEC_REG_ASSG "7" 6251#define BUILTIN_SPEC_REG_ASSG "7"
5367 6252
5368#define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
5369#define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
5370#define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
5371
5372/* make sure to keep these in proper order since it is searched via bsearch() */ 6253/* make sure to keep these in proper order since it is searched via bsearch() */
5373static const struct builtincmd builtintab[] = { 6254static const struct builtincmd builtintab[] = {
5374 { BUILTIN_SPEC_REG ".", dotcmd }, 6255 { BUILTIN_SPEC_REG ".", dotcmd },
@@ -5453,6 +6334,205 @@ static const struct builtincmd builtintab[] = {
5453 ENABLE_ASH_BUILTIN_ECHO) 6334 ENABLE_ASH_BUILTIN_ECHO)
5454 6335
5455/* 6336/*
6337 * Search the table of builtin commands.
6338 */
6339static struct builtincmd *
6340find_builtin(const char *name)
6341{
6342 struct builtincmd *bp;
6343
6344 bp = bsearch(
6345 name, builtintab, NUMBUILTINS, sizeof(builtintab[0]),
6346 pstrcmp
6347 );
6348 return bp;
6349}
6350
6351/*
6352 * Resolve a command name. If you change this routine, you may have to
6353 * change the shellexec routine as well.
6354 */
6355static void
6356find_command(char *name, struct cmdentry *entry, int act, const char *path)
6357{
6358 struct tblentry *cmdp;
6359 int idx;
6360 int prev;
6361 char *fullname;
6362 struct stat statb;
6363 int e;
6364 int updatetbl;
6365 struct builtincmd *bcmd;
6366
6367 /* If name contains a slash, don't use PATH or hash table */
6368 if (strchr(name, '/') != NULL) {
6369 entry->u.index = -1;
6370 if (act & DO_ABS) {
6371 while (stat(name, &statb) < 0) {
6372#ifdef SYSV
6373 if (errno == EINTR)
6374 continue;
6375#endif
6376 entry->cmdtype = CMDUNKNOWN;
6377 return;
6378 }
6379 }
6380 entry->cmdtype = CMDNORMAL;
6381 return;
6382 }
6383
6384#if ENABLE_FEATURE_SH_STANDALONE_SHELL
6385 if (find_applet_by_name(name)) {
6386 entry->cmdtype = CMDNORMAL;
6387 entry->u.index = -1;
6388 return;
6389 }
6390#endif
6391
6392 if (is_safe_applet(name)) {
6393 entry->cmdtype = CMDNORMAL;
6394 entry->u.index = -1;
6395 return;
6396 }
6397
6398 updatetbl = (path == pathval());
6399 if (!updatetbl) {
6400 act |= DO_ALTPATH;
6401 if (strstr(path, "%builtin") != NULL)
6402 act |= DO_ALTBLTIN;
6403 }
6404
6405 /* If name is in the table, check answer will be ok */
6406 cmdp = cmdlookup(name, 0);
6407 if (cmdp != NULL) {
6408 int bit;
6409
6410 switch (cmdp->cmdtype) {
6411 default:
6412#if DEBUG
6413 abort();
6414#endif
6415 case CMDNORMAL:
6416 bit = DO_ALTPATH;
6417 break;
6418 case CMDFUNCTION:
6419 bit = DO_NOFUNC;
6420 break;
6421 case CMDBUILTIN:
6422 bit = DO_ALTBLTIN;
6423 break;
6424 }
6425 if (act & bit) {
6426 updatetbl = 0;
6427 cmdp = NULL;
6428 } else if (cmdp->rehash == 0)
6429 /* if not invalidated by cd, we're done */
6430 goto success;
6431 }
6432
6433 /* If %builtin not in path, check for builtin next */
6434 bcmd = find_builtin(name);
6435 if (bcmd && (IS_BUILTIN_REGULAR(bcmd) || (
6436 act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc <= 0
6437 )))
6438 goto builtin_success;
6439
6440 /* We have to search path. */
6441 prev = -1; /* where to start */
6442 if (cmdp && cmdp->rehash) { /* doing a rehash */
6443 if (cmdp->cmdtype == CMDBUILTIN)
6444 prev = builtinloc;
6445 else
6446 prev = cmdp->param.index;
6447 }
6448
6449 e = ENOENT;
6450 idx = -1;
6451 loop:
6452 while ((fullname = padvance(&path, name)) != NULL) {
6453 stunalloc(fullname);
6454 idx++;
6455 if (pathopt) {
6456 if (prefix(pathopt, "builtin")) {
6457 if (bcmd)
6458 goto builtin_success;
6459 continue;
6460 } else if (!(act & DO_NOFUNC) &&
6461 prefix(pathopt, "func")) {
6462 /* handled below */
6463 } else {
6464 /* ignore unimplemented options */
6465 continue;
6466 }
6467 }
6468 /* if rehash, don't redo absolute path names */
6469 if (fullname[0] == '/' && idx <= prev) {
6470 if (idx < prev)
6471 continue;
6472 TRACE(("searchexec \"%s\": no change\n", name));
6473 goto success;
6474 }
6475 while (stat(fullname, &statb) < 0) {
6476#ifdef SYSV
6477 if (errno == EINTR)
6478 continue;
6479#endif
6480 if (errno != ENOENT && errno != ENOTDIR)
6481 e = errno;
6482 goto loop;
6483 }
6484 e = EACCES; /* if we fail, this will be the error */
6485 if (!S_ISREG(statb.st_mode))
6486 continue;
6487 if (pathopt) { /* this is a %func directory */
6488 stalloc(strlen(fullname) + 1);
6489 readcmdfile(fullname);
6490 cmdp = cmdlookup(name, 0);
6491 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
6492 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
6493 stunalloc(fullname);
6494 goto success;
6495 }
6496 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
6497 if (!updatetbl) {
6498 entry->cmdtype = CMDNORMAL;
6499 entry->u.index = idx;
6500 return;
6501 }
6502 INT_OFF;
6503 cmdp = cmdlookup(name, 1);
6504 cmdp->cmdtype = CMDNORMAL;
6505 cmdp->param.index = idx;
6506 INT_ON;
6507 goto success;
6508 }
6509
6510 /* We failed. If there was an entry for this command, delete it */
6511 if (cmdp && updatetbl)
6512 delete_cmd_entry();
6513 if (act & DO_ERR)
6514 ash_msg("%s: %s", name, errmsg(e, "not found"));
6515 entry->cmdtype = CMDUNKNOWN;
6516 return;
6517
6518 builtin_success:
6519 if (!updatetbl) {
6520 entry->cmdtype = CMDBUILTIN;
6521 entry->u.cmd = bcmd;
6522 return;
6523 }
6524 INT_OFF;
6525 cmdp = cmdlookup(name, 1);
6526 cmdp->cmdtype = CMDBUILTIN;
6527 cmdp->param.cmd = bcmd;
6528 INT_ON;
6529 success:
6530 cmdp->rehash = 0;
6531 entry->cmdtype = cmdp->cmdtype;
6532 entry->u = cmdp->param;
6533}
6534
6535/*
5456 * Execute a simple command. 6536 * Execute a simple command.
5457 */ 6537 */
5458static int back_exitstatus; /* exit status of backquoted command */ 6538static int back_exitstatus; /* exit status of backquoted command */
@@ -5732,95 +6812,6 @@ evalbltin(const struct builtincmd *cmd, int argc, char **argv)
5732 return i; 6812 return i;
5733} 6813}
5734 6814
5735static struct localvar *localvars;
5736
5737/*
5738 * Called after a function returns.
5739 * Interrupts must be off.
5740 */
5741static void
5742poplocalvars(void)
5743{
5744 struct localvar *lvp;
5745 struct var *vp;
5746
5747 while ((lvp = localvars) != NULL) {
5748 localvars = lvp->next;
5749 vp = lvp->vp;
5750 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
5751 if (vp == NULL) { /* $- saved */
5752 memcpy(optlist, lvp->text, sizeof(optlist));
5753 free((char*)lvp->text);
5754 optschanged();
5755 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
5756 unsetvar(vp->text);
5757 } else {
5758 if (vp->func)
5759 (*vp->func)(strchrnul(lvp->text, '=') + 1);
5760 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
5761 free((char*)vp->text);
5762 vp->flags = lvp->flags;
5763 vp->text = lvp->text;
5764 }
5765 free(lvp);
5766 }
5767}
5768
5769/*
5770 * Free a parse tree.
5771 */
5772static void
5773freefunc(struct funcnode *f)
5774{
5775 if (f && --f->count < 0)
5776 free(f);
5777}
5778
5779static int
5780evalfun(struct funcnode *func, int argc, char **argv, int flags)
5781{
5782 volatile struct shparam saveparam;
5783 struct localvar *volatile savelocalvars;
5784 struct jmploc *volatile savehandler;
5785 struct jmploc jmploc;
5786 int e;
5787
5788 saveparam = shellparam;
5789 savelocalvars = localvars;
5790 e = setjmp(jmploc.loc);
5791 if (e) {
5792 goto funcdone;
5793 }
5794 INT_OFF;
5795 savehandler = exception_handler;
5796 exception_handler = &jmploc;
5797 localvars = NULL;
5798 shellparam.malloc = 0;
5799 func->count++;
5800 funcnest++;
5801 INT_ON;
5802 shellparam.nparam = argc - 1;
5803 shellparam.p = argv + 1;
5804#if ENABLE_ASH_GETOPTS
5805 shellparam.optind = 1;
5806 shellparam.optoff = -1;
5807#endif
5808 evaltree(&func->n, flags & EV_TESTED);
5809funcdone:
5810 INT_OFF;
5811 funcnest--;
5812 freefunc(func);
5813 poplocalvars();
5814 localvars = savelocalvars;
5815 freeparam(&shellparam);
5816 shellparam = saveparam;
5817 exception_handler = savehandler;
5818 INT_ON;
5819 evalskip &= ~SKIPFUNC;
5820 return e;
5821}
5822
5823
5824static int 6815static int
5825goodname(const char *p) 6816goodname(const char *p)
5826{ 6817{
@@ -5915,764 +6906,6 @@ execcmd(int argc, char **argv)
5915} 6906}
5916 6907
5917 6908
5918/* ============ Executing commands */
5919
5920/*
5921 * When commands are first encountered, they are entered in a hash table.
5922 * This ensures that a full path search will not have to be done for them
5923 * on each invocation.
5924 *
5925 * We should investigate converting to a linear search, even though that
5926 * would make the command name "hash" a misnomer.
5927 */
5928
5929#define CMDTABLESIZE 31 /* should be prime */
5930#define ARB 1 /* actual size determined at run time */
5931
5932struct tblentry {
5933 struct tblentry *next; /* next entry in hash chain */
5934 union param param; /* definition of builtin function */
5935 short cmdtype; /* index identifying command */
5936 char rehash; /* if set, cd done since entry created */
5937 char cmdname[ARB]; /* name of command */
5938};
5939
5940static struct tblentry *cmdtable[CMDTABLESIZE];
5941static int builtinloc = -1; /* index in path of %builtin, or -1 */
5942
5943static void
5944tryexec(char *cmd, char **argv, char **envp)
5945{
5946 int repeated = 0;
5947 struct BB_applet *a;
5948 int argc = 0;
5949 char **c;
5950
5951 if (strchr(cmd, '/') == NULL
5952 && (a = find_applet_by_name(cmd)) != NULL
5953 && is_safe_applet(cmd)
5954 ) {
5955 c = argv;
5956 while (*c != NULL) {
5957 c++; argc++;
5958 }
5959 applet_name = cmd;
5960 exit(a->main(argc, argv));
5961 }
5962#if ENABLE_FEATURE_SH_STANDALONE_SHELL
5963 if (find_applet_by_name(cmd) != NULL) {
5964 /* re-exec ourselves with the new arguments */
5965 execve(CONFIG_BUSYBOX_EXEC_PATH, argv, envp);
5966 /* If they called chroot or otherwise made the binary no longer
5967 * executable, fall through */
5968 }
5969#endif
5970
5971 repeat:
5972#ifdef SYSV
5973 do {
5974 execve(cmd, argv, envp);
5975 } while (errno == EINTR);
5976#else
5977 execve(cmd, argv, envp);
5978#endif
5979 if (repeated++) {
5980 free(argv);
5981 } else if (errno == ENOEXEC) {
5982 char **ap;
5983 char **new;
5984
5985 for (ap = argv; *ap; ap++)
5986 ;
5987 ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
5988 ap[1] = cmd;
5989 *ap = cmd = (char *)DEFAULT_SHELL;
5990 ap += 2;
5991 argv++;
5992 while ((*ap++ = *argv++))
5993 ;
5994 argv = new;
5995 goto repeat;
5996 }
5997}
5998
5999/*
6000 * Exec a program. Never returns. If you change this routine, you may
6001 * have to change the find_command routine as well.
6002 */
6003#define environment() listvars(VEXPORT, VUNSET, 0)
6004static void shellexec(char **, const char *, int) ATTRIBUTE_NORETURN;
6005static void
6006shellexec(char **argv, const char *path, int idx)
6007{
6008 char *cmdname;
6009 int e;
6010 char **envp;
6011 int exerrno;
6012
6013 clearredir(1);
6014 envp = environment();
6015 if (strchr(argv[0], '/') || is_safe_applet(argv[0])
6016#if ENABLE_FEATURE_SH_STANDALONE_SHELL
6017 || find_applet_by_name(argv[0])
6018#endif
6019 ) {
6020 tryexec(argv[0], argv, envp);
6021 e = errno;
6022 } else {
6023 e = ENOENT;
6024 while ((cmdname = padvance(&path, argv[0])) != NULL) {
6025 if (--idx < 0 && pathopt == NULL) {
6026 tryexec(cmdname, argv, envp);
6027 if (errno != ENOENT && errno != ENOTDIR)
6028 e = errno;
6029 }
6030 stunalloc(cmdname);
6031 }
6032 }
6033
6034 /* Map to POSIX errors */
6035 switch (e) {
6036 case EACCES:
6037 exerrno = 126;
6038 break;
6039 case ENOENT:
6040 exerrno = 127;
6041 break;
6042 default:
6043 exerrno = 2;
6044 break;
6045 }
6046 exitstatus = exerrno;
6047 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
6048 argv[0], e, suppressint ));
6049 ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found"));
6050 /* NOTREACHED */
6051}
6052
6053static void
6054printentry(struct tblentry *cmdp)
6055{
6056 int idx;
6057 const char *path;
6058 char *name;
6059
6060 idx = cmdp->param.index;
6061 path = pathval();
6062 do {
6063 name = padvance(&path, cmdp->cmdname);
6064 stunalloc(name);
6065 } while (--idx >= 0);
6066 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
6067}
6068
6069/*
6070 * Clear out command entries. The argument specifies the first entry in
6071 * PATH which has changed.
6072 */
6073static void
6074clearcmdentry(int firstchange)
6075{
6076 struct tblentry **tblp;
6077 struct tblentry **pp;
6078 struct tblentry *cmdp;
6079
6080 INT_OFF;
6081 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
6082 pp = tblp;
6083 while ((cmdp = *pp) != NULL) {
6084 if ((cmdp->cmdtype == CMDNORMAL &&
6085 cmdp->param.index >= firstchange)
6086 || (cmdp->cmdtype == CMDBUILTIN &&
6087 builtinloc >= firstchange)
6088 ) {
6089 *pp = cmdp->next;
6090 free(cmdp);
6091 } else {
6092 pp = &cmdp->next;
6093 }
6094 }
6095 }
6096 INT_ON;
6097}
6098
6099/*
6100 * Locate a command in the command hash table. If "add" is nonzero,
6101 * add the command to the table if it is not already present. The
6102 * variable "lastcmdentry" is set to point to the address of the link
6103 * pointing to the entry, so that delete_cmd_entry can delete the
6104 * entry.
6105 *
6106 * Interrupts must be off if called with add != 0.
6107 */
6108static struct tblentry **lastcmdentry;
6109
6110static struct tblentry *
6111cmdlookup(const char *name, int add)
6112{
6113 unsigned int hashval;
6114 const char *p;
6115 struct tblentry *cmdp;
6116 struct tblentry **pp;
6117
6118 p = name;
6119 hashval = (unsigned char)*p << 4;
6120 while (*p)
6121 hashval += (unsigned char)*p++;
6122 hashval &= 0x7FFF;
6123 pp = &cmdtable[hashval % CMDTABLESIZE];
6124 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
6125 if (strcmp(cmdp->cmdname, name) == 0)
6126 break;
6127 pp = &cmdp->next;
6128 }
6129 if (add && cmdp == NULL) {
6130 cmdp = *pp = ckmalloc(sizeof(struct tblentry) - ARB
6131 + strlen(name) + 1);
6132 cmdp->next = NULL;
6133 cmdp->cmdtype = CMDUNKNOWN;
6134 strcpy(cmdp->cmdname, name);
6135 }
6136 lastcmdentry = pp;
6137 return cmdp;
6138}
6139
6140/*
6141 * Delete the command entry returned on the last lookup.
6142 */
6143static void
6144delete_cmd_entry(void)
6145{
6146 struct tblentry *cmdp;
6147
6148 INT_OFF;
6149 cmdp = *lastcmdentry;
6150 *lastcmdentry = cmdp->next;
6151 if (cmdp->cmdtype == CMDFUNCTION)
6152 freefunc(cmdp->param.func);
6153 free(cmdp);
6154 INT_ON;
6155}
6156
6157/*
6158 * Add a new command entry, replacing any existing command entry for
6159 * the same name - except special builtins.
6160 */
6161static void
6162addcmdentry(char *name, struct cmdentry *entry)
6163{
6164 struct tblentry *cmdp;
6165
6166 cmdp = cmdlookup(name, 1);
6167 if (cmdp->cmdtype == CMDFUNCTION) {
6168 freefunc(cmdp->param.func);
6169 }
6170 cmdp->cmdtype = entry->cmdtype;
6171 cmdp->param = entry->u;
6172 cmdp->rehash = 0;
6173}
6174
6175static int
6176hashcmd(int argc, char **argv)
6177{
6178 struct tblentry **pp;
6179 struct tblentry *cmdp;
6180 int c;
6181 struct cmdentry entry;
6182 char *name;
6183
6184 while ((c = nextopt("r")) != '\0') {
6185 clearcmdentry(0);
6186 return 0;
6187 }
6188 if (*argptr == NULL) {
6189 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
6190 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
6191 if (cmdp->cmdtype == CMDNORMAL)
6192 printentry(cmdp);
6193 }
6194 }
6195 return 0;
6196 }
6197 c = 0;
6198 while ((name = *argptr) != NULL) {
6199 cmdp = cmdlookup(name, 0);
6200 if (cmdp != NULL
6201 && (cmdp->cmdtype == CMDNORMAL
6202 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
6203 delete_cmd_entry();
6204 find_command(name, &entry, DO_ERR, pathval());
6205 if (entry.cmdtype == CMDUNKNOWN)
6206 c = 1;
6207 argptr++;
6208 }
6209 return c;
6210}
6211
6212/*
6213 * Resolve a command name. If you change this routine, you may have to
6214 * change the shellexec routine as well.
6215 */
6216static void
6217find_command(char *name, struct cmdentry *entry, int act, const char *path)
6218{
6219 struct tblentry *cmdp;
6220 int idx;
6221 int prev;
6222 char *fullname;
6223 struct stat statb;
6224 int e;
6225 int updatetbl;
6226 struct builtincmd *bcmd;
6227
6228 /* If name contains a slash, don't use PATH or hash table */
6229 if (strchr(name, '/') != NULL) {
6230 entry->u.index = -1;
6231 if (act & DO_ABS) {
6232 while (stat(name, &statb) < 0) {
6233#ifdef SYSV
6234 if (errno == EINTR)
6235 continue;
6236#endif
6237 entry->cmdtype = CMDUNKNOWN;
6238 return;
6239 }
6240 }
6241 entry->cmdtype = CMDNORMAL;
6242 return;
6243 }
6244
6245#if ENABLE_FEATURE_SH_STANDALONE_SHELL
6246 if (find_applet_by_name(name)) {
6247 entry->cmdtype = CMDNORMAL;
6248 entry->u.index = -1;
6249 return;
6250 }
6251#endif
6252
6253 if (is_safe_applet(name)) {
6254 entry->cmdtype = CMDNORMAL;
6255 entry->u.index = -1;
6256 return;
6257 }
6258
6259 updatetbl = (path == pathval());
6260 if (!updatetbl) {
6261 act |= DO_ALTPATH;
6262 if (strstr(path, "%builtin") != NULL)
6263 act |= DO_ALTBLTIN;
6264 }
6265
6266 /* If name is in the table, check answer will be ok */
6267 cmdp = cmdlookup(name, 0);
6268 if (cmdp != NULL) {
6269 int bit;
6270
6271 switch (cmdp->cmdtype) {
6272 default:
6273#if DEBUG
6274 abort();
6275#endif
6276 case CMDNORMAL:
6277 bit = DO_ALTPATH;
6278 break;
6279 case CMDFUNCTION:
6280 bit = DO_NOFUNC;
6281 break;
6282 case CMDBUILTIN:
6283 bit = DO_ALTBLTIN;
6284 break;
6285 }
6286 if (act & bit) {
6287 updatetbl = 0;
6288 cmdp = NULL;
6289 } else if (cmdp->rehash == 0)
6290 /* if not invalidated by cd, we're done */
6291 goto success;
6292 }
6293
6294 /* If %builtin not in path, check for builtin next */
6295 bcmd = find_builtin(name);
6296 if (bcmd && (IS_BUILTIN_REGULAR(bcmd) || (
6297 act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc <= 0
6298 )))
6299 goto builtin_success;
6300
6301 /* We have to search path. */
6302 prev = -1; /* where to start */
6303 if (cmdp && cmdp->rehash) { /* doing a rehash */
6304 if (cmdp->cmdtype == CMDBUILTIN)
6305 prev = builtinloc;
6306 else
6307 prev = cmdp->param.index;
6308 }
6309
6310 e = ENOENT;
6311 idx = -1;
6312 loop:
6313 while ((fullname = padvance(&path, name)) != NULL) {
6314 stunalloc(fullname);
6315 idx++;
6316 if (pathopt) {
6317 if (prefix(pathopt, "builtin")) {
6318 if (bcmd)
6319 goto builtin_success;
6320 continue;
6321 } else if (!(act & DO_NOFUNC) &&
6322 prefix(pathopt, "func")) {
6323 /* handled below */
6324 } else {
6325 /* ignore unimplemented options */
6326 continue;
6327 }
6328 }
6329 /* if rehash, don't redo absolute path names */
6330 if (fullname[0] == '/' && idx <= prev) {
6331 if (idx < prev)
6332 continue;
6333 TRACE(("searchexec \"%s\": no change\n", name));
6334 goto success;
6335 }
6336 while (stat(fullname, &statb) < 0) {
6337#ifdef SYSV
6338 if (errno == EINTR)
6339 continue;
6340#endif
6341 if (errno != ENOENT && errno != ENOTDIR)
6342 e = errno;
6343 goto loop;
6344 }
6345 e = EACCES; /* if we fail, this will be the error */
6346 if (!S_ISREG(statb.st_mode))
6347 continue;
6348 if (pathopt) { /* this is a %func directory */
6349 stalloc(strlen(fullname) + 1);
6350 readcmdfile(fullname);
6351 cmdp = cmdlookup(name, 0);
6352 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
6353 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
6354 stunalloc(fullname);
6355 goto success;
6356 }
6357 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
6358 if (!updatetbl) {
6359 entry->cmdtype = CMDNORMAL;
6360 entry->u.index = idx;
6361 return;
6362 }
6363 INT_OFF;
6364 cmdp = cmdlookup(name, 1);
6365 cmdp->cmdtype = CMDNORMAL;
6366 cmdp->param.index = idx;
6367 INT_ON;
6368 goto success;
6369 }
6370
6371 /* We failed. If there was an entry for this command, delete it */
6372 if (cmdp && updatetbl)
6373 delete_cmd_entry();
6374 if (act & DO_ERR)
6375 ash_msg("%s: %s", name, errmsg(e, "not found"));
6376 entry->cmdtype = CMDUNKNOWN;
6377 return;
6378
6379 builtin_success:
6380 if (!updatetbl) {
6381 entry->cmdtype = CMDBUILTIN;
6382 entry->u.cmd = bcmd;
6383 return;
6384 }
6385 INT_OFF;
6386 cmdp = cmdlookup(name, 1);
6387 cmdp->cmdtype = CMDBUILTIN;
6388 cmdp->param.cmd = bcmd;
6389 INT_ON;
6390 success:
6391 cmdp->rehash = 0;
6392 entry->cmdtype = cmdp->cmdtype;
6393 entry->u = cmdp->param;
6394}
6395
6396/*
6397 * Search the table of builtin commands.
6398 */
6399static struct builtincmd *
6400find_builtin(const char *name)
6401{
6402 struct builtincmd *bp;
6403
6404 bp = bsearch(
6405 name, builtintab, NUMBUILTINS, sizeof(builtintab[0]),
6406 pstrcmp
6407 );
6408 return bp;
6409}
6410
6411/*
6412 * Called when a cd is done. Marks all commands so the next time they
6413 * are executed they will be rehashed.
6414 */
6415static void
6416hashcd(void)
6417{
6418 struct tblentry **pp;
6419 struct tblentry *cmdp;
6420
6421 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
6422 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
6423 if (cmdp->cmdtype == CMDNORMAL || (
6424 cmdp->cmdtype == CMDBUILTIN &&
6425 !(IS_BUILTIN_REGULAR(cmdp->param.cmd)) &&
6426 builtinloc > 0
6427 ))
6428 cmdp->rehash = 1;
6429 }
6430 }
6431}
6432
6433/*
6434 * Fix command hash table when PATH changed.
6435 * Called before PATH is changed. The argument is the new value of PATH;
6436 * pathval() still returns the old value at this point.
6437 * Called with interrupts off.
6438 */
6439static void
6440changepath(const char *newval)
6441{
6442 const char *old, *new;
6443 int idx;
6444 int firstchange;
6445 int idx_bltin;
6446
6447 old = pathval();
6448 new = newval;
6449 firstchange = 9999; /* assume no change */
6450 idx = 0;
6451 idx_bltin = -1;
6452 for (;;) {
6453 if (*old != *new) {
6454 firstchange = idx;
6455 if ((*old == '\0' && *new == ':')
6456 || (*old == ':' && *new == '\0'))
6457 firstchange++;
6458 old = new; /* ignore subsequent differences */
6459 }
6460 if (*new == '\0')
6461 break;
6462 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
6463 idx_bltin = idx;
6464 if (*new == ':') {
6465 idx++;
6466 }
6467 new++, old++;
6468 }
6469 if (builtinloc < 0 && idx_bltin >= 0)
6470 builtinloc = idx_bltin; /* zap builtins */
6471 if (builtinloc >= 0 && idx_bltin < 0)
6472 firstchange = 0;
6473 clearcmdentry(firstchange);
6474 builtinloc = idx_bltin;
6475}
6476
6477
6478/*
6479 * Make a copy of a parse tree.
6480 */
6481static struct funcnode *
6482copyfunc(union node *n)
6483{
6484 struct funcnode *f;
6485 size_t blocksize;
6486
6487 funcblocksize = offsetof(struct funcnode, n);
6488 funcstringsize = 0;
6489 calcsize(n);
6490 blocksize = funcblocksize;
6491 f = ckmalloc(blocksize + funcstringsize);
6492 funcblock = (char *) f + offsetof(struct funcnode, n);
6493 funcstring = (char *) f + blocksize;
6494 copynode(n);
6495 f->count = 0;
6496 return f;
6497}
6498
6499/*
6500 * Define a shell function.
6501 */
6502static void
6503defun(char *name, union node *func)
6504{
6505 struct cmdentry entry;
6506
6507 INT_OFF;
6508 entry.cmdtype = CMDFUNCTION;
6509 entry.u.func = copyfunc(func);
6510 addcmdentry(name, &entry);
6511 INT_ON;
6512}
6513
6514/*
6515 * Delete a function if it exists.
6516 */
6517static void
6518unsetfunc(const char *name)
6519{
6520 struct tblentry *cmdp;
6521
6522 cmdp = cmdlookup(name, 0);
6523 if (cmdp!= NULL && cmdp->cmdtype == CMDFUNCTION)
6524 delete_cmd_entry();
6525}
6526
6527
6528/*
6529 * Locate and print what a word is...
6530 */
6531#if ENABLE_ASH_CMDCMD
6532static int
6533describe_command(char *command, int describe_command_verbose)
6534#else
6535#define describe_command_verbose 1
6536static int
6537describe_command(char *command)
6538#endif
6539{
6540 struct cmdentry entry;
6541 struct tblentry *cmdp;
6542#if ENABLE_ASH_ALIAS
6543 const struct alias *ap;
6544#endif
6545 const char *path = pathval();
6546
6547 if (describe_command_verbose) {
6548 out1str(command);
6549 }
6550
6551 /* First look at the keywords */
6552 if (findkwd(command)) {
6553 out1str(describe_command_verbose ? " is a shell keyword" : command);
6554 goto out;
6555 }
6556
6557#if ENABLE_ASH_ALIAS
6558 /* Then look at the aliases */
6559 ap = lookupalias(command, 0);
6560 if (ap != NULL) {
6561 if (describe_command_verbose) {
6562 out1fmt(" is an alias for %s", ap->val);
6563 } else {
6564 out1str("alias ");
6565 printalias(ap);
6566 return 0;
6567 }
6568 goto out;
6569 }
6570#endif
6571 /* Then check if it is a tracked alias */
6572 cmdp = cmdlookup(command, 0);
6573 if (cmdp != NULL) {
6574 entry.cmdtype = cmdp->cmdtype;
6575 entry.u = cmdp->param;
6576 } else {
6577 /* Finally use brute force */
6578 find_command(command, &entry, DO_ABS, path);
6579 }
6580
6581 switch (entry.cmdtype) {
6582 case CMDNORMAL: {
6583 int j = entry.u.index;
6584 char *p;
6585 if (j == -1) {
6586 p = command;
6587 } else {
6588 do {
6589 p = padvance(&path, command);
6590 stunalloc(p);
6591 } while (--j >= 0);
6592 }
6593 if (describe_command_verbose) {
6594 out1fmt(" is%s %s",
6595 (cmdp ? " a tracked alias for" : nullstr), p
6596 );
6597 } else {
6598 out1str(p);
6599 }
6600 break;
6601 }
6602
6603 case CMDFUNCTION:
6604 if (describe_command_verbose) {
6605 out1str(" is a shell function");
6606 } else {
6607 out1str(command);
6608 }
6609 break;
6610
6611 case CMDBUILTIN:
6612 if (describe_command_verbose) {
6613 out1fmt(" is a %sshell builtin",
6614 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
6615 "special " : nullstr
6616 );
6617 } else {
6618 out1str(command);
6619 }
6620 break;
6621
6622 default:
6623 if (describe_command_verbose) {
6624 out1str(": not found\n");
6625 }
6626 return 127;
6627 }
6628 out:
6629 outstr("\n", stdout);
6630 return 0;
6631}
6632
6633static int
6634typecmd(int argc, char **argv)
6635{
6636 int i;
6637 int err = 0;
6638
6639 for (i = 1; i < argc; i++) {
6640#if ENABLE_ASH_CMDCMD
6641 err |= describe_command(argv[i], 1);
6642#else
6643 err |= describe_command(argv[i]);
6644#endif
6645 }
6646 return err;
6647}
6648
6649#if ENABLE_ASH_CMDCMD
6650static int
6651commandcmd(int argc, char **argv)
6652{
6653 int c;
6654 enum {
6655 VERIFY_BRIEF = 1,
6656 VERIFY_VERBOSE = 2,
6657 } verify = 0;
6658
6659 while ((c = nextopt("pvV")) != '\0')
6660 if (c == 'V')
6661 verify |= VERIFY_VERBOSE;
6662 else if (c == 'v')
6663 verify |= VERIFY_BRIEF;
6664#if DEBUG
6665 else if (c != 'p')
6666 abort();
6667#endif
6668 if (verify)
6669 return describe_command(*argptr, verify - VERIFY_BRIEF);
6670
6671 return 0;
6672}
6673#endif
6674
6675
6676/* ============ input.c 6909/* ============ input.c
6677 * 6910 *
6678 * This implements the input routines used by the parser. 6911 * This implements the input routines used by the parser.
@@ -8542,211 +8775,6 @@ find_dot_file(char *name)
8542 /* NOTREACHED */ 8775 /* NOTREACHED */
8543} 8776}
8544 8777
8545static void
8546calcsize(union node *n)
8547{
8548 if (n == NULL)
8549 return;
8550 funcblocksize += nodesize[n->type];
8551 switch (n->type) {
8552 case NCMD:
8553 calcsize(n->ncmd.redirect);
8554 calcsize(n->ncmd.args);
8555 calcsize(n->ncmd.assign);
8556 break;
8557 case NPIPE:
8558 sizenodelist(n->npipe.cmdlist);
8559 break;
8560 case NREDIR:
8561 case NBACKGND:
8562 case NSUBSHELL:
8563 calcsize(n->nredir.redirect);
8564 calcsize(n->nredir.n);
8565 break;
8566 case NAND:
8567 case NOR:
8568 case NSEMI:
8569 case NWHILE:
8570 case NUNTIL:
8571 calcsize(n->nbinary.ch2);
8572 calcsize(n->nbinary.ch1);
8573 break;
8574 case NIF:
8575 calcsize(n->nif.elsepart);
8576 calcsize(n->nif.ifpart);
8577 calcsize(n->nif.test);
8578 break;
8579 case NFOR:
8580 funcstringsize += strlen(n->nfor.var) + 1;
8581 calcsize(n->nfor.body);
8582 calcsize(n->nfor.args);
8583 break;
8584 case NCASE:
8585 calcsize(n->ncase.cases);
8586 calcsize(n->ncase.expr);
8587 break;
8588 case NCLIST:
8589 calcsize(n->nclist.body);
8590 calcsize(n->nclist.pattern);
8591 calcsize(n->nclist.next);
8592 break;
8593 case NDEFUN:
8594 case NARG:
8595 sizenodelist(n->narg.backquote);
8596 funcstringsize += strlen(n->narg.text) + 1;
8597 calcsize(n->narg.next);
8598 break;
8599 case NTO:
8600 case NCLOBBER:
8601 case NFROM:
8602 case NFROMTO:
8603 case NAPPEND:
8604 calcsize(n->nfile.fname);
8605 calcsize(n->nfile.next);
8606 break;
8607 case NTOFD:
8608 case NFROMFD:
8609 calcsize(n->ndup.vname);
8610 calcsize(n->ndup.next);
8611 break;
8612 case NHERE:
8613 case NXHERE:
8614 calcsize(n->nhere.doc);
8615 calcsize(n->nhere.next);
8616 break;
8617 case NNOT:
8618 calcsize(n->nnot.com);
8619 break;
8620 };
8621}
8622
8623static void
8624sizenodelist(struct nodelist *lp)
8625{
8626 while (lp) {
8627 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8628 calcsize(lp->n);
8629 lp = lp->next;
8630 }
8631}
8632
8633static union node *
8634copynode(union node *n)
8635{
8636 union node *new;
8637
8638 if (n == NULL)
8639 return NULL;
8640 new = funcblock;
8641 funcblock = (char *) funcblock + nodesize[n->type];
8642
8643 switch (n->type) {
8644 case NCMD:
8645 new->ncmd.redirect = copynode(n->ncmd.redirect);
8646 new->ncmd.args = copynode(n->ncmd.args);
8647 new->ncmd.assign = copynode(n->ncmd.assign);
8648 break;
8649 case NPIPE:
8650 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8651 new->npipe.backgnd = n->npipe.backgnd;
8652 break;
8653 case NREDIR:
8654 case NBACKGND:
8655 case NSUBSHELL:
8656 new->nredir.redirect = copynode(n->nredir.redirect);
8657 new->nredir.n = copynode(n->nredir.n);
8658 break;
8659 case NAND:
8660 case NOR:
8661 case NSEMI:
8662 case NWHILE:
8663 case NUNTIL:
8664 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8665 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8666 break;
8667 case NIF:
8668 new->nif.elsepart = copynode(n->nif.elsepart);
8669 new->nif.ifpart = copynode(n->nif.ifpart);
8670 new->nif.test = copynode(n->nif.test);
8671 break;
8672 case NFOR:
8673 new->nfor.var = nodeckstrdup(n->nfor.var);
8674 new->nfor.body = copynode(n->nfor.body);
8675 new->nfor.args = copynode(n->nfor.args);
8676 break;
8677 case NCASE:
8678 new->ncase.cases = copynode(n->ncase.cases);
8679 new->ncase.expr = copynode(n->ncase.expr);
8680 break;
8681 case NCLIST:
8682 new->nclist.body = copynode(n->nclist.body);
8683 new->nclist.pattern = copynode(n->nclist.pattern);
8684 new->nclist.next = copynode(n->nclist.next);
8685 break;
8686 case NDEFUN:
8687 case NARG:
8688 new->narg.backquote = copynodelist(n->narg.backquote);
8689 new->narg.text = nodeckstrdup(n->narg.text);
8690 new->narg.next = copynode(n->narg.next);
8691 break;
8692 case NTO:
8693 case NCLOBBER:
8694 case NFROM:
8695 case NFROMTO:
8696 case NAPPEND:
8697 new->nfile.fname = copynode(n->nfile.fname);
8698 new->nfile.fd = n->nfile.fd;
8699 new->nfile.next = copynode(n->nfile.next);
8700 break;
8701 case NTOFD:
8702 case NFROMFD:
8703 new->ndup.vname = copynode(n->ndup.vname);
8704 new->ndup.dupfd = n->ndup.dupfd;
8705 new->ndup.fd = n->ndup.fd;
8706 new->ndup.next = copynode(n->ndup.next);
8707 break;
8708 case NHERE:
8709 case NXHERE:
8710 new->nhere.doc = copynode(n->nhere.doc);
8711 new->nhere.fd = n->nhere.fd;
8712 new->nhere.next = copynode(n->nhere.next);
8713 break;
8714 case NNOT:
8715 new->nnot.com = copynode(n->nnot.com);
8716 break;
8717 };
8718 new->type = n->type;
8719 return new;
8720}
8721
8722static struct nodelist *
8723copynodelist(struct nodelist *lp)
8724{
8725 struct nodelist *start;
8726 struct nodelist **lpp;
8727
8728 lpp = &start;
8729 while (lp) {
8730 *lpp = funcblock;
8731 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8732 (*lpp)->n = copynode(lp->n);
8733 lp = lp->next;
8734 lpp = &(*lpp)->next;
8735 }
8736 *lpp = NULL;
8737 return start;
8738}
8739
8740static char *
8741nodeckstrdup(char *s)
8742{
8743 char *rtn = funcstring;
8744
8745 strcpy(funcstring, s);
8746 funcstring += strlen(s) + 1;
8747 return rtn;
8748}
8749
8750/* 8778/*
8751 * Controls whether the shell is interactive or not. 8779 * Controls whether the shell is interactive or not.
8752 */ 8780 */
@@ -8819,7 +8847,6 @@ minus_o(char *name, int val)
8819 optlist[i] ? "on" : "off"); 8847 optlist[i] ? "on" : "off");
8820} 8848}
8821 8849
8822
8823static void 8850static void
8824setoption(int flag, int val) 8851setoption(int flag, int val)
8825{ 8852{
@@ -11450,65 +11477,16 @@ exportcmd(int argc, char **argv)
11450} 11477}
11451 11478
11452/* 11479/*
11453 * Make a variable a local variable. When a variable is made local, it's 11480 * Delete a function if it exists.
11454 * value and flags are saved in a localvar structure. The saved values
11455 * will be restored when the shell function returns. We handle the name
11456 * "-" as a special case.
11457 */ 11481 */
11458static void 11482static void
11459mklocal(char *name) 11483unsetfunc(const char *name)
11460{
11461 struct localvar *lvp;
11462 struct var **vpp;
11463 struct var *vp;
11464
11465 INT_OFF;
11466 lvp = ckmalloc(sizeof(struct localvar));
11467 if (LONE_DASH(name)) {
11468 char *p;
11469 p = ckmalloc(sizeof(optlist));
11470 lvp->text = memcpy(p, optlist, sizeof(optlist));
11471 vp = NULL;
11472 } else {
11473 char *eq;
11474
11475 vpp = hashvar(name);
11476 vp = *findvar(vpp, name);
11477 eq = strchr(name, '=');
11478 if (vp == NULL) {
11479 if (eq)
11480 setvareq(name, VSTRFIXED);
11481 else
11482 setvar(name, NULL, VSTRFIXED);
11483 vp = *vpp; /* the new variable */
11484 lvp->flags = VUNSET;
11485 } else {
11486 lvp->text = vp->text;
11487 lvp->flags = vp->flags;
11488 vp->flags |= VSTRFIXED|VTEXTFIXED;
11489 if (eq)
11490 setvareq(name, 0);
11491 }
11492 }
11493 lvp->vp = vp;
11494 lvp->next = localvars;
11495 localvars = lvp;
11496 INT_ON;
11497}
11498
11499/*
11500 * The "local" command.
11501 */
11502static int
11503localcmd(int argc, char **argv)
11504{ 11484{
11505 char *name; 11485 struct tblentry *cmdp;
11506 11486
11507 argv = argptr; 11487 cmdp = cmdlookup(name, 0);
11508 while ((name = *argv++) != NULL) { 11488 if (cmdp!= NULL && cmdp->cmdtype == CMDFUNCTION)
11509 mklocal(name); 11489 delete_cmd_entry();
11510 }
11511 return 0;
11512} 11490}
11513 11491
11514/* 11492/*