diff options
Diffstat (limited to 'shell/ash.c')
-rw-r--r-- | shell/ash.c | 569 |
1 files changed, 267 insertions, 302 deletions
diff --git a/shell/ash.c b/shell/ash.c index 4fc3e0e15..0697a4785 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -36,7 +36,7 @@ * Modified by Paul Mundt <lethal@linux-sh.org> (c) 2004 to support * dynamic variables. * - * Modified by Vladimir Oleynik <dzo@simtreas.ru> (c) 2001-2004 to be + * Modified by Vladimir Oleynik <dzo@simtreas.ru> (c) 2001-2005 to be * used in busybox and size optimizations, * rewrote arith (see notes to this), added locale support, * rewrote dynamic variables. @@ -66,7 +66,6 @@ #endif #include <sys/types.h> -#include <sys/cdefs.h> #include <sys/ioctl.h> #include <sys/param.h> #include <sys/resource.h> @@ -91,7 +90,6 @@ #include <setjmp.h> #include <signal.h> #include <stdint.h> -#include <sysexits.h> #include <time.h> #include <fnmatch.h> @@ -130,7 +128,7 @@ static int *dash_errno; #ifdef CONFIG_ASH_ALIAS -/* $NetBSD: alias.h,v 1.5 2002/11/24 22:35:38 christos Exp $ */ +/* alias.h */ #define ALIASINUSE 1 #define ALIASDEAD 2 @@ -150,12 +148,12 @@ static int unalias(const char *); static void printalias(const struct alias *); #endif -/* $NetBSD: cd.h,v 1.3 2002/11/24 22:35:39 christos Exp $ */ +/* cd.h */ static void setpwd(const char *, int); -/* $NetBSD: error.h,v 1.15 2002/11/24 22:35:39 christos Exp $ */ +/* error.h */ /* @@ -189,8 +187,6 @@ static int exception; static volatile int suppressint; static volatile sig_atomic_t intpending; -static int exerrno; /* Last exec error, error for EXEXEC */ - /* exceptions */ #define EXINT 0 /* SIGINT received */ #define EXERROR 1 /* a generic error */ @@ -240,7 +236,7 @@ static volatile sig_atomic_t pendingsigs; static void exraise(int) __attribute__((__noreturn__)); static void onint(void) __attribute__((__noreturn__)); -static void error(const char *, ...) __attribute__((__noreturn__)); +static void sh_error(const char *, ...) __attribute__((__noreturn__)); static void exerror(int, const char *, ...) __attribute__((__noreturn__)); static void sh_warnx(const char *, ...); @@ -276,7 +272,7 @@ static void forceinton(void) }) #endif /* CONFIG_ASH_OPTIMIZE_FOR_SIZE */ -/* $NetBSD: expand.h,v 1.13 2002/11/24 22:35:40 christos Exp $ */ +/* expand.h */ struct strlist { struct strlist *next; @@ -313,7 +309,7 @@ static int casematch(union node *, char *); static void expari(int); #endif -/* $NetBSD: eval.h,v 1.13 2002/11/24 22:35:39 christos Exp $ */ +/* eval.h */ static char *commandname; /* currently executing command */ static struct strlist *cmdenviron; /* environment for builtin command */ @@ -492,7 +488,7 @@ struct funcnode { static void freefunc(struct funcnode *); -/* $NetBSD: parser.h,v 1.15 2002/11/24 22:35:42 christos Exp $ */ +/* parser.h */ /* control characters in argument strings */ #define CTL_FIRST '\201' /* first 'special' character */ @@ -591,7 +587,7 @@ static void fixredir(union node *, const char *, int); static const char *const *findkwd(const char *); static char *endofname(const char *); -/* $NetBSD: shell.h,v 1.16 2003/01/22 20:36:04 dsl Exp $ */ +/* shell.h */ typedef void *pointer; @@ -693,7 +689,7 @@ static const char *tokname(int tok) return buf; } -/* $NetBSD: machdep.h,v 1.10 2002/10/07 14:26:08 christos Exp $ */ +/* machdep.h */ /* * Most machines require the value returned from malloc to be aligned @@ -1160,7 +1156,7 @@ static const char syntax_index_table[258] = { #endif /* USE_SIT_FUNCTION */ -/* $NetBSD: alias.c,v 1.11 2002/11/24 22:35:38 christos Exp $ */ +/* alias.c */ #define ATABSIZE 39 @@ -1207,29 +1203,27 @@ static struct nodelist *copynodelist(struct nodelist *); static char *nodesavestr(char *); - -static void evalstring(char *); +static int evalstring(char *, int mask); union node; /* BLETCH for ansi C */ static void evaltree(union node *, int); static void evalbackcmd(union node *, struct backcmd *); -/* in_function returns nonzero if we are currently evaluating a function */ -#define in_function() funcnest static int evalskip; /* set if we are skipping commands */ static int skipcount; /* number of levels to skip */ static int funcnest; /* depth of function calls */ /* reasons for skipping commands (see comment on breakcmd routine) */ -#define SKIPBREAK 1 -#define SKIPCONT 2 -#define SKIPFUNC 3 -#define SKIPFILE 4 +#define SKIPBREAK (1 << 0) +#define SKIPCONT (1 << 1) +#define SKIPFUNC (1 << 2) +#define SKIPFILE (1 << 3) +#define SKIPEVAL (1 << 4) /* * This file was generated by the mkbuiltins program. */ -#ifdef JOBS +#if JOBS static int bgcmd(int, char **); #endif static int breakcmd(int, char **); @@ -1246,7 +1240,7 @@ static int execcmd(int, char **); static int exitcmd(int, char **); static int exportcmd(int, char **); static int falsecmd(int, char **); -#ifdef JOBS +#if JOBS static int fgcmd(int, char **); #endif #ifdef CONFIG_ASH_GETOPTS @@ -1256,7 +1250,7 @@ static int hashcmd(int, char **); #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET static int helpcmd(int argc, char **argv); #endif -#ifdef JOBS +#if JOBS static int jobscmd(int, char **); #endif #ifdef CONFIG_ASH_MATH_SUPPORT @@ -1276,18 +1270,18 @@ static int umaskcmd(int, char **); static int unsetcmd(int, char **); static int waitcmd(int, char **); static int ulimitcmd(int, char **); -#ifdef JOBS +#if JOBS static int killcmd(int, char **); #endif -/* $NetBSD: mail.h,v 1.9 2002/11/24 22:35:40 christos Exp $ */ +/* mail.h */ #ifdef CONFIG_ASH_MAIL static void chkmail(void); static void changemail(const char *); #endif -/* $NetBSD: exec.h,v 1.20 2003/01/22 20:36:04 dsl Exp $ */ +/* exec.h */ /* values of cmdtype */ #define CMDUNKNOWN -1 /* no entry in table for command */ @@ -1327,7 +1321,7 @@ static const struct builtincmd builtincmd[] = { #ifdef CONFIG_ASH_ALIAS { BUILTIN_REG_ASSG "alias", aliascmd }, #endif -#ifdef JOBS +#if JOBS { BUILTIN_REGULAR "bg", bgcmd }, #endif { BUILTIN_SPEC_REG "break", breakcmd }, @@ -1345,7 +1339,7 @@ static const struct builtincmd builtincmd[] = { { BUILTIN_SPEC_REG "exit", exitcmd }, { BUILTIN_SPEC_REG_ASSG "export", exportcmd }, { BUILTIN_REGULAR "false", falsecmd }, -#ifdef JOBS +#if JOBS { BUILTIN_REGULAR "fg", fgcmd }, #endif #ifdef CONFIG_ASH_GETOPTS @@ -1355,7 +1349,7 @@ static const struct builtincmd builtincmd[] = { #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET { BUILTIN_NOSPEC "help", helpcmd }, #endif -#ifdef JOBS +#if JOBS { BUILTIN_REGULAR "jobs", jobscmd }, { BUILTIN_REGULAR "kill", killcmd }, #endif @@ -1434,11 +1428,11 @@ static void change_random(const char *); # endif #endif -/* $NetBSD: init.h,v 1.9 2002/11/24 22:35:40 christos Exp $ */ +/* init.h */ static void reset(void); -/* $NetBSD: var.h,v 1.21 2003/01/22 20:36:04 dsl Exp $ */ +/* var.h */ /* * Shell variables. @@ -1613,7 +1607,7 @@ static int nullredirs; extern char **environ; -/* $NetBSD: output.h,v 1.16 2002/11/24 22:35:42 christos Exp $ */ +/* output.h */ static void outstr(const char *, FILE *); @@ -1714,6 +1708,11 @@ init(void) /* 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 @@ -1726,7 +1725,6 @@ static int preadbuffer(void); static void pungetc(void); static void pushstring(char *, void *); static void popstring(void); -static void setinputfile(const char *, int); static void setinputfd(int, int); static void setinputstring(char *); static void popfile(void); @@ -1734,7 +1732,7 @@ static void popallfiles(void); static void closescript(void); -/* $NetBSD: jobs.h,v 1.17 2003/01/22 20:36:04 dsl Exp $ */ +/* jobs.h */ /* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */ @@ -1801,18 +1799,19 @@ static void setjobctl(int); static void showjobs(FILE *, int); #endif -/* $NetBSD: main.h,v 1.9 2002/11/24 22:35:41 christos Exp $ */ +/* main.h */ /* pid of main shell */ static int rootpid; -/* true if we aren't a child of the main shell */ -static int rootshell; +/* shell level: 0 for the main shell, 1 for its children, and so on */ +static int shlvl; +#define rootshell (!shlvl) static void readcmdfile(char *); -static void cmdloop(int); +static int cmdloop(int); -/* $NetBSD: memalloc.h,v 1.13 2003/01/22 20:36:04 dsl Exp $ */ +/* memalloc.h */ struct stackmark { @@ -1853,7 +1852,7 @@ static char *stnputs(const char *, size_t, char *); static char *stputs(const char *, char *); -static inline char *_STPUTC(char c, char *p) { +static inline char *_STPUTC(int c, char *p) { if (p == sstrend) p = growstackstr(); *p++ = c; @@ -1885,7 +1884,7 @@ static inline char *_STPUTC(char c, char *p) { #define ckfree(p) free((pointer)(p)) -/* $NetBSD: mystring.h,v 1.10 2002/11/24 22:35:42 christos Exp $ */ +/* mystring.h */ #define DOLATSTRLEN 4 @@ -1899,7 +1898,7 @@ static char *sstrdup(const char *); #define equal(s1, s2) (strcmp(s1, s2) == 0) #define scopy(s1, s2) ((void)strcpy(s2, s1)) -/* $NetBSD: options.h,v 1.16 2003/01/22 20:36:04 dsl Exp $ */ +/* options.h */ struct shparam { int nparam; /* # of positional parameters (without $0) */ @@ -1925,19 +1924,18 @@ struct shparam { #define aflag optlist[10] #define bflag optlist[11] #define uflag optlist[12] -#define qflag optlist[13] -#define viflag optlist[14] +#define viflag optlist[13] #ifdef DEBUG -#define nolog optlist[15] -#define debug optlist[16] +#define nolog optlist[14] +#define debug optlist[15] #endif #ifndef CONFIG_FEATURE_COMMAND_EDITING_VI #define setvimode(on) viflag = 0 /* forcibly keep the option off */ #endif -/* $NetBSD: options.c,v 1.33 2003/01/22 20:36:04 dsl Exp $ */ +/* options.c */ static const char *const optletters_optnames[] = { @@ -1954,7 +1952,6 @@ static const char *const optletters_optnames[] = { "a" "allexport", "b" "notify", "u" "nounset", - "q" "quietprofile", "\0" "vi", #ifdef DEBUG "\0" "nolog", @@ -1987,7 +1984,7 @@ static int shiftcmd(int, char **); static int setcmd(int, char **); static int nextopt(const char *); -/* $NetBSD: redir.h,v 1.14 2002/11/24 22:35:43 christos Exp $ */ +/* redir.h */ /* flags passed to redirect */ #define REDIR_PUSH 01 /* save previous values of file descriptors */ @@ -2000,7 +1997,7 @@ static void clearredir(int); static int copyfd(int, int); static int redirectsafe(union node *, int); -/* $NetBSD: show.h,v 1.6 2003/01/22 20:36:04 dsl Exp $ */ +/* show.h */ #ifdef DEBUG @@ -2013,7 +2010,7 @@ static void trputs(const char *); static void opentrace(void); #endif -/* $NetBSD: trap.h,v 1.16 2002/11/24 22:35:43 christos Exp $ */ +/* trap.h */ /* trap handler commands */ @@ -2027,7 +2024,7 @@ static void clear_traps(void); static void setsignal(int); static void ignoresig(int); static void onsig(int); -static void dotrap(void); +static int dotrap(void); static void setinteractive(int); static void exitshell(void) __attribute__((__noreturn__)); static int decode_signal(const char *, int); @@ -2044,7 +2041,6 @@ reset(void) { evalskip = 0; loopnest = 0; - funcnest = 0; } /* from input.c: */ @@ -2250,7 +2246,7 @@ __lookupalias(const char *name) { #endif /* CONFIG_ASH_ALIAS */ -/* $NetBSD: cd.c,v 1.30 2003/01/22 20:36:03 dsl Exp $ */ +/* cd.c */ /* * The cd and pwd commands. @@ -2337,7 +2333,7 @@ docd: break; } } while (path); - error("can't cd to %s", dest); + sh_error("can't cd to %s", dest); /* NOTREACHED */ out: if (flags & CD_PRINT) @@ -2495,7 +2491,7 @@ setpwd(const char *val, int setold) setvar("PWD", dir, VEXPORT); } -/* $NetBSD: error.c,v 1.30 2003/01/22 20:36:03 dsl Exp $ */ +/* error.c */ /* * Errors and exceptions. @@ -2602,7 +2598,7 @@ exverror(int cond, const char *msg, va_list ap) static void -error(const char *msg, ...) +sh_error(const char *msg, ...) { va_list ap; @@ -2656,7 +2652,7 @@ errmsg(int e, const char *em) } -/* $NetBSD: eval.c,v 1.71 2003/01/23 03:33:16 rafal Exp $ */ +/* eval.c */ /* * Evaluate a command. @@ -2715,7 +2711,8 @@ evalcmd(int argc, char **argv) STPUTC('\0', concat); p = grabstackstr(concat); } - evalstring(p); + evalstring(p, ~SKIPEVAL); + } return exitstatus; } @@ -2725,23 +2722,29 @@ evalcmd(int argc, char **argv) * Execute a command or commands contained in a string. */ -static void -evalstring(char *s) +static int +evalstring(char *s, int mask) { union node *n; struct stackmark smark; + int skip; - setstackmark(&smark); setinputstring(s); + setstackmark(&smark); + skip = 0; while ((n = parsecmd(0)) != NEOF) { evaltree(n, 0); popstackmark(&smark); - if (evalskip) + skip = evalskip; + if (skip) break; } popfile(); - popstackmark(&smark); + + skip &= mask; + evalskip = skip; + return skip; } @@ -2853,10 +2856,15 @@ setstatus: break; } out: - if (pendingsigs) - dotrap(); - if (flags & EV_EXIT || checkexit & exitstatus) + if ((checkexit & exitstatus)) + evalskip |= SKIPEVAL; + else if (pendingsigs && dotrap()) + goto exexit; + + if (flags & EV_EXIT) { +exexit: exraise(EXEXIT); + } } @@ -3071,7 +3079,7 @@ evalpipe(union node *n, int flags) if (lp->next) { if (pipe(pip) < 0) { close(prevfd); - error("Pipe call failed"); + sh_error("Pipe call failed"); } } if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) { @@ -3132,7 +3140,7 @@ evalbackcmd(union node *n, struct backcmd *result) struct job *jp; if (pipe(pip) < 0) - error("Pipe call failed"); + sh_error("Pipe call failed"); jp = makejob(n, 1); if (forkshell(jp, n, FORK_NOJOB) == 0) { FORCEINTON; @@ -3485,6 +3493,7 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags) localvars = NULL; shellparam.malloc = 0; func->count++; + funcnest++; INTON; shellparam.nparam = argc - 1; shellparam.p = argv + 1; @@ -3492,11 +3501,10 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags) shellparam.optind = 1; shellparam.optoff = -1; #endif - funcnest++; evaltree(&func->n, flags & EV_TESTED); - funcnest--; funcdone: INTOFF; + funcnest--; freefunc(func); poplocalvars(); localvars = savelocalvars; @@ -3504,10 +3512,7 @@ funcdone: shellparam = saveparam; handler = savehandler; INTON; - if (evalskip == SKIPFUNC) { - evalskip = 0; - skipcount = 0; - } + evalskip &= ~SKIPFUNC; return e; } @@ -3575,7 +3580,7 @@ breakcmd(int argc, char **argv) int n = argc > 1 ? number(argv[1]) : 1; if (n <= 0) - error(illnum, argv[1]); + sh_error(illnum, argv[1]); if (n > loopnest) n = loopnest; if (n > 0) { @@ -3593,19 +3598,12 @@ breakcmd(int argc, char **argv) static int returncmd(int argc, char **argv) { - int ret = argc > 1 ? number(argv[1]) : exitstatus; - - if (funcnest) { - evalskip = SKIPFUNC; - skipcount = 1; - return ret; - } - else { - /* Do what ksh does; skip the rest of the file */ - evalskip = SKIPFILE; - skipcount = 1; - return ret; - } + /* + * If called outside a function, do what ksh does; + * skip the rest of the file. + */ + evalskip = funcnest ? SKIPFUNC : SKIPFILE; + return argv[1] ? number(argv[1]) : exitstatus; } @@ -3636,7 +3634,7 @@ execcmd(int argc, char **argv) } -/* $NetBSD: exec.c,v 1.35 2003/01/22 20:36:04 dsl Exp $ */ +/* exec.c */ /* * When commands are first encountered, they are entered in a hash table. @@ -3682,6 +3680,7 @@ shellexec(char **argv, const char *path, int idx) char *cmdname; int e; char **envp; + int exerrno; clearredir(1); envp = environment(); @@ -3716,6 +3715,7 @@ shellexec(char **argv, const char *path, int idx) exerrno = 2; break; } + exitstatus = exerrno; TRACE(("shellexec failed for %s, errno %d, suppressint %d\n", argv[0], e, suppressint )); exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC)); @@ -4004,7 +4004,7 @@ loop: readcmdfile(fullname); if ((cmdp = cmdlookup(name, 0)) == NULL || cmdp->cmdtype != CMDFUNCTION) - error("%s not defined in %s", name, fullname); + sh_error("%s not defined in %s", name, fullname); stunalloc(fullname); goto success; } @@ -4438,46 +4438,28 @@ static int commandcmd(int argc, char **argv) { int c; - int default_path = 0; - int verify_only = 0; - int verbose_verify_only = 0; + enum { + VERIFY_BRIEF = 1, + VERIFY_VERBOSE = 2, + } verify = 0; while ((c = nextopt("pvV")) != '\0') - switch (c) { - default: + if (c == 'V') + verify |= VERIFY_VERBOSE; + else if (c == 'v') + verify |= VERIFY_BRIEF; #ifdef DEBUG - fprintf(stderr, -"command: nextopt returned character code 0%o\n", c); - return EX_SOFTWARE; + else if (c != 'p') + abort(); #endif - case 'p': - default_path = 1; - break; - case 'v': - verify_only = 1; - break; - case 'V': - verbose_verify_only = 1; - break; - } - - if (default_path + verify_only + verbose_verify_only > 1 || - !*argptr) { - fprintf(stderr, - "command [-p] command [arg ...]\n" - "command {-v|-V} command\n"); - return EX_USAGE; - } - - if (verify_only || verbose_verify_only) { - return describe_command(*argptr, verbose_verify_only); - } + if (verify) + return describe_command(*argptr, verify - VERIFY_BRIEF); return 0; } #endif -/* $NetBSD: expand.c,v 1.56 2002/11/24 22:35:39 christos Exp $ */ +/* expand.c */ /* * Routines to expand arguments to commands. We have to deal with @@ -4806,14 +4788,13 @@ exptilde(char *startp, char *p, int flag) done: *p = '\0'; if (*name == '\0') { - if ((home = lookupvar(homestr)) == NULL) - goto lose; + home = lookupvar(homestr); } else { if ((pw = getpwnam(name)) == NULL) goto lose; home = pw->pw_dir; } - if (*home == '\0') + if (!home || !*home) goto lose; *p = c; startloc = expdest - (char *)stackblock(); @@ -4897,7 +4878,7 @@ expari(int quotes) p--; #ifdef DEBUG if (p < start) { - error("missing CTLARI (shouldn't happen)"); + sh_error("missing CTLARI (shouldn't happen)"); } #endif } @@ -5275,7 +5256,7 @@ memtodest(const char *p, size_t len, int syntax, int quotes) { q = makestrspace(len * 2, q); while (len--) { - int c = *p++; + int c = (unsigned char)*p++; if (!c) continue; if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK)) @@ -5932,11 +5913,11 @@ varunset(const char *end, const char *var, const char *umsg, int varflags) } else msg = umsg; } - error("%.*s: %s%s", end - var - 1, var, msg, tail); + sh_error("%.*s: %s%s", end - var - 1, var, msg, tail); } -/* $NetBSD: input.c,v 1.37 2002/11/24 22:35:40 christos Exp $ */ +/* input.c */ /* * This implements the input routines used by the parser. @@ -6103,7 +6084,7 @@ retry: int preadbuffer(void) { - char *p, *q; + char *q; int more; char savec; @@ -6122,39 +6103,42 @@ preadbuffer(void) return PEOF; flushall(); + more = parselleft; + if (more <= 0) { again: - if (parselleft <= 0) { - if ((parselleft = preadfd()) <= 0) { + if ((more = preadfd()) <= 0) { parselleft = parsenleft = EOF_NLEFT; return PEOF; } } - q = p = parsenextc; + q = parsenextc; /* delete nul characters */ - for (more = 1; more;) { - switch (*p) { - case '\0': - p++; /* Skip nul */ - goto check; + for (;;) { + int c; - case '\n': - parsenleft = q - parsenextc; - more = 0; /* Stop processing here */ - break; + more--; + c = *q; + if (!c) + memmove(q, q + 1, more); + else { + q++; + if (c == '\n') { + parsenleft = q - parsenextc - 1; + break; + } } - *q++ = *p++; -check: - if (--parselleft <= 0 && more) { + if (more <= 0) { parsenleft = q - parsenextc - 1; if (parsenleft < 0) goto again; - more = 0; + break; } } + parselleft = more; savec = *q; *q = '\0'; @@ -6247,24 +6231,29 @@ popstring(void) * old input onto the stack first. */ -void -setinputfile(const char *fname, int push) +static int +setinputfile(const char *fname, int flags) { int fd; int fd2; INTOFF; - if ((fd = open(fname, O_RDONLY)) < 0) - error("Can't open %s", fname); + if ((fd = open(fname, O_RDONLY)) < 0) { + if (flags & INPUT_NOFILE_OK) + goto out; + sh_error("Can't open %s", fname); + } if (fd < 10) { fd2 = copyfd(fd, 10); close(fd); if (fd2 < 0) - error("Out of file descriptors"); + sh_error("Out of file descriptors"); fd = fd2; } - setinputfd(fd, push); + setinputfd(fd, flags & INPUT_PUSH_FILE); +out: INTON; + return fd; } @@ -6378,7 +6367,7 @@ closescript(void) } } -/* $NetBSD: jobs.c,v 1.56 2002/11/25 12:13:03 agc Exp $ */ +/* jobs.c */ /* mode flags for set_curjob */ #define CUR_DELETE 2 @@ -6453,14 +6442,14 @@ set_curjob(struct job *jp, unsigned mode) put after all stopped jobs. */ do { jp1 = *jpp; -#ifdef JOBS +#if JOBS if (!jp1 || jp1->state != JOBSTOPPED) #endif break; jpp = &jp1->prev_job; } while (1); /* FALLTHROUGH */ -#ifdef JOBS +#if JOBS case CUR_STOPPED: #endif /* newly stopped job - becomes curjob */ @@ -6549,7 +6538,7 @@ killcmd(int argc, char **argv) if (argc <= 1) { usage: - error( + sh_error( "Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n" "kill -l [exitstatus]" ); @@ -6572,7 +6561,7 @@ usage: case 's': signo = decode_signal(optionarg, 1); if (signo < 0) { - error( + sh_error( "invalid signal number or name: %s", optionarg ); @@ -6606,7 +6595,7 @@ usage: if (name) out1fmt(snlfmt, name); else - error("invalid signal number or exit status: %s", *argptr); + sh_error("invalid signal number or exit status: %s", *argptr); return 0; } @@ -6637,7 +6626,7 @@ jobno(const struct job *jp) } #endif -#ifdef JOBS +#if JOBS static int fgcmd(int argc, char **argv) { @@ -7020,7 +7009,7 @@ gotit: #endif return jp; err: - error(err_msg, name); + sh_error(err_msg, name); } @@ -7132,18 +7121,18 @@ growjobtab(void) static inline void forkchild(struct job *jp, union node *n, int mode) { - int wasroot; + int oldlvl; TRACE(("Child shell %d\n", getpid())); - wasroot = rootshell; - rootshell = 0; + oldlvl = shlvl; + shlvl++; closescript(); clear_traps(); #if JOBS /* do job control only in root shell */ jobctl = 0; - if (mode != FORK_NOJOB && jp->jobctl && wasroot) { + if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) { pid_t pgrp; if (jp->nprocs == 0) @@ -7164,10 +7153,10 @@ forkchild(struct job *jp, union node *n, int mode) if (jp->nprocs == 0) { close(0); if (open(_PATH_DEVNULL, O_RDONLY) != 0) - error("Can't open %s", _PATH_DEVNULL); + sh_error("Can't open %s", _PATH_DEVNULL); } } - if (wasroot && iflag) { + if (!oldlvl && iflag) { setsignal(SIGINT); setsignal(SIGQUIT); setsignal(SIGTERM); @@ -7225,7 +7214,7 @@ forkshell(struct job *jp, union node *n, int mode) TRACE(("Fork failed, errno=%d", errno)); if (jp) freejob(jp); - error("Cannot fork"); + sh_error("Cannot fork"); } if (pid == 0) forkchild(jp, n, mode); @@ -7365,7 +7354,7 @@ dowait(int block, struct job *job) } if (sp->status == -1) state = JOBRUNNING; -#ifdef JOBS +#if JOBS if (state == JOBRUNNING) continue; if (WIFSTOPPED(sp->status)) { @@ -7377,7 +7366,7 @@ dowait(int block, struct job *job) if (thisjob) goto gotjob; } -#ifdef JOBS +#if JOBS if (!WIFSTOPPED(status)) #endif @@ -7391,7 +7380,7 @@ gotjob: if (thisjob->state != state) { TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state)); thisjob->state = state; -#ifdef JOBS +#if JOBS if (state == JOBSTOPPED) { set_curjob(thisjob, CUR_STOPPED); } @@ -7739,7 +7728,7 @@ static void xtcsetpgrp(int fd, pid_t pgrp) { if (tcsetpgrp(fd, pgrp)) - error("Cannot set tty process group (%m)"); + sh_error("Cannot set tty process group (%m)"); } #endif /* JOBS */ @@ -7771,7 +7760,7 @@ getstatus(struct job *job) { } #ifdef CONFIG_ASH_MAIL -/* $NetBSD: mail.c,v 1.15 2002/11/24 22:35:40 christos Exp $ */ +/* mail.c */ /* * Routines to check for mail. (Perhaps make part of main.c?) @@ -7842,7 +7831,7 @@ changemail(const char *val) #endif /* CONFIG_ASH_MAIL */ -/* $NetBSD: main.c,v 1.46 2002/12/11 19:12:18 christos Exp $ */ +/* main.c */ #if PROFILE @@ -7879,28 +7868,16 @@ ash_main(int argc, char **argv) #endif state = 0; if (setjmp(jmploc.loc)) { - int status; int e; + int s; reset(); e = exception; - switch (exception) { - case EXEXEC: - status = exerrno; - break; - - case EXERROR: - status = 2; - break; - - default: - status = exitstatus; - break; - } - exitstatus = status; - - if (e == EXEXIT || state == 0 || iflag == 0 || ! rootshell) + if (e == EXERROR) + exitstatus = 2; + s = state; + if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) exitshell(); if (e == EXINT) { @@ -7908,11 +7885,11 @@ ash_main(int argc, char **argv) } popstackmark(&smark); FORCEINTON; /* enable interrupts */ - if (state == 1) + if (s == 1) goto state1; - else if (state == 2) + else if (s == 2) goto state2; - else if (state == 3) + else if (s == 3) goto state3; else goto state4; @@ -7927,7 +7904,6 @@ ash_main(int argc, char **argv) #ifdef CONFIG_ASH_RANDOM_SUPPORT rseed = rootpid + ((time_t)time((time_t *)0)); #endif - rootshell = 1; init(); setstackmark(&smark); procargs(argc, argv); @@ -7969,7 +7945,7 @@ state2: state3: state = 4; if (minusc) - evalstring(minusc); + evalstring(minusc, 0); if (sflag || minusc == NULL) { #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY @@ -8002,7 +7978,7 @@ state4: /* XXX ??? - why isn't this before the "if" statement */ * loop; it turns on prompting if the shell is interactive. */ -static void +static int cmdloop(int top) { union node *n; @@ -8012,9 +7988,9 @@ cmdloop(int top) TRACE(("cmdloop(%d) called\n", top)); for (;;) { + int skip; + setstackmark(&smark); - if (pendingsigs) - dotrap(); #if JOBS if (jobctl) showjobs(stderr, SHOW_CHANGED); @@ -8037,17 +8013,21 @@ cmdloop(int top) out2str("\nUse \"exit\" to leave shell.\n"); } numeof++; - } else if (n != NULL && nflag == 0) { + } else if (nflag == 0) { job_warning = (job_warning == 2) ? 1 : 0; numeof = 0; evaltree(n, 0); } popstackmark(&smark); - if (evalskip) { + skip = evalskip; + + if (skip) { evalskip = 0; - break; + return skip & SKIPEVAL; } } + + return 0; } @@ -8058,31 +8038,16 @@ cmdloop(int top) static void read_profile(const char *name) { - int fd; - int xflag_set = 0; - int vflag_set = 0; + int skip; - INTOFF; - if ((fd = open(name, O_RDONLY)) >= 0) - setinputfd(fd, 1); - INTON; - if (fd < 0) + if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0) return; - /* -q turns off -x and -v just when executing init files */ - if (qflag) { - if (xflag) - xflag = 0, xflag_set = 1; - if (vflag) - vflag = 0, vflag_set = 1; - } - cmdloop(0); - if (qflag) { - if (xflag_set) - xflag = 1; - if (vflag_set) - vflag = 1; - } + + skip = cmdloop(0); popfile(); + + if (skip) + exitshell(); } @@ -8093,14 +8058,7 @@ read_profile(const char *name) static void readcmdfile(char *name) { - int fd; - - INTOFF; - if ((fd = open(name, O_RDONLY)) >= 0) - setinputfd(fd, 1); - else - error("Can't open %s", name); - INTON; + setinputfile(name, INPUT_PUSH_FILE); cmdloop(0); popfile(); } @@ -8134,7 +8092,7 @@ find_dot_file(char *name) } /* not found in the PATH */ - error(not_found_msg, name); + sh_error(not_found_msg, name); /* NOTREACHED */ } @@ -8142,17 +8100,14 @@ static int dotcmd(int argc, char **argv) { struct strlist *sp; volatile struct shparam saveparam; - - exitstatus = 0; + int status = 0; for (sp = cmdenviron; sp; sp = sp->next) setvareq(bb_xstrdup(sp->text), VSTRFIXED | VTEXTFIXED); if (argc >= 2) { /* That's what SVR2 does */ char *fullname; - struct stackmark smark; - setstackmark(&smark); fullname = find_dot_file(argv[1]); if (argc > 2) { @@ -8162,7 +8117,7 @@ static int dotcmd(int argc, char **argv) shellparam.p = argv + 2; }; - setinputfile(fullname, 1); + setinputfile(fullname, INPUT_PUSH_FILE); commandname = fullname; cmdloop(0); popfile(); @@ -8171,10 +8126,9 @@ static int dotcmd(int argc, char **argv) freeparam(&shellparam); shellparam = saveparam; }; - - popstackmark(&smark); + status = exitstatus; } - return exitstatus; + return status; } @@ -8196,7 +8150,7 @@ echocmd(int argc, char **argv) return bb_echo(argc, argv); } #endif -/* $NetBSD: memalloc.c,v 1.27 2003/01/22 20:36:04 dsl Exp $ */ +/* memalloc.c */ /* * Same for malloc, realloc, but returns an error when out of space. @@ -8207,7 +8161,7 @@ ckrealloc(pointer p, size_t nbytes) { p = realloc(p, nbytes); if (p == NULL) - error(bb_msg_memory_exhausted); + sh_error(bb_msg_memory_exhausted); return p; } @@ -8226,7 +8180,7 @@ savestr(const char *s) { char *p = strdup(s); if (!p) - error(bb_msg_memory_exhausted); + sh_error(bb_msg_memory_exhausted); return p; } @@ -8258,7 +8212,7 @@ stalloc(size_t nbytes) blocksize = MINSIZE; len = sizeof(struct stack_block) - MINSIZE + blocksize; if (len < blocksize) - error(bb_msg_memory_exhausted); + sh_error(bb_msg_memory_exhausted); INTOFF; sp = ckmalloc(len); sp->prev = stackp; @@ -8336,7 +8290,7 @@ growstackblock(void) newlen = stacknleft * 2; if (newlen < stacknleft) - error(bb_msg_memory_exhausted); + sh_error(bb_msg_memory_exhausted); if (newlen < 128) newlen += 128; @@ -8456,7 +8410,7 @@ stputs(const char *s, char *p) return stnputs(s, strlen(s), p); } -/* $NetBSD: mystring.c,v 1.15 2002/11/24 22:35:42 christos Exp $ */ +/* mystring.c */ /* * String functions. @@ -8490,7 +8444,7 @@ number(const char *s) { if (! is_number(s)) - error(illnum, s); + sh_error(illnum, s); return atoi(s); } @@ -8815,7 +8769,7 @@ procargs(int argc, char **argv) xminusc = minusc; if (*xargv == NULL) { if (xminusc) - error("-c requires an argument"); + sh_error("-c requires an argument"); sflag = 1; } if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1)) @@ -8881,7 +8835,7 @@ minus_o(char *name, int val) optlist[i] = val; return; } - error("Illegal option -o %s", name); + sh_error("Illegal option -o %s", name); } } @@ -8949,7 +8903,7 @@ setoption(int flag, int val) optlist[i] = val; return; } - error("Illegal option -%c", flag); + sh_error("Illegal option -%c", flag); /* NOTREACHED */ } @@ -9015,7 +8969,7 @@ shiftcmd(int argc, char **argv) if (argc > 1) n = number(argv[1]); if (n > shellparam.nparam) - error("can't shift that many"); + sh_error("can't shift that many"); INTOFF; shellparam.nparam -= n; for (ap1 = shellparam.p ; --n >= 0 ; ap1++) { @@ -9203,7 +9157,7 @@ getoptscmd(int argc, char **argv) char **optbase; if (argc < 3) - error("Usage: getopts optstring var [arg]"); + sh_error("Usage: getopts optstring var [arg]"); else if (argc == 3) { optbase = shellparam.p; if (shellparam.optind > shellparam.nparam + 1) { @@ -9253,13 +9207,13 @@ nextopt(const char *optstring) c = *p++; for (q = optstring ; *q != c ; ) { if (*q == '\0') - error("Illegal option -%c", c); + sh_error("Illegal option -%c", c); if (*++q == ':') q++; } if (*++q == ':') { if (*p == '\0' && (p = *argptr++) == NULL) - error("No arg for -%c option", c); + sh_error("No arg for -%c option", c); optionarg = p; p = NULL; } @@ -9268,7 +9222,7 @@ nextopt(const char *optstring) } -/* $NetBSD: output.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */ +/* output.c */ void outstr(const char *p, FILE *file) @@ -9336,7 +9290,7 @@ fmtstr(char *outbuf, size_t length, const char *fmt, ...) -/* $NetBSD: parser.c,v 1.54 2002/11/24 22:35:42 christos Exp $ */ +/* parser.c */ /* @@ -10855,7 +10809,7 @@ static void synexpect(int token) static void synerror(const char *msg) { - error("Syntax error: %s", msg); + sh_error("Syntax error: %s", msg); /* NOTREACHED */ } @@ -10923,7 +10877,7 @@ static const char *const *findkwd(const char *s) sizeof(const char *), pstrcmp); } -/* $NetBSD: redir.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */ +/* redir.c */ /* * Code for dealing with input/output redirection. @@ -11007,7 +10961,7 @@ openhere(union node *redir) size_t len = 0; if (pipe(pip) < 0) - error("Pipe call failed"); + sh_error("Pipe call failed"); if (redir->type == NHERE) { len = strlen(redir->nhere.doc->narg.text); if (len <= PIPESIZE) { @@ -11088,9 +11042,9 @@ openredirect(union node *redir) return f; ecreate: - error("cannot create %s: %s", fname, errmsg(errno, E_CREAT)); + sh_error("cannot create %s: %s", fname, errmsg(errno, E_CREAT)); eopen: - error("cannot open %s: %s", fname, errmsg(errno, E_OPEN)); + sh_error("cannot open %s: %s", fname, errmsg(errno, E_OPEN)); } static inline void @@ -11164,7 +11118,7 @@ redirect(union node *redir, int flags) if (i != EBADF) { close(newfd); errno = i; - error("%d: %m", fd); + sh_error("%d: %m", fd); /* NOTREACHED */ } } else { @@ -11247,7 +11201,7 @@ copyfd(int from, int to) if (errno == EMFILE) return EMPTY; else - error("%d: %m", from); + sh_error("%d: %m", from); } return newfd; } @@ -11273,7 +11227,7 @@ redirectsafe(union node *redir, int flags) return err; } -/* $NetBSD: show.c,v 1.24 2003/01/22 20:36:04 dsl Exp $ */ +/* show.c */ #ifdef DEBUG static void shtree(union node *, int, char *, FILE*); @@ -11620,7 +11574,7 @@ opentrace(void) #endif /* DEBUG */ -/* $NetBSD: trap.c,v 1.28 2002/11/24 22:35:43 christos Exp $ */ +/* trap.c */ /* * Sigmode records the current value of the signal handlers for the various @@ -11669,7 +11623,7 @@ trapcmd(int argc, char **argv) action = *ap++; while (*ap) { if ((signo = decode_signal(*ap, 0)) < 0) - error("%s: bad trap", *ap); + sh_error("%s: bad trap", *ap); INTOFF; if (action) { if (action[0] == '-' && action[1] == '\0') @@ -11834,23 +11788,34 @@ onsig(int signo) * handlers while we are executing a trap handler. */ -void +int dotrap(void) { char *p; char *q; + int i; int savestatus; + int skip = 0; savestatus = exitstatus; - q = gotsig; - while (pendingsigs = 0, xbarrier(), (p = memchr(q, 1, NSIG - 1))) { - *p = 0; - p = trap[p - q + 1]; + pendingsigs = 0; + xbarrier(); + + for (i = 0, q = gotsig; i < NSIG - 1; i++, q++) { + if (!*q) + continue; + *q = 0; + + p = trap[i + 1]; if (!p) continue; - evalstring(p); + skip = evalstring(p, SKIPEVAL); exitstatus = savestatus; + if (skip) + break; } + + return skip; } @@ -11931,17 +11896,18 @@ exitshell(void) struct jmploc loc; char *p; int status; - int jmp; - jmp = setjmp(loc.loc); status = exitstatus; TRACE(("pid %d, exitshell(%d)\n", getpid(), status)); - if (jmp) + if (setjmp(loc.loc)) { + if (exception == EXEXIT) + _exit(exitstatus); goto out; + } handler = &loc; - if ((p = trap[0]) != NULL && *p != '\0') { + if ((p = trap[0])) { trap[0] = NULL; - evalstring(p); + evalstring(p, 0); } flushall(); setjobctl(0); @@ -11966,7 +11932,7 @@ static int decode_signal(const char *string, int minsig) return name ? signo : -1; } -/* $NetBSD: var.c,v 1.32 2003/01/22 20:36:04 dsl Exp $ */ +/* var.c */ static struct var *vartab[VTABSIZE]; @@ -12022,7 +11988,7 @@ setvar(const char *name, const char *val, int flags) p = strchrnul(q, '='); namelen = p - name; if (!namelen || p != q) - error("%.*s: bad variable name", namelen, name); + sh_error("%.*s: bad variable name", namelen, name); vallen = 0; if (val == NULL) { flags |= VUNSET; @@ -12031,9 +11997,8 @@ setvar(const char *name, const char *val, int flags) } INTOFF; p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen); - *p++ = '\0'; if (val) { - p[-1] = '='; + *p++ = '='; p = mempcpy(p, val, vallen); } *p = '\0'; @@ -12065,7 +12030,7 @@ setvareq(char *s, int flags) if (flags & VNOSAVE) free(s); n = vp->text; - error("%.*s: is read only", strchrnul(n, '=') - n, n); + sh_error("%.*s: is read only", strchrnul(n, '=') - n, n); } if (flags & VNOSET) @@ -12495,7 +12460,7 @@ findvar(struct var **vpp, const char *name) } return vpp; } -/* $NetBSD: setmode.c,v 1.29 2003/01/15 23:58:03 kleink Exp $ */ +/* setmode.c */ #include <sys/times.h> @@ -12540,11 +12505,11 @@ dash_arith(const char *s) result = arith(s, &errcode); if (errcode < 0) { if (errcode == -3) - error("exponent less than 0"); + sh_error("exponent less than 0"); else if (errcode == -2) - error("divide by zero"); + sh_error("divide by zero"); else if (errcode == -5) - error("expression recursion loop detected"); + sh_error("expression recursion loop detected"); else synerror(s); } @@ -12569,7 +12534,7 @@ letcmd(int argc, char **argv) ap = argv + 1; if(!*ap) - error("expression expected"); + sh_error("expression expected"); for (ap = argv + 1; *ap; ap++) { i = dash_arith(*ap); } @@ -12578,7 +12543,7 @@ letcmd(int argc, char **argv) } #endif /* CONFIG_ASH_MATH_SUPPORT */ -/* $NetBSD: miscbltin.c,v 1.31 2002/11/24 22:35:41 christos Exp $ */ +/* miscbltin.c */ /* * Miscellaneous builtins. @@ -12646,7 +12611,7 @@ readcmd(int argc, char **argv) case 'n': nchars = strtol(optionarg, &p, 10); if (*p) - error("invalid count"); + sh_error("invalid count"); nch_flag = (nchars > 0); break; case 's': @@ -12663,19 +12628,19 @@ readcmd(int argc, char **argv) int scale; ts.tv_usec = strtol(p, &p2, 10); if (*p2) - error("invalid timeout"); + sh_error("invalid timeout"); scale = p2 - p; /* normalize to usec */ if (scale > 6) - error("invalid timeout"); + sh_error("invalid timeout"); while (scale++ < 6) ts.tv_usec *= 10; } } else if (*p) { - error("invalid timeout"); + sh_error("invalid timeout"); } if ( ! ts.tv_sec && ! ts.tv_usec) - error("invalid timeout"); + sh_error("invalid timeout"); break; #endif case 'r': @@ -12689,7 +12654,7 @@ readcmd(int argc, char **argv) out2str(prompt); } if (*(ap = argptr) == NULL) - error("arg count"); + sh_error("arg count"); if ((ifs = bltinlookup("IFS")) == NULL) ifs = defifs; #if defined(CONFIG_ASH_READ_NCHARS) @@ -12832,14 +12797,14 @@ static int umaskcmd(int argc, char **argv) mask = 0; do { if (*ap >= '8' || *ap < '0') - error(illnum, argv[1]); + sh_error(illnum, argv[1]); mask = (mask << 3) + (*ap - '0'); } while (*++ap != '\0'); umask(mask); } else { mask = ~mask & 0777; if (!bb_parse_mode(ap, &mask)) { - error("Illegal mode: %s", ap); + sh_error("Illegal mode: %s", ap); } umask(~mask & 0777); } @@ -12989,7 +12954,7 @@ ulimitcmd(int argc, char **argv) char *p = *argptr; if (all || argptr[1]) - error("too many arguments"); + sh_error("too many arguments"); if (strncmp(p, "unlimited\n", 9) == 0) val = RLIM_INFINITY; else { @@ -13002,7 +12967,7 @@ ulimitcmd(int argc, char **argv) break; } if (c) - error("bad number"); + sh_error("bad number"); val *= l->factor; } } @@ -13022,7 +12987,7 @@ ulimitcmd(int argc, char **argv) if (how & SOFT) limit.rlim_cur = val; if (setrlimit(l->cmd, &limit) < 0) - error("error setting limit (%m)"); + sh_error("error setting limit (%m)"); } else { printlim(how, &limit, l); } |