diff options
-rw-r--r-- | shell/ash.c | 805 |
1 files changed, 382 insertions, 423 deletions
diff --git a/shell/ash.c b/shell/ash.c index 532dad1..e262c0e 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -141,6 +141,7 @@ static char optlist[NOPTS]; /* ============ Misc data */ +static int isloginsh; /* pid of main shell */ static int rootpid; /* shell level: 0 for the main shell, 1 for its children, and so on */ @@ -779,8 +780,6 @@ static char *endofname(const char *); /* shell.h */ -typedef void *pointer; - static char nullstr[1]; /* zero length string */ static const char spcstr[] = " "; static const char snlfmt[] = "%s\n"; @@ -1356,7 +1355,7 @@ static const char syntax_index_table[258] = { static int funcblocksize; /* size of structures in function */ static int funcstringsize; /* size of strings in node */ -static pointer funcblock; /* block to allocate function from */ +static void *funcblock; /* block to allocate function from */ static char *funcstring; /* block to allocate strings from */ static const short nodesize[26] = { @@ -1853,45 +1852,6 @@ static void initvar(void) } while (++vp < end); } -static void init(void) -{ - - /* from input.c: */ - { - basepf.nextc = basepf.buf = basebuf; - } - - /* from trap.c: */ - { - signal(SIGCHLD, SIG_DFL); - } - - /* from var.c: */ - { - char **envp; - char ppid[32]; - const char *p; - struct stat st1, st2; - - initvar(); - for (envp = environ; envp && *envp; envp++) { - if (strchr(*envp, '=')) { - setvareq(*envp, VEXPORT|VTEXTFIXED); - } - } - - snprintf(ppid, sizeof(ppid), "%d", (int) getppid()); - setvar("PPID", ppid, 0); - - p = lookupvar("PWD"); - if (p) - if (*p != '/' || stat(p, &st1) || stat(".", &st2) - || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino) - p = 0; - setpwd(p, 0); - } -} - /* PEOF (the end of file marker) */ enum { @@ -1989,8 +1949,7 @@ static void showjobs(FILE *, int); static void readcmdfile(char *); -static int cmdloop(int); - + /* memalloc.h */ @@ -2018,11 +1977,11 @@ static char *sstrend = stackbase.space + MINSIZE; static int herefd = -1; -static pointer ckmalloc(size_t); -static pointer ckrealloc(pointer, size_t); +static void *ckmalloc(size_t); +static void *ckrealloc(void *, size_t); static char *savestr(const char *); -static pointer stalloc(size_t); -static void stunalloc(pointer); +static void *stalloc(size_t); +static void stunalloc(void *); static void setstackmark(struct stackmark *); static void popstackmark(struct stackmark *); static void growstackblock(void); @@ -2098,7 +2057,6 @@ static char *optptr; /* used by nextopt */ static char *minusc; /* argument to -c option */ -static void procargs(int, char **); static void optschanged(void); static void setparam(char **); static void freeparam(volatile struct shparam *); @@ -2187,27 +2145,19 @@ static void reset(void) { /* from eval.c: */ - { - evalskip = 0; - loopnest = 0; - } + evalskip = 0; + loopnest = 0; /* from input.c: */ - { - parselleft = parsenleft = 0; /* clear input buffer */ - popallfiles(); - } + parselleft = parsenleft = 0; /* clear input buffer */ + popallfiles(); /* from parser.c: */ - { - tokpushback = 0; - checkkwd = 0; - } + tokpushback = 0; + checkkwd = 0; /* from redir.c: */ - { - clearredir(0); - } + clearredir(0); } #if ENABLE_ASH_ALIAS @@ -4578,7 +4528,7 @@ expandarg(union node *arg, struct arglist *arglist, int flag) } else { if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */ rmescapes(p); - sp = (struct strlist *)stalloc(sizeof(struct strlist)); + sp = stalloc(sizeof(*sp)); sp->text = p; *exparg.lastp = sp; exparg.lastp = &sp->next; @@ -5386,7 +5336,7 @@ recordregion(int start, int end, int nulonly) ifsp = &ifsfirst; } else { INT_OFF; - ifsp = (struct ifsregion *)ckmalloc(sizeof(struct ifsregion)); + ifsp = ckmalloc(sizeof(*ifsp)); ifsp->next = NULL; ifslastp->next = ifsp; INT_ON; @@ -5440,7 +5390,7 @@ ifsbreakup(char *string, struct arglist *arglist) continue; } *q = '\0'; - sp = (struct strlist *)stalloc(sizeof(*sp)); + sp = stalloc(sizeof(*sp)); sp->text = start; *arglist->lastp = sp; arglist->lastp = &sp->next; @@ -5481,7 +5431,7 @@ ifsbreakup(char *string, struct arglist *arglist) return; add: - sp = (struct strlist *)stalloc(sizeof(*sp)); + sp = stalloc(sizeof(*sp)); sp->text = start; *arglist->lastp = sp; arglist->lastp = &sp->next; @@ -5571,7 +5521,7 @@ addfname(const char *name) { struct strlist *sp; - sp = (struct strlist *)stalloc(sizeof(*sp)); + sp = stalloc(sizeof(*sp)); sp->text = sstrdup(name); *exparg.lastp = sp; exparg.lastp = &sp->next; @@ -6288,7 +6238,7 @@ pushfile(void) parsefile->lleft = parselleft; parsefile->nextc = parsenextc; parsefile->linno = plinno; - pf = (struct parsefile *)ckmalloc(sizeof(struct parsefile)); + pf = ckmalloc(sizeof(*pf)); pf->prev = parsefile; pf->fd = -1; pf->strpush = NULL; @@ -7802,152 +7752,6 @@ changemail(const char *val) #endif /* ASH_MAIL */ -/* main.c */ - - -#if PROFILE -static short profile_buf[16384]; -extern int etext(); -#endif - -static int isloginsh; - -static void read_profile(const char *); - -/* - * Main routine. We initialize things, parse the arguments, execute - * profiles if we're a login shell, and then call cmdloop to execute - * commands. The setjmp call sets up the location to jump to when an - * exception occurs. When an exception occurs the variable "state" - * is used to figure out how far we had gotten. - */ -int ash_main(int argc, char **argv); -int ash_main(int argc, char **argv) -{ - char *shinit; - volatile int state; - struct jmploc jmploc; - struct stackmark smark; - -#ifdef __GLIBC__ - dash_errno = __errno_location(); -#endif - -#if PROFILE - monitor(4, etext, profile_buf, sizeof(profile_buf), 50); -#endif - -#if ENABLE_FEATURE_EDITING - line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP); -#endif - state = 0; - if (setjmp(jmploc.loc)) { - int e; - int s; - - reset(); - - e = exception; - if (e == EXERROR) - exitstatus = 2; - s = state; - if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) - exitshell(); - - if (e == EXINT) { - outcslow('\n', stderr); - } - popstackmark(&smark); - FORCE_INT_ON; /* enable interrupts */ - if (s == 1) - goto state1; - else if (s == 2) - goto state2; - else if (s == 3) - goto state3; - else - goto state4; - } - exception_handler = &jmploc; -#if DEBUG - opentrace(); - trputs("Shell args: "); trargs(argv); -#endif - rootpid = getpid(); - -#if ENABLE_ASH_RANDOM_SUPPORT - rseed = rootpid + ((time_t)time((time_t *)0)); -#endif - init(); - setstackmark(&smark); - procargs(argc, argv); -#if ENABLE_FEATURE_EDITING_SAVEHISTORY - if (iflag) { - const char *hp = lookupvar("HISTFILE"); - - if (hp == NULL) { - hp = lookupvar("HOME"); - if (hp != NULL) { - char *defhp = concat_path_file(hp, ".ash_history"); - setvar("HISTFILE", defhp, 0); - free(defhp); - } - } - } -#endif - if (argv[0] && argv[0][0] == '-') - isloginsh = 1; - if (isloginsh) { - state = 1; - read_profile("/etc/profile"); - state1: - state = 2; - read_profile(".profile"); - } - state2: - state = 3; - if ( -#ifndef linux - getuid() == geteuid() && getgid() == getegid() && -#endif - iflag - ) { - shinit = lookupvar("ENV"); - if (shinit != NULL && *shinit != '\0') { - read_profile(shinit); - } - } - state3: - state = 4; - if (minusc) - evalstring(minusc, 0); - - if (sflag || minusc == NULL) { -#if ENABLE_FEATURE_EDITING_SAVEHISTORY - if ( iflag ) { - const char *hp = lookupvar("HISTFILE"); - - if (hp != NULL) - line_input_state->hist_file = hp; - } -#endif - state4: /* XXX ??? - why isn't this before the "if" statement */ - cmdloop(1); - } -#if PROFILE - monitor(0); -#endif -#ifdef GPROF - { - extern void _mcleanup(void); - _mcleanup(); - } -#endif - exitshell(); - /* NOTREACHED */ -} - - /* * Read and execute commands. "Top" is nonzero for the top level command * loop; it turns on prompting if the shell is interactive. @@ -8006,25 +7810,6 @@ cmdloop(int top) /* - * Read /etc/profile or .profile. Return on error. - */ -static void -read_profile(const char *name) -{ - int skip; - - if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0) - return; - - skip = cmdloop(0); - popfile(); - - if (skip) - exitshell(); -} - - -/* * Read a file containing shell functions. */ static void @@ -8134,8 +7919,8 @@ testcmd(int argc, char **argv) /* * Same for malloc, realloc, but returns an error when out of space. */ -static pointer -ckrealloc(pointer p, size_t nbytes) +static void * +ckrealloc(void * p, size_t nbytes) { p = realloc(p, nbytes); if (p == NULL) @@ -8143,7 +7928,7 @@ ckrealloc(pointer p, size_t nbytes) return p; } -static pointer +static void * ckmalloc(size_t nbytes) { return ckrealloc(NULL, nbytes); @@ -8170,7 +7955,7 @@ savestr(const char *s) * The size 504 was chosen because the Ultrix malloc handles that size * well. */ -static pointer +static void * stalloc(size_t nbytes) { char *p; @@ -8205,7 +7990,7 @@ stalloc(size_t nbytes) static void -stunalloc(pointer p) +stunalloc(void *p) { #if DEBUG if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) { @@ -8280,7 +8065,7 @@ growstackblock(void) sp = stackp; prevstackp = sp->prev; grosslen = newlen + sizeof(struct stack_block) - MINSIZE; - sp = ckrealloc((pointer)sp, grosslen); + sp = ckrealloc(sp, grosslen); sp->prev = prevstackp; stackp = sp; stacknxt = sp->space; @@ -8710,71 +8495,9 @@ freefunc(struct funcnode *f) } -static void options(int); static void setoption(int, int); -/* - * Process the shell command line arguments. - */ -static void -procargs(int argc, char **argv) -{ - int i; - const char *xminusc; - char **xargv; - - xargv = argv; - arg0 = xargv[0]; - if (argc > 0) - xargv++; - for (i = 0; i < NOPTS; i++) - optlist[i] = 2; - argptr = xargv; - options(1); - xargv = argptr; - xminusc = minusc; - if (*xargv == NULL) { - if (xminusc) - ash_msg_and_raise_error(bb_msg_requires_arg, "-c"); - sflag = 1; - } - if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1)) - iflag = 1; - if (mflag == 2) - mflag = iflag; - for (i = 0; i < NOPTS; i++) - if (optlist[i] == 2) - optlist[i] = 0; -#if DEBUG == 2 - debug = 1; -#endif - /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */ - if (xminusc) { - minusc = *xargv++; - if (*xargv) - goto setarg0; - } else if (!sflag) { - setinputfile(*xargv, 0); - setarg0: - arg0 = *xargv++; - commandname = arg0; - } - - shellparam.p = xargv; -#if ENABLE_ASH_GETOPTS - shellparam.optind = 1; - shellparam.optoff = -1; -#endif - /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */ - while (*xargv) { - shellparam.nparam++; - xargv++; - } - optschanged(); -} - - static void optschanged(void) { @@ -8790,19 +8513,19 @@ static void minus_o(char *name, int val) { int i; - if (name == NULL) { - out1str("Current option settings\n"); - for (i = 0; i < NOPTS; i++) - out1fmt("%-16s%s\n", optnames(i), - optlist[i] ? "on" : "off"); - } else { - for (i = 0; i < NOPTS; i++) + if (name) { + for (i = 0; i < NOPTS; i++) { if (equal(name, optnames(i))) { optlist[i] = val; return; } + } ash_msg_and_raise_error("Illegal option -o %s", name); } + out1str("Current option settings\n"); + for (i = 0; i < NOPTS; i++) + out1fmt("%-16s%s\n", optnames(i), + optlist[i] ? "on" : "off"); } @@ -8865,11 +8588,12 @@ setoption(int flag, int val) { int i; - for (i = 0; i < NOPTS; i++) + for (i = 0; i < NOPTS; i++) { if (optletters(i) == flag) { optlist[i] = val; return; } + } ash_msg_and_raise_error("Illegal option -%c", flag); /* NOTREACHED */ } @@ -8980,13 +8704,13 @@ getoptsreset(const char *value) #if ENABLE_LOCALE_SUPPORT static void change_lc_all(const char *value) { - if (value != 0 && *value != 0) + if (value && *value != '\0') setlocale(LC_ALL, value); } static void change_lc_ctype(const char *value) { - if (value != 0 && *value != 0) + if (value && *value != '\0') setlocale(LC_CTYPE, value); } @@ -9188,7 +8912,6 @@ nextopt(const char *optstring) #define EOFMARKLEN 79 - struct heredoc { struct heredoc *next; /* next here document in list */ union node *here; /* redirection node */ @@ -9196,11 +8919,8 @@ struct heredoc { int striptabs; /* if set, strip leading tabs */ }; - - static struct heredoc *heredoclist; /* list of here documents to read */ - static union node *list(int); static union node *andor(void); static union node *pipeline(void); @@ -9214,16 +8934,40 @@ static int readtoken(void); static int xxreadtoken(void); static int readtoken1(int firstc, int syntax, char *eofmark, int striptabs); static int noexpand(char *); -static void synexpect(int) ATTRIBUTE_NORETURN; -static void synerror(const char *) ATTRIBUTE_NORETURN; static void setprompt(int); +static void raise_error_syntax(const char *) ATTRIBUTE_NORETURN; +static void +raise_error_syntax(const char *msg) +{ + ash_msg_and_raise_error("Syntax error: %s", msg); + /* NOTREACHED */ +} + +/* + * Called when an unexpected token is read during the parse. The argument + * is the token that is expected, or -1 if more than one type of token can + * occur at this point. + */ +static void raise_error_unexpected_syntax(int) ATTRIBUTE_NORETURN; +static void +raise_error_unexpected_syntax(int token) +{ + char msg[64]; + int l; + + l = sprintf(msg, "%s unexpected", tokname(lasttoken)); + if (token >= 0) + sprintf(msg + l, " (expecting %s)", tokname(token)); + raise_error_syntax(msg); + /* NOTREACHED */ +} /* * Read and parse a command. Returns NEOF on end of file. (NULL is a * valid parse tree indicating a blank line.) */ -union node * +static union node * parsecmd(int interact) { int t; @@ -9272,7 +9016,7 @@ list(int nlflag) if (n1 == NULL) { n1 = n2; } else { - n3 = (union node *)stalloc(sizeof(struct nbinary)); + n3 = stalloc(sizeof(struct nbinary)); n3->type = NSEMI; n3->nbinary.ch1 = n1; n3->nbinary.ch2 = n2; @@ -9303,7 +9047,7 @@ list(int nlflag) return n1; default: if (nlflag == 1) - synexpect(-1); + raise_error_unexpected_syntax(-1); tokpushback++; return n1; } @@ -9330,7 +9074,7 @@ andor(void) } checkkwd = CHKNL | CHKKWD | CHKALIAS; n2 = pipeline(); - n3 = (union node *)stalloc(sizeof(struct nbinary)); + n3 = stalloc(sizeof(struct nbinary)); n3->type = t; n3->nbinary.ch1 = n1; n3->nbinary.ch2 = n2; @@ -9355,15 +9099,15 @@ pipeline(void) tokpushback++; n1 = command(); if (readtoken() == TPIPE) { - pipenode = (union node *)stalloc(sizeof(struct npipe)); + pipenode = stalloc(sizeof(struct npipe)); pipenode->type = NPIPE; pipenode->npipe.backgnd = 0; - lp = (struct nodelist *)stalloc(sizeof(struct nodelist)); + lp = stalloc(sizeof(struct nodelist)); pipenode->npipe.cmdlist = lp; lp->n = n1; do { prev = lp; - lp = (struct nodelist *)stalloc(sizeof(struct nodelist)); + lp = stalloc(sizeof(struct nodelist)); checkkwd = CHKNL | CHKKWD | CHKALIAS; lp->n = command(); prev->next = lp; @@ -9373,7 +9117,7 @@ pipeline(void) } tokpushback++; if (negate) { - n2 = (union node *)stalloc(sizeof(struct nnot)); + n2 = stalloc(sizeof(struct nnot)); n2->type = NNOT; n2->nnot.com = n1; return n2; @@ -9397,23 +9141,23 @@ command(void) switch (readtoken()) { default: - synexpect(-1); + raise_error_unexpected_syntax(-1); /* NOTREACHED */ case TIF: - n1 = (union node *)stalloc(sizeof(struct nif)); + n1 = stalloc(sizeof(struct nif)); n1->type = NIF; n1->nif.test = list(0); if (readtoken() != TTHEN) - synexpect(TTHEN); + raise_error_unexpected_syntax(TTHEN); n1->nif.ifpart = list(0); n2 = n1; while (readtoken() == TELIF) { - n2->nif.elsepart = (union node *)stalloc(sizeof(struct nif)); + n2->nif.elsepart = stalloc(sizeof(struct nif)); n2 = n2->nif.elsepart; n2->type = NIF; n2->nif.test = list(0); if (readtoken() != TTHEN) - synexpect(TTHEN); + raise_error_unexpected_syntax(TTHEN); n2->nif.ifpart = list(0); } if (lasttoken == TELSE) @@ -9427,13 +9171,13 @@ command(void) case TWHILE: case TUNTIL: { int got; - n1 = (union node *)stalloc(sizeof(struct nbinary)); + n1 = stalloc(sizeof(struct nbinary)); n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL; n1->nbinary.ch1 = list(0); if ((got=readtoken()) != TDO) { TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : "")); - synexpect(TDO); + raise_error_unexpected_syntax(TDO); } n1->nbinary.ch2 = list(0); t = TDONE; @@ -9441,15 +9185,15 @@ command(void) } case TFOR: if (readtoken() != TWORD || quoteflag || ! goodname(wordtext)) - synerror("Bad for loop variable"); - n1 = (union node *)stalloc(sizeof(struct nfor)); + raise_error_syntax("Bad for loop variable"); + n1 = stalloc(sizeof(struct nfor)); n1->type = NFOR; n1->nfor.var = wordtext; checkkwd = CHKKWD | CHKALIAS; if (readtoken() == TIN) { app = ≈ while (readtoken() == TWORD) { - n2 = (union node *)stalloc(sizeof(struct narg)); + n2 = stalloc(sizeof(struct narg)); n2->type = NARG; n2->narg.text = wordtext; n2->narg.backquote = backquotelist; @@ -9459,9 +9203,9 @@ command(void) *app = NULL; n1->nfor.args = ap; if (lasttoken != TNL && lasttoken != TSEMI) - synexpect(-1); + raise_error_unexpected_syntax(-1); } else { - n2 = (union node *)stalloc(sizeof(struct narg)); + n2 = stalloc(sizeof(struct narg)); n2->type = NARG; n2->narg.text = (char *)dolatstr; n2->narg.backquote = NULL; @@ -9476,16 +9220,16 @@ command(void) } checkkwd = CHKNL | CHKKWD | CHKALIAS; if (readtoken() != TDO) - synexpect(TDO); + raise_error_unexpected_syntax(TDO); n1->nfor.body = list(0); t = TDONE; break; case TCASE: - n1 = (union node *)stalloc(sizeof(struct ncase)); + n1 = stalloc(sizeof(struct ncase)); n1->type = NCASE; if (readtoken() != TWORD) - synexpect(TWORD); - n1->ncase.expr = n2 = (union node *)stalloc(sizeof(struct narg)); + raise_error_unexpected_syntax(TWORD); + n1->ncase.expr = n2 = stalloc(sizeof(struct narg)); n2->type = NARG; n2->narg.text = wordtext; n2->narg.backquote = backquotelist; @@ -9494,7 +9238,7 @@ command(void) checkkwd = CHKKWD | CHKALIAS; } while (readtoken() == TNL); if (lasttoken != TIN) - synexpect(TIN); + raise_error_unexpected_syntax(TIN); cpp = &n1->ncase.cases; next_case: checkkwd = CHKNL | CHKKWD; @@ -9502,11 +9246,11 @@ command(void) while (t != TESAC) { if (lasttoken == TLP) readtoken(); - *cpp = cp = (union node *)stalloc(sizeof(struct nclist)); + *cpp = cp = stalloc(sizeof(struct nclist)); cp->type = NCLIST; app = &cp->nclist.pattern; for (;;) { - *app = ap = (union node *)stalloc(sizeof(struct narg)); + *app = ap = stalloc(sizeof(struct narg)); ap->type = NARG; ap->narg.text = wordtext; ap->narg.backquote = backquotelist; @@ -9517,7 +9261,7 @@ command(void) } ap->narg.next = NULL; if (lasttoken != TRP) - synexpect(TRP); + raise_error_unexpected_syntax(TRP); cp->nclist.body = list(2); cpp = &cp->nclist.next; @@ -9526,15 +9270,14 @@ command(void) t = readtoken(); if (t != TESAC) { if (t != TENDCASE) - synexpect(TENDCASE); - else - goto next_case; + raise_error_unexpected_syntax(TENDCASE); + goto next_case; } } *cpp = NULL; goto redir; case TLP: - n1 = (union node *)stalloc(sizeof(struct nredir)); + n1 = stalloc(sizeof(struct nredir)); n1->type = NSUBSHELL; n1->nredir.n = list(0); n1->nredir.redirect = NULL; @@ -9551,7 +9294,7 @@ command(void) } if (readtoken() != t) - synexpect(t); + raise_error_unexpected_syntax(t); redir: /* Now check for redirection which may follow command */ @@ -9566,7 +9309,7 @@ command(void) *rpp = NULL; if (redir) { if (n1->type != NSUBSHELL) { - n2 = (union node *)stalloc(sizeof(struct nredir)); + n2 = stalloc(sizeof(struct nredir)); n2->type = NREDIR; n2->nredir.n = n1; n1 = n2; @@ -9598,7 +9341,7 @@ simplecmd(void) checkkwd = savecheckkwd; switch (readtoken()) { case TWORD: - n = (union node *)stalloc(sizeof(struct narg)); + n = stalloc(sizeof(struct narg)); n->type = NARG; n->narg.text = wordtext; n->narg.backquote = backquotelist; @@ -9617,24 +9360,21 @@ simplecmd(void) parsefname(); /* read name of redirection file */ break; case TLP: - if ( - args && app == &args->narg.next && - !vars && !redir + if (args && app == &args->narg.next + && !vars && !redir ) { struct builtincmd *bcmd; const char *name; /* We have a function */ if (readtoken() != TRP) - synexpect(TRP); + raise_error_unexpected_syntax(TRP); name = n->narg.text; - if ( - !goodname(name) || ( - (bcmd = find_builtin(name)) && - IS_BUILTIN_SPECIAL(bcmd) - ) - ) - synerror("Bad function name"); + if (!goodname(name) + || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd)) + ) { + raise_error_syntax("Bad function name"); + } n->type = NDEFUN; checkkwd = CHKNL | CHKKWD | CHKALIAS; n->narg.next = command(); @@ -9650,7 +9390,7 @@ simplecmd(void) *app = NULL; *vpp = NULL; *rpp = NULL; - n = (union node *)stalloc(sizeof(struct ncmd)); + n = stalloc(sizeof(struct ncmd)); n->type = NCMD; n->ncmd.args = args; n->ncmd.assign = vars; @@ -9663,7 +9403,7 @@ makename(void) { union node *n; - n = (union node *)stalloc(sizeof(struct narg)); + n = stalloc(sizeof(struct narg)); n->type = NARG; n->narg.next = NULL; n->narg.text = wordtext; @@ -9682,11 +9422,9 @@ static void fixredir(union node *n, const char *text, int err) else if (LONE_DASH(text)) n->ndup.dupfd = -1; else { - if (err) - synerror("Bad fd number"); - else - n->ndup.vname = makename(); + raise_error_syntax("Bad fd number"); + n->ndup.vname = makename(); } } @@ -9697,7 +9435,7 @@ parsefname(void) union node *n = redirnode; if (readtoken() != TWORD) - synexpect(-1); + raise_error_unexpected_syntax(-1); if (n->type == NHERE) { struct heredoc *here = heredoc; struct heredoc *p; @@ -9707,7 +9445,7 @@ parsefname(void) n->type = NXHERE; TRACE(("Here document %d\n", n->type)); if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN) - synerror("Illegal eof marker for << redirection"); + raise_error_syntax("Illegal eof marker for << redirection"); rmescapes(wordtext); here->eofmark = wordtext; here->next = NULL; @@ -9743,7 +9481,7 @@ parseheredoc(void) } readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX, here->eofmark, here->striptabs); - n = (union node *)stalloc(sizeof(struct narg)); + n = stalloc(sizeof(struct narg)); n->narg.type = NARG; n->narg.next = NULL; n->narg.text = wordtext; @@ -9845,10 +9583,8 @@ readtoken(void) * We could also make parseoperator in essence the main routine, and * have parseword (readtoken1?) handle both words and redirection.] */ - #define NEW_xxreadtoken #ifdef NEW_xxreadtoken - /* singles must be first! */ static const char xxreadtoken_chars[7] = { '\n', '(', ')', '&', '|', ';', 0 }; @@ -9881,9 +9617,9 @@ static int xxreadtoken(void) if ((c != ' ') && (c != '\t') #if ENABLE_ASH_ALIAS - && (c != PEOA) + && (c != PEOA) #endif - ) { + ) { if (c == '#') { while ((c = pgetc()) != '\n' && c != PEOF); pungetc(); @@ -9907,7 +9643,7 @@ static int xxreadtoken(void) p = strchr(xxreadtoken_chars, c); if (p == NULL) { - READTOKEN1: + READTOKEN1: return readtoken1(c, BASESYNTAX, (char *) NULL, 0); } @@ -9924,11 +9660,8 @@ static int xxreadtoken(void) } } /* for */ } - - #else #define RETURN(token) return lasttoken = token - static int xxreadtoken(void) { @@ -10199,14 +9932,14 @@ readtoken1(int firstc, int syntax, char *eofmark, int striptabs) endword: #if ENABLE_ASH_MATH_SUPPORT if (syntax == ARISYNTAX) - synerror("Missing '))'"); + raise_error_syntax("Missing '))'"); #endif if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL) - synerror("Unterminated quoted string"); + raise_error_syntax("Unterminated quoted string"); if (varnest != 0) { startlinno = plinno; /* { */ - synerror("Missing '}'"); + raise_error_syntax("Missing '}'"); } USTPUTC('\0', out); len = out - (char *)stackblock(); @@ -10277,7 +10010,7 @@ parseredir: { char fd = *out; union node *np; - np = (union node *)stalloc(sizeof(struct nfile)); + np = stalloc(sizeof(struct nfile)); if (c == '>') { np->nfile.fd = 1; c = pgetc(); @@ -10297,11 +10030,11 @@ parseredir: { switch (c) { case '<': if (sizeof(struct nfile) != sizeof(struct nhere)) { - np = (union node *)stalloc(sizeof(struct nhere)); + np = stalloc(sizeof(struct nhere)); np->nfile.fd = 0; } np->type = NHERE; - heredoc = (struct heredoc *)stalloc(sizeof(struct heredoc)); + heredoc = stalloc(sizeof(struct heredoc)); heredoc->here = np; c = pgetc(); if (c == '-') { @@ -10356,7 +10089,7 @@ parsesub: { #if ENABLE_ASH_MATH_SUPPORT PARSEARITH(); #else - synerror("We unsupport $((arith))"); + raise_error_syntax("We unsupport $((arith))"); #endif } else { pungetc(); @@ -10392,7 +10125,7 @@ parsesub: { USTPUTC(c, out); c = pgetc(); } else - badsub: synerror("Bad substitution"); + badsub: raise_error_syntax("Bad substitution"); STPUTC('=', out); flags = 0; @@ -10523,7 +10256,7 @@ parsebackq: { case PEOA: #endif startlinno = plinno; - synerror("EOF in backquote substitution"); + raise_error_syntax("EOF in backquote substitution"); case '\n': plinno++; @@ -10546,7 +10279,7 @@ parsebackq: { nlpp = &bqlist; while (*nlpp) nlpp = &(*nlpp)->next; - *nlpp = (struct nodelist *)stalloc(sizeof(struct nodelist)); + *nlpp = stalloc(sizeof(**nlpp)); (*nlpp)->next = NULL; parsebackquote = oldstyle; @@ -10561,7 +10294,7 @@ parsebackq: { doprompt = saveprompt; else { if (readtoken() != TRP) - synexpect(TRP); + raise_error_unexpected_syntax(TRP); } (*nlpp)->n = n; @@ -10592,8 +10325,7 @@ parsebackq: { USTPUTC(CTLBACKQ, out); if (oldstyle) goto parsebackq_oldreturn; - else - goto parsebackq_newreturn; + goto parsebackq_newreturn; } #if ENABLE_ASH_MATH_SUPPORT @@ -10606,9 +10338,9 @@ parsearith: { syntax = ARISYNTAX; USTPUTC(CTLARI, out); if (dblquote) - USTPUTC('"',out); + USTPUTC('"', out); else - USTPUTC(' ',out); + USTPUTC(' ', out); } else { /* * we collapse embedded arithmetic expansion to @@ -10667,31 +10399,6 @@ endofname(const char *name) /* - * Called when an unexpected token is read during the parse. The argument - * is the token that is expected, or -1 if more than one type of token can - * occur at this point. - */ -static void synexpect(int token) -{ - char msg[64]; - int l; - - l = sprintf(msg, "%s unexpected", tokname(lasttoken)); - if (token >= 0) - sprintf(msg + l, " (expecting %s)", tokname(token)); - synerror(msg); - /* NOTREACHED */ -} - -static void -synerror(const char *msg) -{ - ash_msg_and_raise_error("Syntax error: %s", msg); - /* NOTREACHED */ -} - - -/* * called by editline -- any expansions to the prompt * should be added here. */ @@ -12353,7 +12060,7 @@ dash_arith(const char *s) else if (errcode == -5) ash_msg_and_raise_error("expression recursion loop detected"); else - synerror(s); + raise_error_syntax(s); } INT_ON; @@ -13485,6 +13192,257 @@ static arith_t arith(const char *expr, int *perrcode) #endif /* ASH_MATH_SUPPORT */ +/* ============ main() and helpers + * + * Main routine. We initialize things, parse the arguments, execute + * profiles if we're a login shell, and then call cmdloop to execute + * commands. The setjmp call sets up the location to jump to when an + * exception occurs. When an exception occurs the variable "state" + * is used to figure out how far we had gotten. + */ + +static void init(void) +{ + /* from input.c: */ + basepf.nextc = basepf.buf = basebuf; + + /* from trap.c: */ + signal(SIGCHLD, SIG_DFL); + + /* from var.c: */ + { + char **envp; + char ppid[32]; + const char *p; + struct stat st1, st2; + + initvar(); + for (envp = environ; envp && *envp; envp++) { + if (strchr(*envp, '=')) { + setvareq(*envp, VEXPORT|VTEXTFIXED); + } + } + + snprintf(ppid, sizeof(ppid), "%d", (int) getppid()); + setvar("PPID", ppid, 0); + + p = lookupvar("PWD"); + if (p) + if (*p != '/' || stat(p, &st1) || stat(".", &st2) + || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino) + p = '\0'; + setpwd(p, 0); + } +} + +/* + * Process the shell command line arguments. + */ +static void +procargs(int argc, char **argv) +{ + int i; + const char *xminusc; + char **xargv; + + xargv = argv; + arg0 = xargv[0]; + if (argc > 0) + xargv++; + for (i = 0; i < NOPTS; i++) + optlist[i] = 2; + argptr = xargv; + options(1); + xargv = argptr; + xminusc = minusc; + if (*xargv == NULL) { + if (xminusc) + ash_msg_and_raise_error(bb_msg_requires_arg, "-c"); + sflag = 1; + } + if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1)) + iflag = 1; + if (mflag == 2) + mflag = iflag; + for (i = 0; i < NOPTS; i++) + if (optlist[i] == 2) + optlist[i] = 0; +#if DEBUG == 2 + debug = 1; +#endif + /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */ + if (xminusc) { + minusc = *xargv++; + if (*xargv) + goto setarg0; + } else if (!sflag) { + setinputfile(*xargv, 0); + setarg0: + arg0 = *xargv++; + commandname = arg0; + } + + shellparam.p = xargv; +#if ENABLE_ASH_GETOPTS + shellparam.optind = 1; + shellparam.optoff = -1; +#endif + /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */ + while (*xargv) { + shellparam.nparam++; + xargv++; + } + optschanged(); +} + +/* + * Read /etc/profile or .profile. + */ +static void +read_profile(const char *name) +{ + int skip; + + if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0) + return; + skip = cmdloop(0); + popfile(); + if (skip) + exitshell(); +} + +#if PROFILE +static short profile_buf[16384]; +extern int etext(); +#endif + +int ash_main(int argc, char **argv); +int ash_main(int argc, char **argv) +{ + char *shinit; + volatile int state; + struct jmploc jmploc; + struct stackmark smark; + +#ifdef __GLIBC__ + dash_errno = __errno_location(); +#endif + +#if PROFILE + monitor(4, etext, profile_buf, sizeof(profile_buf), 50); +#endif + +#if ENABLE_FEATURE_EDITING + line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP); +#endif + state = 0; + if (setjmp(jmploc.loc)) { + int e; + int s; + + reset(); + + e = exception; + if (e == EXERROR) + exitstatus = 2; + s = state; + if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) + exitshell(); + + if (e == EXINT) { + outcslow('\n', stderr); + } + popstackmark(&smark); + FORCE_INT_ON; /* enable interrupts */ + if (s == 1) + goto state1; + else if (s == 2) + goto state2; + else if (s == 3) + goto state3; + else + goto state4; + } + exception_handler = &jmploc; +#if DEBUG + opentrace(); + trputs("Shell args: "); + trargs(argv); +#endif + rootpid = getpid(); + +#if ENABLE_ASH_RANDOM_SUPPORT + rseed = rootpid + time(NULL); +#endif + init(); + setstackmark(&smark); + procargs(argc, argv); +#if ENABLE_FEATURE_EDITING_SAVEHISTORY + if (iflag) { + const char *hp = lookupvar("HISTFILE"); + + if (hp == NULL) { + hp = lookupvar("HOME"); + if (hp != NULL) { + char *defhp = concat_path_file(hp, ".ash_history"); + setvar("HISTFILE", defhp, 0); + free(defhp); + } + } + } +#endif + if (argv[0] && argv[0][0] == '-') + isloginsh = 1; + if (isloginsh) { + state = 1; + read_profile("/etc/profile"); + state1: + state = 2; + read_profile(".profile"); + } + state2: + state = 3; + if ( +#ifndef linux + getuid() == geteuid() && getgid() == getegid() && +#endif + iflag + ) { + shinit = lookupvar("ENV"); + if (shinit != NULL && *shinit != '\0') { + read_profile(shinit); + } + } + state3: + state = 4; + if (minusc) + evalstring(minusc, 0); + + if (sflag || minusc == NULL) { +#if ENABLE_FEATURE_EDITING_SAVEHISTORY + if ( iflag ) { + const char *hp = lookupvar("HISTFILE"); + + if (hp != NULL) + line_input_state->hist_file = hp; + } +#endif + state4: /* XXX ??? - why isn't this before the "if" statement */ + cmdloop(1); + } +#if PROFILE + monitor(0); +#endif +#ifdef GPROF + { + extern void _mcleanup(void); + _mcleanup(); + } +#endif + exitshell(); + /* NOTREACHED */ +} + #if DEBUG const char *applet_name = "debug stuff usage"; int main(int argc, char **argv) @@ -13493,6 +13451,7 @@ int main(int argc, char **argv) } #endif + /*- * Copyright (c) 1989, 1991, 1993, 1994 * The Regents of the University of California. All rights reserved. |