ash: cleanup part 8
No binary (build failed)
—
(log yok)
| @@ -407,6 +407,7 @@ out2str(const char *p) | |
| /* ============ Parsing structures */ | |
| + | |
| #define NCMD 0 | |
| #define NPIPE 1 | |
| #define NREDIR 2 | |
| @@ -896,12 +897,7 @@ struct strlist { | |
| }; | |
| #if ENABLE_ASH_ALIAS | |
| - | #define ALIASINUSE 1 |
| - | #define ALIASDEAD 2 |
| struct alias; | |
| - | static int aliascmd(int, char **); |
| - | static int unaliascmd(int, char **); |
| - | static void printalias(const struct alias *); |
| #endif | |
| struct strpush { | |
| @@ -1485,7 +1481,7 @@ nextopt(const char *optstring) | |
| } | |
| - | /* ============ Variables */ |
| + | /* ============ Shell variables */ |
| /* flags */ | |
| #define VEXPORT 0x01 /* variable is exported */ | |
| @@ -1503,11 +1499,6 @@ nextopt(const char *optstring) | |
| # define VDYNAMIC 0 | |
| #endif | |
| - | #if ENABLE_LOCALE_SUPPORT |
| - | static void change_lc_all(const char *value); |
| - | static void change_lc_ctype(const char *value); |
| - | #endif |
| - | |
| static const char defpathvar[] = "PATH=/usr/local/bin:/usr/bin:/sbin:/bin"; | |
| #ifdef IFS_BROKEN | |
| static const char defifsvar[] = "IFS= \t\n"; | |
| @@ -1516,6 +1507,27 @@ static const char defifsvar[] = "IFS= \t\n"; | |
| static const char defifs[] = " \t\n"; | |
| #endif | |
| + | struct shparam { |
| + | int nparam; /* # of positional parameters (without $0) */ |
| + | unsigned char malloc; /* if parameter list dynamically allocated */ |
| + | char **p; /* parameter list */ |
| + | #if ENABLE_ASH_GETOPTS |
| + | int optind; /* next parameter to be processed by getopts */ |
| + | int optoff; /* used by getopts */ |
| + | #endif |
| + | }; |
| + | |
| + | static struct shparam shellparam; /* $@ current positional parameters */ |
| + | |
| + | #if ENABLE_ASH_GETOPTS |
| + | static void |
| + | getoptsreset(const char *value) |
| + | { |
| + | shellparam.optind = number(value); |
| + | shellparam.optoff = -1; |
| + | } |
| + | #endif |
| + | |
| struct var { | |
| struct var *next; /* next entry in hash list */ | |
| int flags; /* flags are defined above */ | |
| @@ -1532,46 +1544,45 @@ struct localvar { | |
| }; | |
| /* Forward decls for varinit[] */ | |
| + | #if ENABLE_LOCALE_SUPPORT |
| + | static void change_lc_all(const char *value); |
| + | static void change_lc_ctype(const char *value); |
| + | #endif |
| #if ENABLE_ASH_MAIL | |
| static void chkmail(void); | |
| static void changemail(const char *); | |
| #endif | |
| static void changepath(const char *); | |
| - | #if ENABLE_ASH_GETOPTS |
| - | static void getoptsreset(const char *); |
| - | #endif |
| #if ENABLE_ASH_RANDOM_SUPPORT | |
| static void change_random(const char *); | |
| #endif | |
| static struct var varinit[] = { | |
| #ifdef IFS_BROKEN | |
| - | { 0, VSTRFIXED|VTEXTFIXED, defifsvar, 0 }, |
| + | { NULL, VSTRFIXED|VTEXTFIXED, defifsvar, NULL }, |
| #else | |
| - | { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0", 0 }, |
| + | { NULL, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0", NULL }, |
| #endif | |
| - | |
| #if ENABLE_ASH_MAIL | |
| - | { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0", changemail }, |
| - | { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail }, |
| + | { NULL, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0", changemail }, |
| + | { NULL, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail }, |
| #endif | |
| - | |
| - | { 0, VSTRFIXED|VTEXTFIXED, defpathvar, changepath }, |
| - | { 0, VSTRFIXED|VTEXTFIXED, "PS1=$ ", 0 }, |
| - | { 0, VSTRFIXED|VTEXTFIXED, "PS2=> ", 0 }, |
| - | { 0, VSTRFIXED|VTEXTFIXED, "PS4=+ ", 0 }, |
| + | { NULL, VSTRFIXED|VTEXTFIXED, defpathvar, changepath }, |
| + | { NULL, VSTRFIXED|VTEXTFIXED, "PS1=$ ", NULL }, |
| + | { NULL, VSTRFIXED|VTEXTFIXED, "PS2=> ", NULL }, |
| + | { NULL, VSTRFIXED|VTEXTFIXED, "PS4=+ ", NULL }, |
| #if ENABLE_ASH_GETOPTS | |
| - | { 0, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset }, |
| + | { NULL, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset }, |
| #endif | |
| #if ENABLE_ASH_RANDOM_SUPPORT | |
| - | {0, VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random }, |
| + | { NULL, VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random }, |
| #endif | |
| #if ENABLE_LOCALE_SUPPORT | |
| - | {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL\0", change_lc_all }, |
| - | {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE\0", change_lc_ctype }, |
| + | { NULL, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL\0", change_lc_all }, |
| + | { NULL, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE\0", change_lc_ctype }, |
| #endif | |
| #if ENABLE_FEATURE_EDITING_SAVEHISTORY | |
| - | {0, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE\0", NULL }, |
| + | { NULL, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE\0", NULL }, |
| #endif | |
| }; | |
| @@ -1611,10 +1622,6 @@ static struct var varinit[] = { | |
| #define mpathset() ((vmpath.flags & VUNSET) == 0) | |
| - | static struct var **hashvar(const char *); |
| - | |
| - | static int loopnest; /* current loop nesting level */ |
| - | |
| /* | |
| * The parsefile structure pointed to by the global variable parsefile | |
| * contains information about the current file being read. | |
| @@ -1627,36 +1634,13 @@ struct redirtab { | |
| static struct redirtab *redirlist; | |
| static int nullredirs; | |
| - | |
| extern char **environ; | |
| - | |
| static int preverrout_fd; /* save fd2 before print debug if xflag is set. */ | |
| - | struct shparam { |
| - | int nparam; /* # of positional parameters (without $0) */ |
| - | unsigned char malloc; /* if parameter list dynamically allocated */ |
| - | char **p; /* parameter list */ |
| - | #if ENABLE_ASH_GETOPTS |
| - | int optind; /* next parameter to be processed by getopts */ |
| - | int optoff; /* used by getopts */ |
| - | #endif |
| - | }; |
| - | |
| - | static struct shparam shellparam; /* $@ current positional parameters */ |
| - | |
| #define VTABSIZE 39 | |
| static struct var *vartab[VTABSIZE]; | |
| - | #if ENABLE_ASH_GETOPTS |
| - | static void |
| - | getoptsreset(const char *value) |
| - | { |
| - | shellparam.optind = number(value); |
| - | shellparam.optoff = -1; |
| - | } |
| - | #endif |
| - | |
| #define is_name(c) ((c) == '_' || isalpha((unsigned char)(c))) | |
| #define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c))) | |
| @@ -2397,6 +2381,7 @@ static int casematch(union node *, char *); | |
| static void expari(int); | |
| #endif | |
| + | |
| /* parser.h */ | |
| /* control characters in argument strings */ | |
| @@ -2452,7 +2437,6 @@ static char *parsenextc; /* copy of parsefile->nextc */ | |
| #define basebuf bb_common_bufsiz1 /* buffer for top level input file */ | |
| - | |
| static int tokpushback; /* last token pushed back */ | |
| #define NEOF ((union node *)&tokpushback) | |
| static int parsebackquote; /* nonzero if we are inside backquotes */ | |
| @@ -2465,7 +2449,7 @@ static struct heredoc *heredoc; | |
| static int quoteflag; /* set if (part of) last token was quoted */ | |
| static void fixredir(union node *, const char *, int); | |
| - | static char *endofname(const char *); |
| + | |
| /* shell.h */ | |
| @@ -2478,7 +2462,6 @@ static const char dolatstr[] = { CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' }; | |
| #define xlikely(x) __builtin_expect((x),1) | |
| - | |
| #define TEOF 0 | |
| #define TNL 1 | |
| #define TREDIR 2 | |
| @@ -2610,12 +2593,6 @@ findkwd(const char *s) | |
| ( (((unsigned int)c) - 33 < 32) \ | |
| && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1)) | |
| - | #define digit_val(c) ((c) - '0') |
| - | |
| - | /* |
| - | * This file was generated by the mksyntax program. |
| - | */ |
| - | |
| #if ENABLE_ASH_OPTIMIZE_FOR_SIZE | |
| #define USE_SIT_FUNCTION | |
| #endif | |
| @@ -3019,15 +2996,15 @@ static const char syntax_index_table[258] = { | |
| #endif /* USE_SIT_FUNCTION */ | |
| - | /* alias.c */ |
| + | /* alias.c */ |
| #define ATABSIZE 39 | |
| - | static int funcblocksize; /* size of structures in function */ |
| - | static int funcstringsize; /* size of strings in node */ |
| - | static void *funcblock; /* block to allocate function from */ |
| - | static char *funcstring; /* block to allocate strings from */ |
| + | static int funcblocksize; /* size of structures in function */ |
| + | static int funcstringsize; /* size of strings in node */ |
| + | static void *funcblock; /* block to allocate function from */ |
| + | static char *funcstring; /* block to allocate strings from */ |
| static const short nodesize[26] = { | |
| SHELL_ALIGN(sizeof(struct ncmd)), | |
| @@ -3058,14 +3035,12 @@ static const short nodesize[26] = { | |
| SHELL_ALIGN(sizeof(struct nnot)), | |
| }; | |
| - | |
| static void calcsize(union node *); | |
| static void sizenodelist(struct nodelist *); | |
| static union node *copynode(union node *); | |
| static struct nodelist *copynodelist(struct nodelist *); | |
| static char *nodeckstrdup(char *); | |
| - | |
| static int evalskip; /* set if we are skipping commands */ | |
| static int skipcount; /* number of levels to skip */ | |
| static int funcnest; /* depth of function calls */ | |
| @@ -3077,60 +3052,6 @@ static int funcnest; /* depth of function calls */ | |
| #define SKIPFILE (1 << 3) | |
| #define SKIPEVAL (1 << 4) | |
| - | /* |
| - | * This file was generated by the mkbuiltins program. |
| - | */ |
| - | |
| - | #if JOBS |
| - | static int fg_bgcmd(int, char **); |
| - | #endif |
| - | static int breakcmd(int, char **); |
| - | static int cdcmd(int, char **); |
| - | #if ENABLE_ASH_CMDCMD |
| - | static int commandcmd(int, char **); |
| - | #endif |
| - | static int dotcmd(int, char **); |
| - | static int evalcmd(int, char **); |
| - | #if ENABLE_ASH_BUILTIN_ECHO |
| - | static int echocmd(int, char **); |
| - | #endif |
| - | #if ENABLE_ASH_BUILTIN_TEST |
| - | static int testcmd(int, char **); |
| - | #endif |
| - | static int execcmd(int, char **); |
| - | static int exitcmd(int, char **); |
| - | static int exportcmd(int, char **); |
| - | static int falsecmd(int, char **); |
| - | #if ENABLE_ASH_GETOPTS |
| - | static int getoptscmd(int, char **); |
| - | #endif |
| - | static int hashcmd(int, char **); |
| - | #if !ENABLE_FEATURE_SH_EXTRA_QUIET |
| - | static int helpcmd(int argc, char **argv); |
| - | #endif |
| - | #if JOBS |
| - | static int jobscmd(int, char **); |
| - | #endif |
| - | #if ENABLE_ASH_MATH_SUPPORT |
| - | static int letcmd(int, char **); |
| - | #endif |
| - | static int localcmd(int, char **); |
| - | static int pwdcmd(int, char **); |
| - | static int readcmd(int, char **); |
| - | static int returncmd(int, char **); |
| - | static int setcmd(int, char **); |
| - | static int shiftcmd(int, char **); |
| - | static int timescmd(int, char **); |
| - | static int trapcmd(int, char **); |
| - | static int truecmd(int, char **); |
| - | static int typecmd(int, char **); |
| - | static int umaskcmd(int, char **); |
| - | static int unsetcmd(int, char **); |
| - | static int waitcmd(int, char **); |
| - | static int ulimitcmd(int, char **); |
| - | #if JOBS |
| - | static int killcmd(int, char **); |
| - | #endif |
| /* exec.h */ | |
| @@ -3189,30 +3110,9 @@ static unsigned long rseed; | |
| # endif | |
| #endif | |
| - | /* PEOF (the end of file marker) */ |
| - | |
| - | enum { |
| - | INPUT_PUSH_FILE = 1, |
| - | INPUT_NOFILE_OK = 2, |
| - | }; |
| - | |
| - | /* |
| - | * The input line number. Input.c just defines this variable, and saves |
| - | * and restores it when files are pushed and popped. The user of this |
| - | * package must set its value. |
| - | */ |
| - | static void pungetc(void); |
| - | static void pushstring(char *, void *); |
| - | static void popstring(void); |
| - | static void setinputfd(int, int); |
| - | static void setinputstring(char *); |
| - | static void popfile(void); |
| - | static void popallfiles(void); |
| - | static void closescript(void); |
| /* jobs.h */ | |
| - | |
| /* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */ | |
| #define FORK_FG 0 | |
| #define FORK_BG 1 | |
| @@ -3286,7 +3186,6 @@ static void readcmdfile(char *); | |
| static char *minusc; /* argument to -c option */ | |
| - | |
| static void optschanged(void); | |
| static void setparam(char **); | |
| static void freeparam(volatile struct shparam *); | |
| @@ -3350,7 +3249,12 @@ static int is_safe_applet(char *name) | |
| } | |
| + | /* ============ Alias handling */ |
| #if ENABLE_ASH_ALIAS | |
| + | |
| + | #define ALIASINUSE 1 |
| + | #define ALIASDEAD 2 |
| + | |
| struct alias { | |
| struct alias *next; | |
| char *name; | |
| @@ -3475,6 +3379,12 @@ rmaliases(void) | |
| INT_ON; | |
| } | |
| + | static void |
| + | printalias(const struct alias *ap) |
| + | { |
| + | out1fmt("%s=%s\n", ap->name, single_quote(ap->val)); |
| + | } |
| + | |
| /* | |
| * TODO - sort output | |
| */ | |
| @@ -3532,25 +3442,17 @@ unaliascmd(int argc, char **argv) | |
| return i; | |
| } | |
| - | |
| - | static void |
| - | printalias(const struct alias *ap) |
| - | { |
| - | out1fmt("%s=%s\n", ap->name, single_quote(ap->val)); |
| - | } |
| #endif /* ASH_ALIAS */ | |
| - | /* eval.c */ |
| - | /* |
| - | * Evaluate a command. |
| - | */ |
| + | /* ============ eval.c */ |
| /* flags in argument to evaltree */ | |
| #define EV_EXIT 01 /* exit after evaluating tree */ | |
| #define EV_TESTED 02 /* exit status is checked; ignore -e flag */ | |
| #define EV_BACKCMD 04 /* command executing within back quotes */ | |
| + | /* forward declarations - evaluation is faily recursive business... */ |
| static void evalloop(union node *, int); | |
| static void evalfor(union node *, int); | |
| static void evalcase(union node *, int); | |
| @@ -3679,12 +3581,12 @@ evaltree(union node *n, int flags) | |
| } | |
| } | |
| - | |
| #if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3) | |
| static | |
| #endif | |
| void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__)); | |
| + | static int loopnest; /* current loop nesting level */ |
| static void | |
| evalloop(union node *n, int flags) | |
| @@ -3722,7 +3624,6 @@ evalloop(union node *n, int flags) | |
| exitstatus = status; | |
| } | |
| - | |
| static void | |
| evalfor(union node *n, int flags) | |
| { | |
| @@ -3762,7 +3663,6 @@ evalfor(union node *n, int flags) | |
| popstackmark(&smark); | |
| } | |
| - | |
| static void | |
| evalcase(union node *n, int flags) | |
| { | |
| @@ -3789,7 +3689,6 @@ evalcase(union node *n, int flags) | |
| popstackmark(&smark); | |
| } | |
| - | |
| /* | |
| * Kick off a subshell to evaluate a tree. | |
| */ | |
| @@ -3822,7 +3721,6 @@ evalsubshell(union node *n, int flags) | |
| INT_ON; | |
| } | |
| - | |
| /* | |
| * Compute the names of the files in a redirection list. | |
| */ | |
| @@ -3858,7 +3756,6 @@ expredir(union node *n) | |
| } | |
| } | |
| - | |
| /* | |
| * Evaluate a pipeline. All the processes in the pipeline are children | |
| * of the process creating the pipeline. (This differs from some versions | |
| @@ -3919,7 +3816,6 @@ evalpipe(union node *n, int flags) | |
| INT_ON; | |
| } | |
| - | |
| #if ENABLE_ASH_CMDCMD | |
| static char ** | |
| parse_command_args(char **argv, const char **path) | |
| @@ -3955,6 +3851,57 @@ parse_command_args(char **argv, const char **path) | |
| } | |
| #endif | |
| + | /* Forward declarations for builtintab[] */ |
| + | #if JOBS |
| + | static int fg_bgcmd(int, char **); |
| + | #endif |
| + | static int breakcmd(int, char **); |
| + | #if ENABLE_ASH_CMDCMD |
| + | static int commandcmd(int, char **); |
| + | #endif |
| + | static int dotcmd(int, char **); |
| + | static int evalcmd(int, char **); |
| + | #if ENABLE_ASH_BUILTIN_ECHO |
| + | static int echocmd(int, char **); |
| + | #endif |
| + | #if ENABLE_ASH_BUILTIN_TEST |
| + | static int testcmd(int, char **); |
| + | #endif |
| + | static int execcmd(int, char **); |
| + | static int exitcmd(int, char **); |
| + | static int exportcmd(int, char **); |
| + | static int falsecmd(int, char **); |
| + | #if ENABLE_ASH_GETOPTS |
| + | static int getoptscmd(int, char **); |
| + | #endif |
| + | static int hashcmd(int, char **); |
| + | #if !ENABLE_FEATURE_SH_EXTRA_QUIET |
| + | static int helpcmd(int argc, char **argv); |
| + | #endif |
| + | #if JOBS |
| + | static int jobscmd(int, char **); |
| + | #endif |
| + | #if ENABLE_ASH_MATH_SUPPORT |
| + | static int letcmd(int, char **); |
| + | #endif |
| + | static int localcmd(int, char **); |
| + | static int pwdcmd(int, char **); |
| + | static int readcmd(int, char **); |
| + | static int returncmd(int, char **); |
| + | static int setcmd(int, char **); |
| + | static int shiftcmd(int, char **); |
| + | static int timescmd(int, char **); |
| + | static int trapcmd(int, char **); |
| + | static int truecmd(int, char **); |
| + | static int typecmd(int, char **); |
| + | static int umaskcmd(int, char **); |
| + | static int unsetcmd(int, char **); |
| + | static int waitcmd(int, char **); |
| + | static int ulimitcmd(int, char **); |
| + | #if JOBS |
| + | static int killcmd(int, char **); |
| + | #endif |
| + | |
| #define BUILTIN_NOSPEC "0" | |
| #define BUILTIN_SPECIAL "1" | |
| #define BUILTIN_REGULAR "2" | |
| @@ -4514,7 +4461,7 @@ execcmd(int argc, char **argv) | |
| } | |
| - | /* exec.c */ |
| + | /* ============ Executing commands */ |
| /* | |
| * When commands are first encountered, they are entered in a hash table. | |
| @@ -4528,7 +4475,6 @@ execcmd(int argc, char **argv) | |
| #define CMDTABLESIZE 31 /* should be prime */ | |
| #define ARB 1 /* actual size determined at run time */ | |
| - | |
| struct tblentry { | |
| struct tblentry *next; /* next entry in hash chain */ | |
| union param param; /* definition of builtin function */ | |
| @@ -4537,38 +4483,86 @@ struct tblentry { | |
| char cmdname[ARB]; /* name of command */ | |
| }; | |
| - | |
| static struct tblentry *cmdtable[CMDTABLESIZE]; | |
| static int builtinloc = -1; /* index in path of %builtin, or -1 */ | |
| - | |
| - | static void tryexec(char *, char **, char **); |
| - | static void clearcmdentry(int); |
| - | static struct tblentry *cmdlookup(const char *, int); |
| - | static void delete_cmd_entry(void); |
| - | |
| - | |
| - | /* |
| - | * Exec a program. Never returns. If you change this routine, you may |
| - | * have to change the find_command routine as well. |
| - | */ |
| - | #define environment() listvars(VEXPORT, VUNSET, 0) |
| - | static void shellexec(char **, const char *, int) ATTRIBUTE_NORETURN; |
| static void | |
| - | shellexec(char **argv, const char *path, int idx) |
| + | tryexec(char *cmd, char **argv, char **envp) |
| { | |
| - | char *cmdname; |
| - | int e; |
| - | char **envp; |
| - | int exerrno; |
| + | int repeated = 0; |
| + | struct BB_applet *a; |
| + | int argc = 0; |
| + | char **c; |
| - | clearredir(1); |
| - | envp = environment(); |
| - | if (strchr(argv[0], '/') || is_safe_applet(argv[0]) |
| + | if (strchr(cmd, '/') == NULL |
| + | && (a = find_applet_by_name(cmd)) != NULL |
| + | && is_safe_applet(cmd) |
| + | ) { |
| + | c = argv; |
| + | while (*c != NULL) { |
| + | c++; argc++; |
| + | } |
| + | applet_name = cmd; |
| + | exit(a->main(argc, argv)); |
| + | } |
| #if ENABLE_FEATURE_SH_STANDALONE_SHELL | |
| - | || find_applet_by_name(argv[0]) |
| + | if (find_applet_by_name(cmd) != NULL) { |
| + | /* re-exec ourselves with the new arguments */ |
| + | execve(CONFIG_BUSYBOX_EXEC_PATH, argv, envp); |
| + | /* If they called chroot or otherwise made the binary no longer |
| + | * executable, fall through */ |
| + | } |
| #endif | |
| - | ) { |
| + | |
| + | repeat: |
| + | #ifdef SYSV |
| + | do { |
| + | execve(cmd, argv, envp); |
| + | } while (errno == EINTR); |
| + | #else |
| + | execve(cmd, argv, envp); |
| + | #endif |
| + | if (repeated++) { |
| + | free(argv); |
| + | } else if (errno == ENOEXEC) { |
| + | char **ap; |
| + | char **new; |
| + | |
| + | for (ap = argv; *ap; ap++) |
| + | ; |
| + | ap = new = ckmalloc((ap - argv + 2) * sizeof(char *)); |
| + | ap[1] = cmd; |
| + | *ap = cmd = (char *)DEFAULT_SHELL; |
| + | ap += 2; |
| + | argv++; |
| + | while ((*ap++ = *argv++)) |
| + | ; |
| + | argv = new; |
| + | goto repeat; |
| + | } |
| + | } |
| + | |
| + | /* |
| + | * Exec a program. Never returns. If you change this routine, you may |
| + | * have to change the find_command routine as well. |
| + | */ |
| + | #define environment() listvars(VEXPORT, VUNSET, 0) |
| + | static void shellexec(char **, const char *, int) ATTRIBUTE_NORETURN; |
| + | static void |
| + | shellexec(char **argv, const char *path, int idx) |
| + | { |
| + | char *cmdname; |
| + | int e; |
| + | char **envp; |
| + | int exerrno; |
| + | |
| + | clearredir(1); |
| + | envp = environment(); |
| + | if (strchr(argv[0], '/') || is_safe_applet(argv[0]) |
| + | #if ENABLE_FEATURE_SH_STANDALONE_SHELL |
| + | || find_applet_by_name(argv[0]) |
| + | #endif |
| + | ) { |
| tryexec(argv[0], argv, envp); | |
| e = errno; | |
| } else { | |
| @@ -4602,83 +4596,128 @@ shellexec(char **argv, const char *path, int idx) | |
| /* NOTREACHED */ | |
| } | |
| + | static void |
| + | printentry(struct tblentry *cmdp) |
| + | { |
| + | int idx; |
| + | const char *path; |
| + | char *name; |
| + | |
| + | idx = cmdp->param.index; |
| + | path = pathval(); |
| + | do { |
| + | name = padvance(&path, cmdp->cmdname); |
| + | stunalloc(name); |
| + | } while (--idx >= 0); |
| + | out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr)); |
| + | } |
| + | /* |
| + | * Clear out command entries. The argument specifies the first entry in |
| + | * PATH which has changed. |
| + | */ |
| static void | |
| - | tryexec(char *cmd, char **argv, char **envp) |
| + | clearcmdentry(int firstchange) |
| { | |
| - | int repeated = 0; |
| - | struct BB_applet *a; |
| - | int argc = 0; |
| - | char **c; |
| + | struct tblentry **tblp; |
| + | struct tblentry **pp; |
| + | struct tblentry *cmdp; |
| - | if (strchr(cmd, '/') == NULL |
| - | && (a = find_applet_by_name(cmd)) != NULL |
| - | && is_safe_applet(cmd) |
| - | ) { |
| - | c = argv; |
| - | while (*c != NULL) { |
| - | c++; argc++; |
| + | INT_OFF; |
| + | for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) { |
| + | pp = tblp; |
| + | while ((cmdp = *pp) != NULL) { |
| + | if ((cmdp->cmdtype == CMDNORMAL && |
| + | cmdp->param.index >= firstchange) |
| + | || (cmdp->cmdtype == CMDBUILTIN && |
| + | builtinloc >= firstchange) |
| + | ) { |
| + | *pp = cmdp->next; |
| + | free(cmdp); |
| + | } else { |
| + | pp = &cmdp->next; |
| + | } |
| } | |
| - | applet_name = cmd; |
| - | exit(a->main(argc, argv)); |
| - | } |
| - | #if ENABLE_FEATURE_SH_STANDALONE_SHELL |
| - | if (find_applet_by_name(cmd) != NULL) { |
| - | /* re-exec ourselves with the new arguments */ |
| - | execve(CONFIG_BUSYBOX_EXEC_PATH, argv, envp); |
| - | /* If they called chroot or otherwise made the binary no longer |
| - | * executable, fall through */ |
| } | |
| - | #endif |
| + | INT_ON; |
| + | } |
| - | repeat: |
| - | #ifdef SYSV |
| - | do { |
| - | execve(cmd, argv, envp); |
| - | } while (errno == EINTR); |
| - | #else |
| - | execve(cmd, argv, envp); |
| - | #endif |
| - | if (repeated++) { |
| - | free(argv); |
| - | } else if (errno == ENOEXEC) { |
| - | char **ap; |
| - | char **new; |
| + | /* |
| + | * Locate a command in the command hash table. If "add" is nonzero, |
| + | * add the command to the table if it is not already present. The |
| + | * variable "lastcmdentry" is set to point to the address of the link |
| + | * pointing to the entry, so that delete_cmd_entry can delete the |
| + | * entry. |
| + | * |
| + | * Interrupts must be off if called with add != 0. |
| + | */ |
| + | static struct tblentry **lastcmdentry; |
| - | for (ap = argv; *ap; ap++) |
| - | ; |
| - | ap = new = ckmalloc((ap - argv + 2) * sizeof(char *)); |
| - | ap[1] = cmd; |
| - | *ap = cmd = (char *)DEFAULT_SHELL; |
| - | ap += 2; |
| - | argv++; |
| - | while ((*ap++ = *argv++)) |
| - | ; |
| - | argv = new; |
| - | goto repeat; |
| + | static struct tblentry * |
| + | cmdlookup(const char *name, int add) |
| + | { |
| + | unsigned int hashval; |
| + | const char *p; |
| + | struct tblentry *cmdp; |
| + | struct tblentry **pp; |
| + | |
| + | p = name; |
| + | hashval = (unsigned char)*p << 4; |
| + | while (*p) |
| + | hashval += (unsigned char)*p++; |
| + | hashval &= 0x7FFF; |
| + | pp = &cmdtable[hashval % CMDTABLESIZE]; |
| + | for (cmdp = *pp; cmdp; cmdp = cmdp->next) { |
| + | if (strcmp(cmdp->cmdname, name) == 0) |
| + | break; |
| + | pp = &cmdp->next; |
| + | } |
| + | if (add && cmdp == NULL) { |
| + | cmdp = *pp = ckmalloc(sizeof(struct tblentry) - ARB |
| + | + strlen(name) + 1); |
| + | cmdp->next = NULL; |
| + | cmdp->cmdtype = CMDUNKNOWN; |
| + | strcpy(cmdp->cmdname, name); |
| } | |
| + | lastcmdentry = pp; |
| + | return cmdp; |
| } | |
| + | /* |
| + | * Delete the command entry returned on the last lookup. |
| + | */ |
| + | static void |
| + | delete_cmd_entry(void) |
| + | { |
| + | struct tblentry *cmdp; |
| - | /*** Command hashing code ***/ |
| + | INT_OFF; |
| + | cmdp = *lastcmdentry; |
| + | *lastcmdentry = cmdp->next; |
| + | if (cmdp->cmdtype == CMDFUNCTION) |
| + | freefunc(cmdp->param.func); |
| + | free(cmdp); |
| + | INT_ON; |
| + | } |
| + | /* |
| + | * Add a new command entry, replacing any existing command entry for |
| + | * the same name - except special builtins. |
| + | */ |
| static void | |
| - | printentry(struct tblentry *cmdp) |
| + | addcmdentry(char *name, struct cmdentry *entry) |
| { | |
| - | int idx; |
| - | const char *path; |
| - | char *name; |
| + | struct tblentry *cmdp; |
| - | idx = cmdp->param.index; |
| - | path = pathval(); |
| - | do { |
| - | name = padvance(&path, cmdp->cmdname); |
| - | stunalloc(name); |
| - | } while (--idx >= 0); |
| - | out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr)); |
| + | cmdp = cmdlookup(name, 1); |
| + | if (cmdp->cmdtype == CMDFUNCTION) { |
| + | freefunc(cmdp->param.func); |
| + | } |
| + | cmdp->cmdtype = entry->cmdtype; |
| + | cmdp->param = entry->u; |
| + | cmdp->rehash = 0; |
| } | |
| - | |
| static int | |
| hashcmd(int argc, char **argv) | |
| { | |
| @@ -4716,7 +4755,6 @@ hashcmd(int argc, char **argv) | |
| return c; | |
| } | |
| - | |
| /* | |
| * Resolve a command name. If you change this routine, you may have to | |
| * change the shellexec routine as well. | |
| @@ -4901,7 +4939,6 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |
| entry->u = cmdp->param; | |
| } | |
| - | |
| /* | |
| * Search the table of builtin commands. | |
| */ | |
| @@ -4917,7 +4954,6 @@ find_builtin(const char *name) | |
| return bp; | |
| } | |
| - | |
| /* | |
| * Called when a cd is done. Marks all commands so the next time they | |
| * are executed they will be rehashed. | |
| @@ -4940,7 +4976,6 @@ hashcd(void) | |
| } | |
| } | |
| - | |
| /* | |
| * Fix command hash table when PATH changed. | |
| * Called before PATH is changed. The argument is the new value of PATH; | |
| @@ -4986,116 +5021,6 @@ changepath(const char *newval) | |
| } | |
| - | /* |
| - | * Clear out command entries. The argument specifies the first entry in |
| - | * PATH which has changed. |
| - | */ |
| - | static void |
| - | clearcmdentry(int firstchange) |
| - | { |
| - | struct tblentry **tblp; |
| - | struct tblentry **pp; |
| - | struct tblentry *cmdp; |
| - | |
| - | INT_OFF; |
| - | for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) { |
| - | pp = tblp; |
| - | while ((cmdp = *pp) != NULL) { |
| - | if ((cmdp->cmdtype == CMDNORMAL && |
| - | cmdp->param.index >= firstchange) |
| - | || (cmdp->cmdtype == CMDBUILTIN && |
| - | builtinloc >= firstchange) |
| - | ) { |
| - | *pp = cmdp->next; |
| - | free(cmdp); |
| - | } else { |
| - | pp = &cmdp->next; |
| - | } |
| - | } |
| - | } |
| - | INT_ON; |
| - | } |
| - | |
| - | |
| - | /* |
| - | * Locate a command in the command hash table. If "add" is nonzero, |
| - | * add the command to the table if it is not already present. The |
| - | * variable "lastcmdentry" is set to point to the address of the link |
| - | * pointing to the entry, so that delete_cmd_entry can delete the |
| - | * entry. |
| - | * |
| - | * Interrupts must be off if called with add != 0. |
| - | */ |
| - | static struct tblentry **lastcmdentry; |
| - | |
| - | static struct tblentry * |
| - | cmdlookup(const char *name, int add) |
| - | { |
| - | unsigned int hashval; |
| - | const char *p; |
| - | struct tblentry *cmdp; |
| - | struct tblentry **pp; |
| - | |
| - | p = name; |
| - | hashval = (unsigned char)*p << 4; |
| - | while (*p) |
| - | hashval += (unsigned char)*p++; |
| - | hashval &= 0x7FFF; |
| - | pp = &cmdtable[hashval % CMDTABLESIZE]; |
| - | for (cmdp = *pp; cmdp; cmdp = cmdp->next) { |
| - | if (strcmp(cmdp->cmdname, name) == 0) |
| - | break; |
| - | pp = &cmdp->next; |
| - | } |
| - | if (add && cmdp == NULL) { |
| - | cmdp = *pp = ckmalloc(sizeof(struct tblentry) - ARB |
| - | + strlen(name) + 1); |
| - | cmdp->next = NULL; |
| - | cmdp->cmdtype = CMDUNKNOWN; |
| - | strcpy(cmdp->cmdname, name); |
| - | } |
| - | lastcmdentry = pp; |
| - | return cmdp; |
| - | } |
| - | |
| - | |
| - | /* |
| - | * Delete the command entry returned on the last lookup. |
| - | */ |
| - | static void |
| - | delete_cmd_entry(void) |
| - | { |
| - | struct tblentry *cmdp; |
| - | |
| - | INT_OFF; |
| - | cmdp = *lastcmdentry; |
| - | *lastcmdentry = cmdp->next; |
| - | if (cmdp->cmdtype == CMDFUNCTION) |
| - | freefunc(cmdp->param.func); |
| - | free(cmdp); |
| - | INT_ON; |
| - | } |
| - | |
| - | |
| - | /* |
| - | * Add a new command entry, replacing any existing command entry for |
| - | * the same name - except special builtins. |
| - | */ |
| - | static void |
| - | addcmdentry(char *name, struct cmdentry *entry) |
| - | { |
| - | struct tblentry *cmdp; |
| - | |
| - | cmdp = cmdlookup(name, 1); |
| - | if (cmdp->cmdtype == CMDFUNCTION) { |
| - | freefunc(cmdp->param.func); |
| - | } |
| - | cmdp->cmdtype = entry->cmdtype; |
| - | cmdp->param = entry->u; |
| - | cmdp->rehash = 0; |
| - | } |
| - | |
| - | |
| /* | |
| * Make a copy of a parse tree. | |
| */ | |
| @@ -5145,6 +5070,7 @@ unsetfunc(const char *name) | |
| delete_cmd_entry(); | |
| } | |
| + | |
| /* | |
| * Locate and print what a word is... | |
| */ | |
| @@ -6804,94 +6730,45 @@ varunset(const char *end, const char *var, const char *umsg, int varflags) | |
| } | |
| - | /* input.c */ |
| - | |
| - | /* |
| + | /* ============ input.c |
| + | * |
| * This implements the input routines used by the parser. | |
| */ | |
| - | |
| #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */ | |
| - | static void pushfile(void); |
| - | |
| - | /* |
| - | * Read a character from the script, returning PEOF on end of file. |
| - | * Nul characters in the input are silently discarded. |
| - | */ |
| - | static int preadbuffer(void); |
| - | #define pgetc_as_macro() (--parsenleft >= 0? SC2INT(*parsenextc++) : preadbuffer()) |
| + | enum { |
| + | INPUT_PUSH_FILE = 1, |
| + | INPUT_NOFILE_OK = 2, |
| + | }; |
| - | #if ENABLE_ASH_OPTIMIZE_FOR_SIZE |
| - | #define pgetc_macro() pgetc() |
| - | static int |
| - | pgetc(void) |
| - | { |
| - | return pgetc_as_macro(); |
| - | } |
| - | #else |
| - | #define pgetc_macro() pgetc_as_macro() |
| - | static int |
| - | pgetc(void) |
| + | static void |
| + | popstring(void) |
| { | |
| - | return pgetc_macro(); |
| - | } |
| - | #endif |
| + | struct strpush *sp = parsefile->strpush; |
| - | /* |
| - | * Same as pgetc(), but ignores PEOA. |
| - | */ |
| + | INT_OFF; |
| #if ENABLE_ASH_ALIAS | |
| - | static int |
| - | pgetc2(void) |
| - | { |
| - | int c; |
| - | |
| - | do { |
| - | c = pgetc_macro(); |
| - | } while (c == PEOA); |
| - | return c; |
| - | } |
| - | #else |
| - | static int |
| - | pgetc2(void) |
| - | { |
| - | return pgetc_macro(); |
| - | } |
| - | #endif |
| - | |
| - | /* |
| - | * Read a line from the script. |
| - | */ |
| - | static char * |
| - | pfgets(char *line, int len) |
| - | { |
| - | char *p = line; |
| - | int nleft = len; |
| - | int c; |
| - | |
| - | while (--nleft > 0) { |
| - | c = pgetc2(); |
| - | if (c == PEOF) { |
| - | if (p == line) |
| - | return NULL; |
| - | break; |
| - | } |
| - | *p++ = c; |
| - | if (c == '\n') |
| - | break; |
| - | } |
| - | *p = '\0'; |
| - | return line; |
| - | } |
| - | |
| - | #if ENABLE_FEATURE_EDITING_VI |
| - | #define setvimode(on) do { \ |
| - | if (on) line_input_state->flags |= VI_MODE; \ |
| - | else line_input_state->flags &= ~VI_MODE; \ |
| - | } while (0) |
| - | #else |
| - | #define setvimode(on) viflag = 0 /* forcibly keep the option off */ |
| + | if (sp->ap) { |
| + | if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') { |
| + | checkkwd |= CHKALIAS; |
| + | } |
| + | if (sp->string != sp->ap->val) { |
| + | free(sp->string); |
| + | } |
| + | sp->ap->flag &= ~ALIASINUSE; |
| + | if (sp->ap->flag & ALIASDEAD) { |
| + | unalias(sp->ap->name); |
| + | } |
| + | } |
| #endif | |
| + | parsenextc = sp->prevstring; |
| + | parsenleft = sp->prevnleft; |
| + | /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/ |
| + | parsefile->strpush = sp->prev; |
| + | if (sp != &(parsefile->basestrpush)) |
| + | free(sp); |
| + | INT_ON; |
| + | } |
| static int | |
| preadfd(void) | |
| @@ -7024,6 +6901,72 @@ preadbuffer(void) | |
| return SC2INT(*parsenextc++); | |
| } | |
| + | |
| + | #define pgetc_as_macro() (--parsenleft >= 0? SC2INT(*parsenextc++) : preadbuffer()) |
| + | |
| + | #if ENABLE_ASH_OPTIMIZE_FOR_SIZE |
| + | #define pgetc_macro() pgetc() |
| + | static int |
| + | pgetc(void) |
| + | { |
| + | return pgetc_as_macro(); |
| + | } |
| + | #else |
| + | #define pgetc_macro() pgetc_as_macro() |
| + | static int |
| + | pgetc(void) |
| + | { |
| + | return pgetc_macro(); |
| + | } |
| + | #endif |
| + | |
| + | /* |
| + | * Same as pgetc(), but ignores PEOA. |
| + | */ |
| + | #if ENABLE_ASH_ALIAS |
| + | static int |
| + | pgetc2(void) |
| + | { |
| + | int c; |
| + | |
| + | do { |
| + | c = pgetc_macro(); |
| + | } while (c == PEOA); |
| + | return c; |
| + | } |
| + | #else |
| + | static int |
| + | pgetc2(void) |
| + | { |
| + | return pgetc_macro(); |
| + | } |
| + | #endif |
| + | |
| + | /* |
| + | * Read a line from the script. |
| + | */ |
| + | static char * |
| + | pfgets(char *line, int len) |
| + | { |
| + | char *p = line; |
| + | int nleft = len; |
| + | int c; |
| + | |
| + | while (--nleft > 0) { |
| + | c = pgetc2(); |
| + | if (c == PEOF) { |
| + | if (p == line) |
| + | return NULL; |
| + | break; |
| + | } |
| + | *p++ = c; |
| + | if (c == '\n') |
| + | break; |
| + | } |
| + | *p = '\0'; |
| + | return line; |
| + | } |
| + | |
| /* | |
| * Undo the last call to pgetc. Only one character may be pushed back. | |
| * PEOF may be pushed back. | |
| @@ -7068,103 +7011,6 @@ pushstring(char *s, void *ap) | |
| INT_ON; | |
| } | |
| - | static void |
| - | popstring(void) |
| - | { |
| - | struct strpush *sp = parsefile->strpush; |
| - | |
| - | INT_OFF; |
| - | #if ENABLE_ASH_ALIAS |
| - | if (sp->ap) { |
| - | if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') { |
| - | checkkwd |= CHKALIAS; |
| - | } |
| - | if (sp->string != sp->ap->val) { |
| - | free(sp->string); |
| - | } |
| - | sp->ap->flag &= ~ALIASINUSE; |
| - | if (sp->ap->flag & ALIASDEAD) { |
| - | unalias(sp->ap->name); |
| - | } |
| - | } |
| - | #endif |
| - | parsenextc = sp->prevstring; |
| - | parsenleft = sp->prevnleft; |
| - | /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/ |
| - | parsefile->strpush = sp->prev; |
| - | if (sp != &(parsefile->basestrpush)) |
| - | free(sp); |
| - | INT_ON; |
| - | } |
| - | |
| - | |
| - | /* |
| - | * Set the input to take input from a file. If push is set, push the |
| - | * old input onto the stack first. |
| - | */ |
| - | static int |
| - | setinputfile(const char *fname, int flags) |
| - | { |
| - | int fd; |
| - | int fd2; |
| - | |
| - | INT_OFF; |
| - | fd = open(fname, O_RDONLY); |
| - | if (fd < 0) { |
| - | if (flags & INPUT_NOFILE_OK) |
| - | goto out; |
| - | ash_msg_and_raise_error("Can't open %s", fname); |
| - | } |
| - | if (fd < 10) { |
| - | fd2 = copyfd(fd, 10); |
| - | close(fd); |
| - | if (fd2 < 0) |
| - | ash_msg_and_raise_error("Out of file descriptors"); |
| - | fd = fd2; |
| - | } |
| - | setinputfd(fd, flags & INPUT_PUSH_FILE); |
| - | out: |
| - | INT_ON; |
| - | return fd; |
| - | } |
| - | |
| - | |
| - | /* |
| - | * Like setinputfile, but takes an open file descriptor. Call this with |
| - | * interrupts off. |
| - | */ |
| - | static void |
| - | setinputfd(int fd, int push) |
| - | { |
| - | (void) fcntl(fd, F_SETFD, FD_CLOEXEC); |
| - | if (push) { |
| - | pushfile(); |
| - | parsefile->buf = 0; |
| - | } |
| - | parsefile->fd = fd; |
| - | if (parsefile->buf == NULL) |
| - | parsefile->buf = ckmalloc(IBUFSIZ); |
| - | parselleft = parsenleft = 0; |
| - | plinno = 1; |
| - | } |
| - | |
| - | |
| - | /* |
| - | * Like setinputfile, but takes input from a string. |
| - | */ |
| - | static void |
| - | setinputstring(char *string) |
| - | { |
| - | INT_OFF; |
| - | pushfile(); |
| - | parsenextc = string; |
| - | parsenleft = strlen(string); |
| - | parsefile->buf = NULL; |
| - | plinno = 1; |
| - | INT_ON; |
| - | } |
| - | |
| - | |
| /* | |
| * To handle the "." command, a stack of input files is used. Pushfile | |
| * adds a new entry to the stack and popfile restores the previous level. | |
| @@ -7186,7 +7032,6 @@ pushfile(void) | |
| parsefile = pf; | |
| } | |
| - | |
| static void | |
| popfile(void) | |
| { | |
| @@ -7208,7 +7053,6 @@ popfile(void) | |
| INT_ON; | |
| } | |
| - | |
| /* | |
| * Return to top level. | |
| */ | |
| @@ -7219,7 +7063,6 @@ popallfiles(void) | |
| popfile(); | |
| } | |
| - | |
| /* | |
| * Close the file(s) that the shell is reading commands from. Called | |
| * after a fork is done. | |
| @@ -7234,6 +7077,71 @@ closescript(void) | |
| } | |
| } | |
| + | /* |
| + | * Like setinputfile, but takes an open file descriptor. Call this with |
| + | * interrupts off. |
| + | */ |
| + | static void |
| + | setinputfd(int fd, int push) |
| + | { |
| + | fcntl(fd, F_SETFD, FD_CLOEXEC); |
| + | if (push) { |
| + | pushfile(); |
| + | parsefile->buf = 0; |
| + | } |
| + | parsefile->fd = fd; |
| + | if (parsefile->buf == NULL) |
| + | parsefile->buf = ckmalloc(IBUFSIZ); |
| + | parselleft = parsenleft = 0; |
| + | plinno = 1; |
| + | } |
| + | |
| + | /* |
| + | * Set the input to take input from a file. If push is set, push the |
| + | * old input onto the stack first. |
| + | */ |
| + | static int |
| + | setinputfile(const char *fname, int flags) |
| + | { |
| + | int fd; |
| + | int fd2; |
| + | |
| + | INT_OFF; |
| + | fd = open(fname, O_RDONLY); |
| + | if (fd < 0) { |
| + | if (flags & INPUT_NOFILE_OK) |
| + | goto out; |
| + | ash_msg_and_raise_error("Can't open %s", fname); |
| + | } |
| + | if (fd < 10) { |
| + | fd2 = copyfd(fd, 10); |
| + | close(fd); |
| + | if (fd2 < 0) |
| + | ash_msg_and_raise_error("Out of file descriptors"); |
| + | fd = fd2; |
| + | } |
| + | setinputfd(fd, flags & INPUT_PUSH_FILE); |
| + | out: |
| + | INT_ON; |
| + | return fd; |
| + | } |
| + | |
| + | /* |
| + | * Like setinputfile, but takes input from a string. |
| + | */ |
| + | static void |
| + | setinputstring(char *string) |
| + | { |
| + | INT_OFF; |
| + | pushfile(); |
| + | parsenextc = string; |
| + | parsenleft = strlen(string); |
| + | parsefile->buf = NULL; |
| + | plinno = 1; |
| + | INT_ON; |
| + | } |
| + | |
| + | |
| /* jobs.c */ | |
| /* mode flags for set_curjob */ | |
| @@ -8903,6 +8811,15 @@ nodeckstrdup(char *s) | |
| } | |
| + | #if ENABLE_FEATURE_EDITING_VI |
| + | #define setvimode(on) do { \ |
| + | if (on) line_input_state->flags |= VI_MODE; \ |
| + | else line_input_state->flags &= ~VI_MODE; \ |
| + | } while (0) |
| + | #else |
| + | #define setvimode(on) viflag = 0 /* forcibly keep the option off */ |
| + | #endif |
| + | |
| static void | |
| optschanged(void) | |
| { | |
| @@ -9495,7 +9412,7 @@ fixredir(union node *n, const char *text, int err) | |
| n->ndup.vname = NULL; | |
| if (isdigit(text[0]) && text[1] == '\0') | |
| - | n->ndup.dupfd = digit_val(text[0]); |
| + | n->ndup.dupfd = text[0] - '0'; |
| else if (LONE_DASH(text)) | |
| n->ndup.dupfd = -1; | |
| else { | |
| @@ -10160,7 +10077,7 @@ parseredir: { | |
| } | |
| } | |
| if (fd != '\0') | |
| - | np->nfile.fd = digit_val(fd); |
| + | np->nfile.fd = fd - '0'; |
| redirnode = np; | |
| goto parseredir_return; | |
| } | |