aboutsummaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
authorvda <vda@69ca8d6d-28ef-0310-b511-8ec308f3f277>2007-02-23 01:05:38 +0000
committervda <vda@69ca8d6d-28ef-0310-b511-8ec308f3f277>2007-02-23 01:05:38 +0000
commit25abda587e7485fe6e42bfe731c553d1b2ba7e97 (patch)
treefafc069118ba7b5091add210ba3acd480194466f /shell
parent34164b837f2b363552e9a22c9a2e06cb7677e603 (diff)
downloadbusybox-w32-25abda587e7485fe6e42bfe731c553d1b2ba7e97.tar.gz
busybox-w32-25abda587e7485fe6e42bfe731c553d1b2ba7e97.tar.bz2
busybox-w32-25abda587e7485fe6e42bfe731c553d1b2ba7e97.zip
ash: cleanup part 8
git-svn-id: svn://busybox.net/trunk/busybox@17960 69ca8d6d-28ef-0310-b511-8ec308f3f277
Diffstat (limited to 'shell')
-rw-r--r--shell/ash.c965
1 files changed, 441 insertions, 524 deletions
diff --git a/shell/ash.c b/shell/ash.c
index e061211a0..94333360b 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -407,6 +407,7 @@ out2str(const char *p)
407 407
408 408
409/* ============ Parsing structures */ 409/* ============ Parsing structures */
410
410#define NCMD 0 411#define NCMD 0
411#define NPIPE 1 412#define NPIPE 1
412#define NREDIR 2 413#define NREDIR 2
@@ -896,12 +897,7 @@ struct strlist {
896}; 897};
897 898
898#if ENABLE_ASH_ALIAS 899#if ENABLE_ASH_ALIAS
899#define ALIASINUSE 1
900#define ALIASDEAD 2
901struct alias; 900struct alias;
902static int aliascmd(int, char **);
903static int unaliascmd(int, char **);
904static void printalias(const struct alias *);
905#endif 901#endif
906 902
907struct strpush { 903struct strpush {
@@ -1485,7 +1481,7 @@ nextopt(const char *optstring)
1485} 1481}
1486 1482
1487 1483
1488/* ============ Variables */ 1484/* ============ Shell variables */
1489 1485
1490/* flags */ 1486/* flags */
1491#define VEXPORT 0x01 /* variable is exported */ 1487#define VEXPORT 0x01 /* variable is exported */
@@ -1503,11 +1499,6 @@ nextopt(const char *optstring)
1503# define VDYNAMIC 0 1499# define VDYNAMIC 0
1504#endif 1500#endif
1505 1501
1506#if ENABLE_LOCALE_SUPPORT
1507static void change_lc_all(const char *value);
1508static void change_lc_ctype(const char *value);
1509#endif
1510
1511static const char defpathvar[] = "PATH=/usr/local/bin:/usr/bin:/sbin:/bin"; 1502static const char defpathvar[] = "PATH=/usr/local/bin:/usr/bin:/sbin:/bin";
1512#ifdef IFS_BROKEN 1503#ifdef IFS_BROKEN
1513static const char defifsvar[] = "IFS= \t\n"; 1504static const char defifsvar[] = "IFS= \t\n";
@@ -1516,6 +1507,27 @@ static const char defifsvar[] = "IFS= \t\n";
1516static const char defifs[] = " \t\n"; 1507static const char defifs[] = " \t\n";
1517#endif 1508#endif
1518 1509
1510struct shparam {
1511 int nparam; /* # of positional parameters (without $0) */
1512 unsigned char malloc; /* if parameter list dynamically allocated */
1513 char **p; /* parameter list */
1514#if ENABLE_ASH_GETOPTS
1515 int optind; /* next parameter to be processed by getopts */
1516 int optoff; /* used by getopts */
1517#endif
1518};
1519
1520static struct shparam shellparam; /* $@ current positional parameters */
1521
1522#if ENABLE_ASH_GETOPTS
1523static void
1524getoptsreset(const char *value)
1525{
1526 shellparam.optind = number(value);
1527 shellparam.optoff = -1;
1528}
1529#endif
1530
1519struct var { 1531struct var {
1520 struct var *next; /* next entry in hash list */ 1532 struct var *next; /* next entry in hash list */
1521 int flags; /* flags are defined above */ 1533 int flags; /* flags are defined above */
@@ -1532,46 +1544,45 @@ struct localvar {
1532}; 1544};
1533 1545
1534/* Forward decls for varinit[] */ 1546/* Forward decls for varinit[] */
1547#if ENABLE_LOCALE_SUPPORT
1548static void change_lc_all(const char *value);
1549static void change_lc_ctype(const char *value);
1550#endif
1535#if ENABLE_ASH_MAIL 1551#if ENABLE_ASH_MAIL
1536static void chkmail(void); 1552static void chkmail(void);
1537static void changemail(const char *); 1553static void changemail(const char *);
1538#endif 1554#endif
1539static void changepath(const char *); 1555static void changepath(const char *);
1540#if ENABLE_ASH_GETOPTS
1541static void getoptsreset(const char *);
1542#endif
1543#if ENABLE_ASH_RANDOM_SUPPORT 1556#if ENABLE_ASH_RANDOM_SUPPORT
1544static void change_random(const char *); 1557static void change_random(const char *);
1545#endif 1558#endif
1546 1559
1547static struct var varinit[] = { 1560static struct var varinit[] = {
1548#ifdef IFS_BROKEN 1561#ifdef IFS_BROKEN
1549 { 0, VSTRFIXED|VTEXTFIXED, defifsvar, 0 }, 1562 { NULL, VSTRFIXED|VTEXTFIXED, defifsvar, NULL },
1550#else 1563#else
1551 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0", 0 }, 1564 { NULL, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0", NULL },
1552#endif 1565#endif
1553
1554#if ENABLE_ASH_MAIL 1566#if ENABLE_ASH_MAIL
1555 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0", changemail }, 1567 { NULL, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0", changemail },
1556 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail }, 1568 { NULL, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail },
1557#endif 1569#endif
1558 1570 { NULL, VSTRFIXED|VTEXTFIXED, defpathvar, changepath },
1559 { 0, VSTRFIXED|VTEXTFIXED, defpathvar, changepath }, 1571 { NULL, VSTRFIXED|VTEXTFIXED, "PS1=$ ", NULL },
1560 { 0, VSTRFIXED|VTEXTFIXED, "PS1=$ ", 0 }, 1572 { NULL, VSTRFIXED|VTEXTFIXED, "PS2=> ", NULL },
1561 { 0, VSTRFIXED|VTEXTFIXED, "PS2=> ", 0 }, 1573 { NULL, VSTRFIXED|VTEXTFIXED, "PS4=+ ", NULL },
1562 { 0, VSTRFIXED|VTEXTFIXED, "PS4=+ ", 0 },
1563#if ENABLE_ASH_GETOPTS 1574#if ENABLE_ASH_GETOPTS
1564 { 0, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset }, 1575 { NULL, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset },
1565#endif 1576#endif
1566#if ENABLE_ASH_RANDOM_SUPPORT 1577#if ENABLE_ASH_RANDOM_SUPPORT
1567 {0, VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random }, 1578 { NULL, VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random },
1568#endif 1579#endif
1569#if ENABLE_LOCALE_SUPPORT 1580#if ENABLE_LOCALE_SUPPORT
1570 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL\0", change_lc_all }, 1581 { NULL, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL\0", change_lc_all },
1571 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE\0", change_lc_ctype }, 1582 { NULL, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE\0", change_lc_ctype },
1572#endif 1583#endif
1573#if ENABLE_FEATURE_EDITING_SAVEHISTORY 1584#if ENABLE_FEATURE_EDITING_SAVEHISTORY
1574 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE\0", NULL }, 1585 { NULL, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE\0", NULL },
1575#endif 1586#endif
1576}; 1587};
1577 1588
@@ -1611,10 +1622,6 @@ static struct var varinit[] = {
1611 1622
1612#define mpathset() ((vmpath.flags & VUNSET) == 0) 1623#define mpathset() ((vmpath.flags & VUNSET) == 0)
1613 1624
1614static struct var **hashvar(const char *);
1615
1616static int loopnest; /* current loop nesting level */
1617
1618/* 1625/*
1619 * The parsefile structure pointed to by the global variable parsefile 1626 * The parsefile structure pointed to by the global variable parsefile
1620 * contains information about the current file being read. 1627 * contains information about the current file being read.
@@ -1627,36 +1634,13 @@ struct redirtab {
1627 1634
1628static struct redirtab *redirlist; 1635static struct redirtab *redirlist;
1629static int nullredirs; 1636static int nullredirs;
1630
1631extern char **environ; 1637extern char **environ;
1632
1633static int preverrout_fd; /* save fd2 before print debug if xflag is set. */ 1638static int preverrout_fd; /* save fd2 before print debug if xflag is set. */
1634 1639
1635struct shparam {
1636 int nparam; /* # of positional parameters (without $0) */
1637 unsigned char malloc; /* if parameter list dynamically allocated */
1638 char **p; /* parameter list */
1639#if ENABLE_ASH_GETOPTS
1640 int optind; /* next parameter to be processed by getopts */
1641 int optoff; /* used by getopts */
1642#endif
1643};
1644
1645static struct shparam shellparam; /* $@ current positional parameters */
1646
1647#define VTABSIZE 39 1640#define VTABSIZE 39
1648 1641
1649static struct var *vartab[VTABSIZE]; 1642static struct var *vartab[VTABSIZE];
1650 1643
1651#if ENABLE_ASH_GETOPTS
1652static void
1653getoptsreset(const char *value)
1654{
1655 shellparam.optind = number(value);
1656 shellparam.optoff = -1;
1657}
1658#endif
1659
1660#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c))) 1644#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
1661#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c))) 1645#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
1662 1646
@@ -2397,6 +2381,7 @@ static int casematch(union node *, char *);
2397static void expari(int); 2381static void expari(int);
2398#endif 2382#endif
2399 2383
2384
2400/* parser.h */ 2385/* parser.h */
2401 2386
2402/* control characters in argument strings */ 2387/* control characters in argument strings */
@@ -2452,7 +2437,6 @@ static char *parsenextc; /* copy of parsefile->nextc */
2452 2437
2453#define basebuf bb_common_bufsiz1 /* buffer for top level input file */ 2438#define basebuf bb_common_bufsiz1 /* buffer for top level input file */
2454 2439
2455
2456static int tokpushback; /* last token pushed back */ 2440static int tokpushback; /* last token pushed back */
2457#define NEOF ((union node *)&tokpushback) 2441#define NEOF ((union node *)&tokpushback)
2458static int parsebackquote; /* nonzero if we are inside backquotes */ 2442static int parsebackquote; /* nonzero if we are inside backquotes */
@@ -2465,7 +2449,7 @@ static struct heredoc *heredoc;
2465static int quoteflag; /* set if (part of) last token was quoted */ 2449static int quoteflag; /* set if (part of) last token was quoted */
2466 2450
2467static void fixredir(union node *, const char *, int); 2451static void fixredir(union node *, const char *, int);
2468static char *endofname(const char *); 2452
2469 2453
2470/* shell.h */ 2454/* shell.h */
2471 2455
@@ -2478,7 +2462,6 @@ static const char dolatstr[] = { CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' };
2478 2462
2479#define xlikely(x) __builtin_expect((x),1) 2463#define xlikely(x) __builtin_expect((x),1)
2480 2464
2481
2482#define TEOF 0 2465#define TEOF 0
2483#define TNL 1 2466#define TNL 1
2484#define TREDIR 2 2467#define TREDIR 2
@@ -2610,12 +2593,6 @@ findkwd(const char *s)
2610 ( (((unsigned int)c) - 33 < 32) \ 2593 ( (((unsigned int)c) - 33 < 32) \
2611 && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1)) 2594 && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1))
2612 2595
2613#define digit_val(c) ((c) - '0')
2614
2615/*
2616 * This file was generated by the mksyntax program.
2617 */
2618
2619#if ENABLE_ASH_OPTIMIZE_FOR_SIZE 2596#if ENABLE_ASH_OPTIMIZE_FOR_SIZE
2620#define USE_SIT_FUNCTION 2597#define USE_SIT_FUNCTION
2621#endif 2598#endif
@@ -3019,15 +2996,15 @@ static const char syntax_index_table[258] = {
3019 2996
3020#endif /* USE_SIT_FUNCTION */ 2997#endif /* USE_SIT_FUNCTION */
3021 2998
3022/* alias.c */
3023 2999
3000/* alias.c */
3024 3001
3025#define ATABSIZE 39 3002#define ATABSIZE 39
3026 3003
3027static int funcblocksize; /* size of structures in function */ 3004static int funcblocksize; /* size of structures in function */
3028static int funcstringsize; /* size of strings in node */ 3005static int funcstringsize; /* size of strings in node */
3029static void *funcblock; /* block to allocate function from */ 3006static void *funcblock; /* block to allocate function from */
3030static char *funcstring; /* block to allocate strings from */ 3007static char *funcstring; /* block to allocate strings from */
3031 3008
3032static const short nodesize[26] = { 3009static const short nodesize[26] = {
3033 SHELL_ALIGN(sizeof(struct ncmd)), 3010 SHELL_ALIGN(sizeof(struct ncmd)),
@@ -3058,14 +3035,12 @@ static const short nodesize[26] = {
3058 SHELL_ALIGN(sizeof(struct nnot)), 3035 SHELL_ALIGN(sizeof(struct nnot)),
3059}; 3036};
3060 3037
3061
3062static void calcsize(union node *); 3038static void calcsize(union node *);
3063static void sizenodelist(struct nodelist *); 3039static void sizenodelist(struct nodelist *);
3064static union node *copynode(union node *); 3040static union node *copynode(union node *);
3065static struct nodelist *copynodelist(struct nodelist *); 3041static struct nodelist *copynodelist(struct nodelist *);
3066static char *nodeckstrdup(char *); 3042static char *nodeckstrdup(char *);
3067 3043
3068
3069static int evalskip; /* set if we are skipping commands */ 3044static int evalskip; /* set if we are skipping commands */
3070static int skipcount; /* number of levels to skip */ 3045static int skipcount; /* number of levels to skip */
3071static int funcnest; /* depth of function calls */ 3046static int funcnest; /* depth of function calls */
@@ -3077,60 +3052,6 @@ static int funcnest; /* depth of function calls */
3077#define SKIPFILE (1 << 3) 3052#define SKIPFILE (1 << 3)
3078#define SKIPEVAL (1 << 4) 3053#define SKIPEVAL (1 << 4)
3079 3054
3080/*
3081 * This file was generated by the mkbuiltins program.
3082 */
3083
3084#if JOBS
3085static int fg_bgcmd(int, char **);
3086#endif
3087static int breakcmd(int, char **);
3088static int cdcmd(int, char **);
3089#if ENABLE_ASH_CMDCMD
3090static int commandcmd(int, char **);
3091#endif
3092static int dotcmd(int, char **);
3093static int evalcmd(int, char **);
3094#if ENABLE_ASH_BUILTIN_ECHO
3095static int echocmd(int, char **);
3096#endif
3097#if ENABLE_ASH_BUILTIN_TEST
3098static int testcmd(int, char **);
3099#endif
3100static int execcmd(int, char **);
3101static int exitcmd(int, char **);
3102static int exportcmd(int, char **);
3103static int falsecmd(int, char **);
3104#if ENABLE_ASH_GETOPTS
3105static int getoptscmd(int, char **);
3106#endif
3107static int hashcmd(int, char **);
3108#if !ENABLE_FEATURE_SH_EXTRA_QUIET
3109static int helpcmd(int argc, char **argv);
3110#endif
3111#if JOBS
3112static int jobscmd(int, char **);
3113#endif
3114#if ENABLE_ASH_MATH_SUPPORT
3115static int letcmd(int, char **);
3116#endif
3117static int localcmd(int, char **);
3118static int pwdcmd(int, char **);
3119static int readcmd(int, char **);
3120static int returncmd(int, char **);
3121static int setcmd(int, char **);
3122static int shiftcmd(int, char **);
3123static int timescmd(int, char **);
3124static int trapcmd(int, char **);
3125static int truecmd(int, char **);
3126static int typecmd(int, char **);
3127static int umaskcmd(int, char **);
3128static int unsetcmd(int, char **);
3129static int waitcmd(int, char **);
3130static int ulimitcmd(int, char **);
3131#if JOBS
3132static int killcmd(int, char **);
3133#endif
3134 3055
3135/* exec.h */ 3056/* exec.h */
3136 3057
@@ -3189,30 +3110,9 @@ static unsigned long rseed;
3189# endif 3110# endif
3190#endif 3111#endif
3191 3112
3192/* PEOF (the end of file marker) */
3193
3194enum {
3195 INPUT_PUSH_FILE = 1,
3196 INPUT_NOFILE_OK = 2,
3197};
3198
3199/*
3200 * The input line number. Input.c just defines this variable, and saves
3201 * and restores it when files are pushed and popped. The user of this
3202 * package must set its value.
3203 */
3204static void pungetc(void);
3205static void pushstring(char *, void *);
3206static void popstring(void);
3207static void setinputfd(int, int);
3208static void setinputstring(char *);
3209static void popfile(void);
3210static void popallfiles(void);
3211static void closescript(void);
3212 3113
3213/* jobs.h */ 3114/* jobs.h */
3214 3115
3215
3216/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */ 3116/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
3217#define FORK_FG 0 3117#define FORK_FG 0
3218#define FORK_BG 1 3118#define FORK_BG 1
@@ -3286,7 +3186,6 @@ static void readcmdfile(char *);
3286 3186
3287static char *minusc; /* argument to -c option */ 3187static char *minusc; /* argument to -c option */
3288 3188
3289
3290static void optschanged(void); 3189static void optschanged(void);
3291static void setparam(char **); 3190static void setparam(char **);
3292static void freeparam(volatile struct shparam *); 3191static void freeparam(volatile struct shparam *);
@@ -3350,7 +3249,12 @@ static int is_safe_applet(char *name)
3350} 3249}
3351 3250
3352 3251
3252/* ============ Alias handling */
3353#if ENABLE_ASH_ALIAS 3253#if ENABLE_ASH_ALIAS
3254
3255#define ALIASINUSE 1
3256#define ALIASDEAD 2
3257
3354struct alias { 3258struct alias {
3355 struct alias *next; 3259 struct alias *next;
3356 char *name; 3260 char *name;
@@ -3475,6 +3379,12 @@ rmaliases(void)
3475 INT_ON; 3379 INT_ON;
3476} 3380}
3477 3381
3382static void
3383printalias(const struct alias *ap)
3384{
3385 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3386}
3387
3478/* 3388/*
3479 * TODO - sort output 3389 * TODO - sort output
3480 */ 3390 */
@@ -3532,25 +3442,17 @@ unaliascmd(int argc, char **argv)
3532 3442
3533 return i; 3443 return i;
3534} 3444}
3535
3536static void
3537printalias(const struct alias *ap)
3538{
3539 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3540}
3541#endif /* ASH_ALIAS */ 3445#endif /* ASH_ALIAS */
3542 3446
3543/* eval.c */
3544 3447
3545/* 3448/* ============ eval.c */
3546 * Evaluate a command.
3547 */
3548 3449
3549/* flags in argument to evaltree */ 3450/* flags in argument to evaltree */
3550#define EV_EXIT 01 /* exit after evaluating tree */ 3451#define EV_EXIT 01 /* exit after evaluating tree */
3551#define EV_TESTED 02 /* exit status is checked; ignore -e flag */ 3452#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
3552#define EV_BACKCMD 04 /* command executing within back quotes */ 3453#define EV_BACKCMD 04 /* command executing within back quotes */
3553 3454
3455/* forward declarations - evaluation is faily recursive business... */
3554static void evalloop(union node *, int); 3456static void evalloop(union node *, int);
3555static void evalfor(union node *, int); 3457static void evalfor(union node *, int);
3556static void evalcase(union node *, int); 3458static void evalcase(union node *, int);
@@ -3679,12 +3581,12 @@ evaltree(union node *n, int flags)
3679 } 3581 }
3680} 3582}
3681 3583
3682
3683#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3) 3584#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
3684static 3585static
3685#endif 3586#endif
3686void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__)); 3587void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
3687 3588
3589static int loopnest; /* current loop nesting level */
3688 3590
3689static void 3591static void
3690evalloop(union node *n, int flags) 3592evalloop(union node *n, int flags)
@@ -3722,7 +3624,6 @@ evalloop(union node *n, int flags)
3722 exitstatus = status; 3624 exitstatus = status;
3723} 3625}
3724 3626
3725
3726static void 3627static void
3727evalfor(union node *n, int flags) 3628evalfor(union node *n, int flags)
3728{ 3629{
@@ -3762,7 +3663,6 @@ evalfor(union node *n, int flags)
3762 popstackmark(&smark); 3663 popstackmark(&smark);
3763} 3664}
3764 3665
3765
3766static void 3666static void
3767evalcase(union node *n, int flags) 3667evalcase(union node *n, int flags)
3768{ 3668{
@@ -3789,7 +3689,6 @@ evalcase(union node *n, int flags)
3789 popstackmark(&smark); 3689 popstackmark(&smark);
3790} 3690}
3791 3691
3792
3793/* 3692/*
3794 * Kick off a subshell to evaluate a tree. 3693 * Kick off a subshell to evaluate a tree.
3795 */ 3694 */
@@ -3822,7 +3721,6 @@ evalsubshell(union node *n, int flags)
3822 INT_ON; 3721 INT_ON;
3823} 3722}
3824 3723
3825
3826/* 3724/*
3827 * Compute the names of the files in a redirection list. 3725 * Compute the names of the files in a redirection list.
3828 */ 3726 */
@@ -3858,7 +3756,6 @@ expredir(union node *n)
3858 } 3756 }
3859} 3757}
3860 3758
3861
3862/* 3759/*
3863 * Evaluate a pipeline. All the processes in the pipeline are children 3760 * Evaluate a pipeline. All the processes in the pipeline are children
3864 * of the process creating the pipeline. (This differs from some versions 3761 * of the process creating the pipeline. (This differs from some versions
@@ -3919,7 +3816,6 @@ evalpipe(union node *n, int flags)
3919 INT_ON; 3816 INT_ON;
3920} 3817}
3921 3818
3922
3923#if ENABLE_ASH_CMDCMD 3819#if ENABLE_ASH_CMDCMD
3924static char ** 3820static char **
3925parse_command_args(char **argv, const char **path) 3821parse_command_args(char **argv, const char **path)
@@ -3955,6 +3851,57 @@ parse_command_args(char **argv, const char **path)
3955} 3851}
3956#endif 3852#endif
3957 3853
3854/* Forward declarations for builtintab[] */
3855#if JOBS
3856static int fg_bgcmd(int, char **);
3857#endif
3858static int breakcmd(int, char **);
3859#if ENABLE_ASH_CMDCMD
3860static int commandcmd(int, char **);
3861#endif
3862static int dotcmd(int, char **);
3863static int evalcmd(int, char **);
3864#if ENABLE_ASH_BUILTIN_ECHO
3865static int echocmd(int, char **);
3866#endif
3867#if ENABLE_ASH_BUILTIN_TEST
3868static int testcmd(int, char **);
3869#endif
3870static int execcmd(int, char **);
3871static int exitcmd(int, char **);
3872static int exportcmd(int, char **);
3873static int falsecmd(int, char **);
3874#if ENABLE_ASH_GETOPTS
3875static int getoptscmd(int, char **);
3876#endif
3877static int hashcmd(int, char **);
3878#if !ENABLE_FEATURE_SH_EXTRA_QUIET
3879static int helpcmd(int argc, char **argv);
3880#endif
3881#if JOBS
3882static int jobscmd(int, char **);
3883#endif
3884#if ENABLE_ASH_MATH_SUPPORT
3885static int letcmd(int, char **);
3886#endif
3887static int localcmd(int, char **);
3888static int pwdcmd(int, char **);
3889static int readcmd(int, char **);
3890static int returncmd(int, char **);
3891static int setcmd(int, char **);
3892static int shiftcmd(int, char **);
3893static int timescmd(int, char **);
3894static int trapcmd(int, char **);
3895static int truecmd(int, char **);
3896static int typecmd(int, char **);
3897static int umaskcmd(int, char **);
3898static int unsetcmd(int, char **);
3899static int waitcmd(int, char **);
3900static int ulimitcmd(int, char **);
3901#if JOBS
3902static int killcmd(int, char **);
3903#endif
3904
3958#define BUILTIN_NOSPEC "0" 3905#define BUILTIN_NOSPEC "0"
3959#define BUILTIN_SPECIAL "1" 3906#define BUILTIN_SPECIAL "1"
3960#define BUILTIN_REGULAR "2" 3907#define BUILTIN_REGULAR "2"
@@ -4514,7 +4461,7 @@ execcmd(int argc, char **argv)
4514} 4461}
4515 4462
4516 4463
4517/* exec.c */ 4464/* ============ Executing commands */
4518 4465
4519/* 4466/*
4520 * When commands are first encountered, they are entered in a hash table. 4467 * When commands are first encountered, they are entered in a hash table.
@@ -4528,7 +4475,6 @@ execcmd(int argc, char **argv)
4528#define CMDTABLESIZE 31 /* should be prime */ 4475#define CMDTABLESIZE 31 /* should be prime */
4529#define ARB 1 /* actual size determined at run time */ 4476#define ARB 1 /* actual size determined at run time */
4530 4477
4531
4532struct tblentry { 4478struct tblentry {
4533 struct tblentry *next; /* next entry in hash chain */ 4479 struct tblentry *next; /* next entry in hash chain */
4534 union param param; /* definition of builtin function */ 4480 union param param; /* definition of builtin function */
@@ -4537,72 +4483,9 @@ struct tblentry {
4537 char cmdname[ARB]; /* name of command */ 4483 char cmdname[ARB]; /* name of command */
4538}; 4484};
4539 4485
4540
4541static struct tblentry *cmdtable[CMDTABLESIZE]; 4486static struct tblentry *cmdtable[CMDTABLESIZE];
4542static int builtinloc = -1; /* index in path of %builtin, or -1 */ 4487static int builtinloc = -1; /* index in path of %builtin, or -1 */
4543 4488
4544
4545static void tryexec(char *, char **, char **);
4546static void clearcmdentry(int);
4547static struct tblentry *cmdlookup(const char *, int);
4548static void delete_cmd_entry(void);
4549
4550
4551/*
4552 * Exec a program. Never returns. If you change this routine, you may
4553 * have to change the find_command routine as well.
4554 */
4555#define environment() listvars(VEXPORT, VUNSET, 0)
4556static void shellexec(char **, const char *, int) ATTRIBUTE_NORETURN;
4557static void
4558shellexec(char **argv, const char *path, int idx)
4559{
4560 char *cmdname;
4561 int e;
4562 char **envp;
4563 int exerrno;
4564
4565 clearredir(1);
4566 envp = environment();
4567 if (strchr(argv[0], '/') || is_safe_applet(argv[0])
4568#if ENABLE_FEATURE_SH_STANDALONE_SHELL
4569 || find_applet_by_name(argv[0])
4570#endif
4571 ) {
4572 tryexec(argv[0], argv, envp);
4573 e = errno;
4574 } else {
4575 e = ENOENT;
4576 while ((cmdname = padvance(&path, argv[0])) != NULL) {
4577 if (--idx < 0 && pathopt == NULL) {
4578 tryexec(cmdname, argv, envp);
4579 if (errno != ENOENT && errno != ENOTDIR)
4580 e = errno;
4581 }
4582 stunalloc(cmdname);
4583 }
4584 }
4585
4586 /* Map to POSIX errors */
4587 switch (e) {
4588 case EACCES:
4589 exerrno = 126;
4590 break;
4591 case ENOENT:
4592 exerrno = 127;
4593 break;
4594 default:
4595 exerrno = 2;
4596 break;
4597 }
4598 exitstatus = exerrno;
4599 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
4600 argv[0], e, suppressint ));
4601 ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found"));
4602 /* NOTREACHED */
4603}
4604
4605
4606static void 4489static void
4607tryexec(char *cmd, char **argv, char **envp) 4490tryexec(char *cmd, char **argv, char **envp)
4608{ 4491{
@@ -4659,8 +4542,59 @@ tryexec(char *cmd, char **argv, char **envp)
4659 } 4542 }
4660} 4543}
4661 4544
4545/*
4546 * Exec a program. Never returns. If you change this routine, you may
4547 * have to change the find_command routine as well.
4548 */
4549#define environment() listvars(VEXPORT, VUNSET, 0)
4550static void shellexec(char **, const char *, int) ATTRIBUTE_NORETURN;
4551static void
4552shellexec(char **argv, const char *path, int idx)
4553{
4554 char *cmdname;
4555 int e;
4556 char **envp;
4557 int exerrno;
4558
4559 clearredir(1);
4560 envp = environment();
4561 if (strchr(argv[0], '/') || is_safe_applet(argv[0])
4562#if ENABLE_FEATURE_SH_STANDALONE_SHELL
4563 || find_applet_by_name(argv[0])
4564#endif
4565 ) {
4566 tryexec(argv[0], argv, envp);
4567 e = errno;
4568 } else {
4569 e = ENOENT;
4570 while ((cmdname = padvance(&path, argv[0])) != NULL) {
4571 if (--idx < 0 && pathopt == NULL) {
4572 tryexec(cmdname, argv, envp);
4573 if (errno != ENOENT && errno != ENOTDIR)
4574 e = errno;
4575 }
4576 stunalloc(cmdname);
4577 }
4578 }
4662 4579
4663/*** Command hashing code ***/ 4580 /* Map to POSIX errors */
4581 switch (e) {
4582 case EACCES:
4583 exerrno = 126;
4584 break;
4585 case ENOENT:
4586 exerrno = 127;
4587 break;
4588 default:
4589 exerrno = 2;
4590 break;
4591 }
4592 exitstatus = exerrno;
4593 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
4594 argv[0], e, suppressint ));
4595 ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found"));
4596 /* NOTREACHED */
4597}
4664 4598
4665static void 4599static void
4666printentry(struct tblentry *cmdp) 4600printentry(struct tblentry *cmdp)
@@ -4678,6 +4612,111 @@ printentry(struct tblentry *cmdp)
4678 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr)); 4612 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
4679} 4613}
4680 4614
4615/*
4616 * Clear out command entries. The argument specifies the first entry in
4617 * PATH which has changed.
4618 */
4619static void
4620clearcmdentry(int firstchange)
4621{
4622 struct tblentry **tblp;
4623 struct tblentry **pp;
4624 struct tblentry *cmdp;
4625
4626 INT_OFF;
4627 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
4628 pp = tblp;
4629 while ((cmdp = *pp) != NULL) {
4630 if ((cmdp->cmdtype == CMDNORMAL &&
4631 cmdp->param.index >= firstchange)
4632 || (cmdp->cmdtype == CMDBUILTIN &&
4633 builtinloc >= firstchange)
4634 ) {
4635 *pp = cmdp->next;
4636 free(cmdp);
4637 } else {
4638 pp = &cmdp->next;
4639 }
4640 }
4641 }
4642 INT_ON;
4643}
4644
4645/*
4646 * Locate a command in the command hash table. If "add" is nonzero,
4647 * add the command to the table if it is not already present. The
4648 * variable "lastcmdentry" is set to point to the address of the link
4649 * pointing to the entry, so that delete_cmd_entry can delete the
4650 * entry.
4651 *
4652 * Interrupts must be off if called with add != 0.
4653 */
4654static struct tblentry **lastcmdentry;
4655
4656static struct tblentry *
4657cmdlookup(const char *name, int add)
4658{
4659 unsigned int hashval;
4660 const char *p;
4661 struct tblentry *cmdp;
4662 struct tblentry **pp;
4663
4664 p = name;
4665 hashval = (unsigned char)*p << 4;
4666 while (*p)
4667 hashval += (unsigned char)*p++;
4668 hashval &= 0x7FFF;
4669 pp = &cmdtable[hashval % CMDTABLESIZE];
4670 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
4671 if (strcmp(cmdp->cmdname, name) == 0)
4672 break;
4673 pp = &cmdp->next;
4674 }
4675 if (add && cmdp == NULL) {
4676 cmdp = *pp = ckmalloc(sizeof(struct tblentry) - ARB
4677 + strlen(name) + 1);
4678 cmdp->next = NULL;
4679 cmdp->cmdtype = CMDUNKNOWN;
4680 strcpy(cmdp->cmdname, name);
4681 }
4682 lastcmdentry = pp;
4683 return cmdp;
4684}
4685
4686/*
4687 * Delete the command entry returned on the last lookup.
4688 */
4689static void
4690delete_cmd_entry(void)
4691{
4692 struct tblentry *cmdp;
4693
4694 INT_OFF;
4695 cmdp = *lastcmdentry;
4696 *lastcmdentry = cmdp->next;
4697 if (cmdp->cmdtype == CMDFUNCTION)
4698 freefunc(cmdp->param.func);
4699 free(cmdp);
4700 INT_ON;
4701}
4702
4703/*
4704 * Add a new command entry, replacing any existing command entry for
4705 * the same name - except special builtins.
4706 */
4707static void
4708addcmdentry(char *name, struct cmdentry *entry)
4709{
4710 struct tblentry *cmdp;
4711
4712 cmdp = cmdlookup(name, 1);
4713 if (cmdp->cmdtype == CMDFUNCTION) {
4714 freefunc(cmdp->param.func);
4715 }
4716 cmdp->cmdtype = entry->cmdtype;
4717 cmdp->param = entry->u;
4718 cmdp->rehash = 0;
4719}
4681 4720
4682static int 4721static int
4683hashcmd(int argc, char **argv) 4722hashcmd(int argc, char **argv)
@@ -4716,7 +4755,6 @@ hashcmd(int argc, char **argv)
4716 return c; 4755 return c;
4717} 4756}
4718 4757
4719
4720/* 4758/*
4721 * Resolve a command name. If you change this routine, you may have to 4759 * Resolve a command name. If you change this routine, you may have to
4722 * change the shellexec routine as well. 4760 * change the shellexec routine as well.
@@ -4901,7 +4939,6 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
4901 entry->u = cmdp->param; 4939 entry->u = cmdp->param;
4902} 4940}
4903 4941
4904
4905/* 4942/*
4906 * Search the table of builtin commands. 4943 * Search the table of builtin commands.
4907 */ 4944 */
@@ -4917,7 +4954,6 @@ find_builtin(const char *name)
4917 return bp; 4954 return bp;
4918} 4955}
4919 4956
4920
4921/* 4957/*
4922 * Called when a cd is done. Marks all commands so the next time they 4958 * Called when a cd is done. Marks all commands so the next time they
4923 * are executed they will be rehashed. 4959 * are executed they will be rehashed.
@@ -4940,7 +4976,6 @@ hashcd(void)
4940 } 4976 }
4941} 4977}
4942 4978
4943
4944/* 4979/*
4945 * Fix command hash table when PATH changed. 4980 * Fix command hash table when PATH changed.
4946 * Called before PATH is changed. The argument is the new value of PATH; 4981 * Called before PATH is changed. The argument is the new value of PATH;
@@ -4987,116 +5022,6 @@ changepath(const char *newval)
4987 5022
4988 5023
4989/* 5024/*
4990 * Clear out command entries. The argument specifies the first entry in
4991 * PATH which has changed.
4992 */
4993static void
4994clearcmdentry(int firstchange)
4995{
4996 struct tblentry **tblp;
4997 struct tblentry **pp;
4998 struct tblentry *cmdp;
4999
5000 INT_OFF;
5001 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
5002 pp = tblp;
5003 while ((cmdp = *pp) != NULL) {
5004 if ((cmdp->cmdtype == CMDNORMAL &&
5005 cmdp->param.index >= firstchange)
5006 || (cmdp->cmdtype == CMDBUILTIN &&
5007 builtinloc >= firstchange)
5008 ) {
5009 *pp = cmdp->next;
5010 free(cmdp);
5011 } else {
5012 pp = &cmdp->next;
5013 }
5014 }
5015 }
5016 INT_ON;
5017}
5018
5019
5020/*
5021 * Locate a command in the command hash table. If "add" is nonzero,
5022 * add the command to the table if it is not already present. The
5023 * variable "lastcmdentry" is set to point to the address of the link
5024 * pointing to the entry, so that delete_cmd_entry can delete the
5025 * entry.
5026 *
5027 * Interrupts must be off if called with add != 0.
5028 */
5029static struct tblentry **lastcmdentry;
5030
5031static struct tblentry *
5032cmdlookup(const char *name, int add)
5033{
5034 unsigned int hashval;
5035 const char *p;
5036 struct tblentry *cmdp;
5037 struct tblentry **pp;
5038
5039 p = name;
5040 hashval = (unsigned char)*p << 4;
5041 while (*p)
5042 hashval += (unsigned char)*p++;
5043 hashval &= 0x7FFF;
5044 pp = &cmdtable[hashval % CMDTABLESIZE];
5045 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
5046 if (strcmp(cmdp->cmdname, name) == 0)
5047 break;
5048 pp = &cmdp->next;
5049 }
5050 if (add && cmdp == NULL) {
5051 cmdp = *pp = ckmalloc(sizeof(struct tblentry) - ARB
5052 + strlen(name) + 1);
5053 cmdp->next = NULL;
5054 cmdp->cmdtype = CMDUNKNOWN;
5055 strcpy(cmdp->cmdname, name);
5056 }
5057 lastcmdentry = pp;
5058 return cmdp;
5059}
5060
5061
5062/*
5063 * Delete the command entry returned on the last lookup.
5064 */
5065static void
5066delete_cmd_entry(void)
5067{
5068 struct tblentry *cmdp;
5069
5070 INT_OFF;
5071 cmdp = *lastcmdentry;
5072 *lastcmdentry = cmdp->next;
5073 if (cmdp->cmdtype == CMDFUNCTION)
5074 freefunc(cmdp->param.func);
5075 free(cmdp);
5076 INT_ON;
5077}
5078
5079
5080/*
5081 * Add a new command entry, replacing any existing command entry for
5082 * the same name - except special builtins.
5083 */
5084static void
5085addcmdentry(char *name, struct cmdentry *entry)
5086{
5087 struct tblentry *cmdp;
5088
5089 cmdp = cmdlookup(name, 1);
5090 if (cmdp->cmdtype == CMDFUNCTION) {
5091 freefunc(cmdp->param.func);
5092 }
5093 cmdp->cmdtype = entry->cmdtype;
5094 cmdp->param = entry->u;
5095 cmdp->rehash = 0;
5096}
5097
5098
5099/*
5100 * Make a copy of a parse tree. 5025 * Make a copy of a parse tree.
5101 */ 5026 */
5102static struct funcnode * 5027static struct funcnode *
@@ -5145,6 +5070,7 @@ unsetfunc(const char *name)
5145 delete_cmd_entry(); 5070 delete_cmd_entry();
5146} 5071}
5147 5072
5073
5148/* 5074/*
5149 * Locate and print what a word is... 5075 * Locate and print what a word is...
5150 */ 5076 */
@@ -6804,94 +6730,45 @@ varunset(const char *end, const char *var, const char *umsg, int varflags)
6804} 6730}
6805 6731
6806 6732
6807/* input.c */ 6733/* ============ input.c
6808 6734 *
6809/*
6810 * This implements the input routines used by the parser. 6735 * This implements the input routines used by the parser.
6811 */ 6736 */
6812
6813#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */ 6737#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
6814 6738
6815static void pushfile(void); 6739enum {
6816 6740 INPUT_PUSH_FILE = 1,
6817/* 6741 INPUT_NOFILE_OK = 2,
6818 * Read a character from the script, returning PEOF on end of file. 6742};
6819 * Nul characters in the input are silently discarded.
6820 */
6821static int preadbuffer(void);
6822#define pgetc_as_macro() (--parsenleft >= 0? SC2INT(*parsenextc++) : preadbuffer())
6823 6743
6824#if ENABLE_ASH_OPTIMIZE_FOR_SIZE 6744static void
6825#define pgetc_macro() pgetc() 6745popstring(void)
6826static int
6827pgetc(void)
6828{
6829 return pgetc_as_macro();
6830}
6831#else
6832#define pgetc_macro() pgetc_as_macro()
6833static int
6834pgetc(void)
6835{ 6746{
6836 return pgetc_macro(); 6747 struct strpush *sp = parsefile->strpush;
6837}
6838#endif
6839 6748
6840/* 6749 INT_OFF;
6841 * Same as pgetc(), but ignores PEOA.
6842 */
6843#if ENABLE_ASH_ALIAS 6750#if ENABLE_ASH_ALIAS
6844static int 6751 if (sp->ap) {
6845pgetc2(void) 6752 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6846{ 6753 checkkwd |= CHKALIAS;
6847 int c; 6754 }
6848 6755 if (sp->string != sp->ap->val) {
6849 do { 6756 free(sp->string);
6850 c = pgetc_macro(); 6757 }
6851 } while (c == PEOA); 6758 sp->ap->flag &= ~ALIASINUSE;
6852 return c; 6759 if (sp->ap->flag & ALIASDEAD) {
6853} 6760 unalias(sp->ap->name);
6854#else
6855static int
6856pgetc2(void)
6857{
6858 return pgetc_macro();
6859}
6860#endif
6861
6862/*
6863 * Read a line from the script.
6864 */
6865static char *
6866pfgets(char *line, int len)
6867{
6868 char *p = line;
6869 int nleft = len;
6870 int c;
6871
6872 while (--nleft > 0) {
6873 c = pgetc2();
6874 if (c == PEOF) {
6875 if (p == line)
6876 return NULL;
6877 break;
6878 } 6761 }
6879 *p++ = c;
6880 if (c == '\n')
6881 break;
6882 } 6762 }
6883 *p = '\0';
6884 return line;
6885}
6886
6887#if ENABLE_FEATURE_EDITING_VI
6888#define setvimode(on) do { \
6889 if (on) line_input_state->flags |= VI_MODE; \
6890 else line_input_state->flags &= ~VI_MODE; \
6891} while (0)
6892#else
6893#define setvimode(on) viflag = 0 /* forcibly keep the option off */
6894#endif 6763#endif
6764 parsenextc = sp->prevstring;
6765 parsenleft = sp->prevnleft;
6766/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6767 parsefile->strpush = sp->prev;
6768 if (sp != &(parsefile->basestrpush))
6769 free(sp);
6770 INT_ON;
6771}
6895 6772
6896static int 6773static int
6897preadfd(void) 6774preadfd(void)
@@ -7024,6 +6901,72 @@ preadbuffer(void)
7024 return SC2INT(*parsenextc++); 6901 return SC2INT(*parsenextc++);
7025} 6902}
7026 6903
6904
6905#define pgetc_as_macro() (--parsenleft >= 0? SC2INT(*parsenextc++) : preadbuffer())
6906
6907#if ENABLE_ASH_OPTIMIZE_FOR_SIZE
6908#define pgetc_macro() pgetc()
6909static int
6910pgetc(void)
6911{
6912 return pgetc_as_macro();
6913}
6914#else
6915#define pgetc_macro() pgetc_as_macro()
6916static int
6917pgetc(void)
6918{
6919 return pgetc_macro();
6920}
6921#endif
6922
6923/*
6924 * Same as pgetc(), but ignores PEOA.
6925 */
6926#if ENABLE_ASH_ALIAS
6927static int
6928pgetc2(void)
6929{
6930 int c;
6931
6932 do {
6933 c = pgetc_macro();
6934 } while (c == PEOA);
6935 return c;
6936}
6937#else
6938static int
6939pgetc2(void)
6940{
6941 return pgetc_macro();
6942}
6943#endif
6944
6945/*
6946 * Read a line from the script.
6947 */
6948static char *
6949pfgets(char *line, int len)
6950{
6951 char *p = line;
6952 int nleft = len;
6953 int c;
6954
6955 while (--nleft > 0) {
6956 c = pgetc2();
6957 if (c == PEOF) {
6958 if (p == line)
6959 return NULL;
6960 break;
6961 }
6962 *p++ = c;
6963 if (c == '\n')
6964 break;
6965 }
6966 *p = '\0';
6967 return line;
6968}
6969
7027/* 6970/*
7028 * Undo the last call to pgetc. Only one character may be pushed back. 6971 * Undo the last call to pgetc. Only one character may be pushed back.
7029 * PEOF may be pushed back. 6972 * PEOF may be pushed back.
@@ -7068,103 +7011,6 @@ pushstring(char *s, void *ap)
7068 INT_ON; 7011 INT_ON;
7069} 7012}
7070 7013
7071static void
7072popstring(void)
7073{
7074 struct strpush *sp = parsefile->strpush;
7075
7076 INT_OFF;
7077#if ENABLE_ASH_ALIAS
7078 if (sp->ap) {
7079 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
7080 checkkwd |= CHKALIAS;
7081 }
7082 if (sp->string != sp->ap->val) {
7083 free(sp->string);
7084 }
7085 sp->ap->flag &= ~ALIASINUSE;
7086 if (sp->ap->flag & ALIASDEAD) {
7087 unalias(sp->ap->name);
7088 }
7089 }
7090#endif
7091 parsenextc = sp->prevstring;
7092 parsenleft = sp->prevnleft;
7093/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
7094 parsefile->strpush = sp->prev;
7095 if (sp != &(parsefile->basestrpush))
7096 free(sp);
7097 INT_ON;
7098}
7099
7100
7101/*
7102 * Set the input to take input from a file. If push is set, push the
7103 * old input onto the stack first.
7104 */
7105static int
7106setinputfile(const char *fname, int flags)
7107{
7108 int fd;
7109 int fd2;
7110
7111 INT_OFF;
7112 fd = open(fname, O_RDONLY);
7113 if (fd < 0) {
7114 if (flags & INPUT_NOFILE_OK)
7115 goto out;
7116 ash_msg_and_raise_error("Can't open %s", fname);
7117 }
7118 if (fd < 10) {
7119 fd2 = copyfd(fd, 10);
7120 close(fd);
7121 if (fd2 < 0)
7122 ash_msg_and_raise_error("Out of file descriptors");
7123 fd = fd2;
7124 }
7125 setinputfd(fd, flags & INPUT_PUSH_FILE);
7126 out:
7127 INT_ON;
7128 return fd;
7129}
7130
7131
7132/*
7133 * Like setinputfile, but takes an open file descriptor. Call this with
7134 * interrupts off.
7135 */
7136static void
7137setinputfd(int fd, int push)
7138{
7139 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
7140 if (push) {
7141 pushfile();
7142 parsefile->buf = 0;
7143 }
7144 parsefile->fd = fd;
7145 if (parsefile->buf == NULL)
7146 parsefile->buf = ckmalloc(IBUFSIZ);
7147 parselleft = parsenleft = 0;
7148 plinno = 1;
7149}
7150
7151
7152/*
7153 * Like setinputfile, but takes input from a string.
7154 */
7155static void
7156setinputstring(char *string)
7157{
7158 INT_OFF;
7159 pushfile();
7160 parsenextc = string;
7161 parsenleft = strlen(string);
7162 parsefile->buf = NULL;
7163 plinno = 1;
7164 INT_ON;
7165}
7166
7167
7168/* 7014/*
7169 * To handle the "." command, a stack of input files is used. Pushfile 7015 * To handle the "." command, a stack of input files is used. Pushfile
7170 * adds a new entry to the stack and popfile restores the previous level. 7016 * adds a new entry to the stack and popfile restores the previous level.
@@ -7186,7 +7032,6 @@ pushfile(void)
7186 parsefile = pf; 7032 parsefile = pf;
7187} 7033}
7188 7034
7189
7190static void 7035static void
7191popfile(void) 7036popfile(void)
7192{ 7037{
@@ -7208,7 +7053,6 @@ popfile(void)
7208 INT_ON; 7053 INT_ON;
7209} 7054}
7210 7055
7211
7212/* 7056/*
7213 * Return to top level. 7057 * Return to top level.
7214 */ 7058 */
@@ -7219,7 +7063,6 @@ popallfiles(void)
7219 popfile(); 7063 popfile();
7220} 7064}
7221 7065
7222
7223/* 7066/*
7224 * Close the file(s) that the shell is reading commands from. Called 7067 * Close the file(s) that the shell is reading commands from. Called
7225 * after a fork is done. 7068 * after a fork is done.
@@ -7234,6 +7077,71 @@ closescript(void)
7234 } 7077 }
7235} 7078}
7236 7079
7080/*
7081 * Like setinputfile, but takes an open file descriptor. Call this with
7082 * interrupts off.
7083 */
7084static void
7085setinputfd(int fd, int push)
7086{
7087 fcntl(fd, F_SETFD, FD_CLOEXEC);
7088 if (push) {
7089 pushfile();
7090 parsefile->buf = 0;
7091 }
7092 parsefile->fd = fd;
7093 if (parsefile->buf == NULL)
7094 parsefile->buf = ckmalloc(IBUFSIZ);
7095 parselleft = parsenleft = 0;
7096 plinno = 1;
7097}
7098
7099/*
7100 * Set the input to take input from a file. If push is set, push the
7101 * old input onto the stack first.
7102 */
7103static int
7104setinputfile(const char *fname, int flags)
7105{
7106 int fd;
7107 int fd2;
7108
7109 INT_OFF;
7110 fd = open(fname, O_RDONLY);
7111 if (fd < 0) {
7112 if (flags & INPUT_NOFILE_OK)
7113 goto out;
7114 ash_msg_and_raise_error("Can't open %s", fname);
7115 }
7116 if (fd < 10) {
7117 fd2 = copyfd(fd, 10);
7118 close(fd);
7119 if (fd2 < 0)
7120 ash_msg_and_raise_error("Out of file descriptors");
7121 fd = fd2;
7122 }
7123 setinputfd(fd, flags & INPUT_PUSH_FILE);
7124 out:
7125 INT_ON;
7126 return fd;
7127}
7128
7129/*
7130 * Like setinputfile, but takes input from a string.
7131 */
7132static void
7133setinputstring(char *string)
7134{
7135 INT_OFF;
7136 pushfile();
7137 parsenextc = string;
7138 parsenleft = strlen(string);
7139 parsefile->buf = NULL;
7140 plinno = 1;
7141 INT_ON;
7142}
7143
7144
7237/* jobs.c */ 7145/* jobs.c */
7238 7146
7239/* mode flags for set_curjob */ 7147/* mode flags for set_curjob */
@@ -8903,6 +8811,15 @@ nodeckstrdup(char *s)
8903} 8811}
8904 8812
8905 8813
8814#if ENABLE_FEATURE_EDITING_VI
8815#define setvimode(on) do { \
8816 if (on) line_input_state->flags |= VI_MODE; \
8817 else line_input_state->flags &= ~VI_MODE; \
8818} while (0)
8819#else
8820#define setvimode(on) viflag = 0 /* forcibly keep the option off */
8821#endif
8822
8906static void 8823static void
8907optschanged(void) 8824optschanged(void)
8908{ 8825{
@@ -9495,7 +9412,7 @@ fixredir(union node *n, const char *text, int err)
9495 n->ndup.vname = NULL; 9412 n->ndup.vname = NULL;
9496 9413
9497 if (isdigit(text[0]) && text[1] == '\0') 9414 if (isdigit(text[0]) && text[1] == '\0')
9498 n->ndup.dupfd = digit_val(text[0]); 9415 n->ndup.dupfd = text[0] - '0';
9499 else if (LONE_DASH(text)) 9416 else if (LONE_DASH(text))
9500 n->ndup.dupfd = -1; 9417 n->ndup.dupfd = -1;
9501 else { 9418 else {
@@ -10160,7 +10077,7 @@ parseredir: {
10160 } 10077 }
10161 } 10078 }
10162 if (fd != '\0') 10079 if (fd != '\0')
10163 np->nfile.fd = digit_val(fd); 10080 np->nfile.fd = fd - '0';
10164 redirnode = np; 10081 redirnode = np;
10165 goto parseredir_return; 10082 goto parseredir_return;
10166} 10083}