X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=shell%2Fash.c;h=0f951e84d835b5991e3ae2b5335ed1eca66c6f78;hb=fac312d78bf34833c629232fa5055408715cb65b;hp=59aa336cd63c52f6656e690ee4f5a9bdeb5cefbc;hpb=dc4e75ef7ca135c836d22e380847672cf5b3773b;p=oweals%2Fbusybox.git diff --git a/shell/ash.c b/shell/ash.c index 59aa336cd..0f951e84d 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -33,9 +33,13 @@ * rewrite arith.y to micro stack based cryptic algorithm by * Copyright (c) 2001 Aaron Lehmann * - * Modified by Vladimir Oleynik (c) 2001-2003 to be + * Modified by Paul Mundt (c) 2004 to support + * dynamic variables. + * + * Modified by Vladimir Oleynik (c) 2001-2004 to be * used in busybox and size optimizations, - * support locale, rewrited arith (see notes to this) + * rewrote arith (see notes to this), added locale support, + * rewrote dynamic variables. * */ @@ -88,7 +92,7 @@ #include #include #include - +#include #include @@ -170,7 +174,7 @@ static const char not_found_msg[] = "%s: not found"; * We enclose jmp_buf in a structure so that we can declare pointers to * jump locations. The global variable handler contains the location to * jump to when an exception occurs, and the global variable exception - * contains a code identifying the exeception. To implement nested + * contains a code identifying the exception. To implement nested * exception handlers, the user should save the value of handler on entry * to an inner scope, set handler to point to a jmploc structure for the * inner scope, and restore handler on exit from the scope. @@ -550,6 +554,29 @@ static int parselleft; /* copy of parsefile->lleft */ /* next character in input buffer */ static char *parsenextc; /* copy of parsefile->nextc */ + +struct strpush { + struct strpush *prev; /* preceding string on stack */ + char *prevstring; + int prevnleft; +#ifdef CONFIG_ASH_ALIAS + struct alias *ap; /* if push was associated with an alias */ +#endif + char *string; /* remember the string since it may change */ +}; + +struct parsefile { + struct parsefile *prev; /* preceding file on stack */ + int linno; /* current line */ + int fd; /* file descriptor (or -1 if string) */ + int nleft; /* number of chars left in this line */ + int lleft; /* number of chars left in this buffer */ + char *nextc; /* next char in buffer */ + char *buf; /* input buffer */ + struct strpush *strpush; /* for pushing strings at this level */ + struct strpush basestrpush; /* so pushing one is fast */ +}; + static struct parsefile basepf; /* top level input file */ static char basebuf[IBUFSIZ]; /* buffer for top level input file */ static struct parsefile *parsefile = &basepf; /* current input file */ @@ -1191,7 +1218,7 @@ static char *nodesavestr(char *); -static void evalstring(char *, int); +static void evalstring(char *); union node; /* BLETCH for ansi C */ static void evaltree(union node *, int); static void evalbackcmd(union node *, struct backcmd *); @@ -1419,7 +1446,21 @@ static void defun(char *, union node *); static void unsetfunc(const char *); #ifdef CONFIG_ASH_MATH_SUPPORT -static int dash_arith(const char *); +#ifdef CONFIG_ASH_MATH_SUPPORT_64 +typedef int64_t arith_t; +#else +typedef long arith_t; +#endif +static arith_t dash_arith(const char *); +static arith_t arith(const char *expr, int *perrcode); +#endif + +#ifdef CONFIG_ASH_RANDOM_SUPPORT +static unsigned long rseed; +static void change_random(const char *); +# ifndef DYNAMIC_VAR +# define DYNAMIC_VAR +# endif #endif /* $NetBSD: init.h,v 1.9 2002/11/24 22:35:40 christos Exp $ */ @@ -1442,14 +1483,17 @@ static void reset(void); #define VNOFUNC 0x40 /* don't call the callback function */ #define VNOSET 0x80 /* do not set variable - just readonly test */ #define VNOSAVE 0x100 /* when text is on the heap before setvareq */ - +#ifdef DYNAMIC_VAR +# define VDYNAMIC 0x200 /* dynamic variable */ +# else +# define VDYNAMIC 0 +#endif struct var { struct var *next; /* next entry in hash list */ int flags; /* flags are defined above */ const char *text; /* name=value */ - void (*func)(const char *); - /* function to be called when */ + void (*func)(const char *); /* function to be called when */ /* the variable gets set/unset */ }; @@ -1477,6 +1521,7 @@ static void change_lc_all(const char *value); static void change_lc_ctype(const char *value); #endif + #define VTABSIZE 39 static const char defpathvar[] = "PATH=/usr/local/bin:/usr/bin:/sbin:/bin"; @@ -1501,18 +1546,21 @@ static struct var varinit[] = { #endif { 0, VSTRFIXED|VTEXTFIXED, defpathvar, changepath }, - { 0, VSTRFIXED|VTEXTFIXED, "PS1=$ ", 0 }, - { 0, VSTRFIXED|VTEXTFIXED, "PS2=> ", 0 }, - { 0, VSTRFIXED|VTEXTFIXED, "PS4=+ ", 0 }, + { 0, VSTRFIXED|VTEXTFIXED, "PS1=$ ", 0 }, + { 0, VSTRFIXED|VTEXTFIXED, "PS2=> ", 0 }, + { 0, VSTRFIXED|VTEXTFIXED, "PS4=+ ", 0 }, #ifdef CONFIG_ASH_GETOPTS { 0, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset }, #endif +#ifdef CONFIG_ASH_RANDOM_SUPPORT + {0, VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random }, +#endif #ifdef CONFIG_LOCALE_SUPPORT - {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL=", change_lc_all}, - {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE=", change_lc_ctype}, + {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL\0", change_lc_all }, + {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE\0", change_lc_ctype }, #endif #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY - {0, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE=", NULL}, + {0, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE\0", NULL }, #endif }; @@ -1528,7 +1576,11 @@ static struct var varinit[] = { #define vps2 (&vps1)[1] #define vps4 (&vps2)[1] #define voptind (&vps4)[1] - +#ifdef CONFIG_ASH_GETOPTS +#define vrandom (&voptind)[1] +#else +#define vrandom (&vps4)[1] +#endif #define defpath (defpathvar + 5) /* @@ -1573,28 +1625,6 @@ static inline int varequal(const char *a, const char *b) { static int loopnest; /* current loop nesting level */ -struct strpush { - struct strpush *prev; /* preceding string on stack */ - char *prevstring; - int prevnleft; -#ifdef CONFIG_ASH_ALIAS - struct alias *ap; /* if push was associated with an alias */ -#endif - char *string; /* remember the string since it may change */ -}; - -struct parsefile { - struct parsefile *prev; /* preceding file on stack */ - int linno; /* current line */ - int fd; /* file descriptor (or -1 if string) */ - int nleft; /* number of chars left in this line */ - int lleft; /* number of chars left in this buffer */ - char *nextc; /* next char in buffer */ - char *buf; /* input buffer */ - struct strpush *strpush; /* for pushing strings at this level */ - struct strpush basestrpush; /* so pushing one is fast */ -}; - /* * The parsefile structure pointed to by the global variable parsefile * contains information about the current file being read. @@ -1618,12 +1648,11 @@ extern char **environ; static void outstr(const char *, FILE *); static void outcslow(int, FILE *); static void flushall(void); -static void flushout(FILE *); +static void flusherr(void); static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2))); static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4))); -static void xwrite(int, const void *, size_t); static int preverrout_fd; /* save fd2 before print debug if xflag is set. */ @@ -1636,7 +1665,7 @@ static void out1str(const char *p) static void out2str(const char *p) { outstr(p, stderr); - flushout(stderr); + flusherr(); } /* @@ -2679,7 +2708,7 @@ static const struct builtincmd bltin = { */ /* - * The eval commmand. + * The eval command. */ static int @@ -2703,7 +2732,7 @@ evalcmd(int argc, char **argv) STPUTC('\0', concat); p = grabstackstr(concat); } - evalstring(p, EV_TESTED); + evalstring(p); } return exitstatus; } @@ -2714,7 +2743,7 @@ evalcmd(int argc, char **argv) */ static void -evalstring(char *s, int flag) +evalstring(char *s) { union node *n; struct stackmark smark; @@ -2723,7 +2752,7 @@ evalstring(char *s, int flag) setinputstring(s); while ((n = parsecmd(0)) != NEOF) { - evaltree(n, flag); + evaltree(n, 0); popstackmark(&smark); if (evalskip) break; @@ -3275,7 +3304,7 @@ evalcommand(union node *cmd, int flags) } sp = arglist.list; } - xwrite(preverrout_fd, "\n", 1); + bb_full_write(preverrout_fd, "\n", 1); } cmd_is_exec = 0; @@ -3292,7 +3321,7 @@ evalcommand(union node *cmd, int flags) find_command(argv[0], &cmdentry, cmd_flag, path); if (cmdentry.cmdtype == CMDUNKNOWN) { status = 127; - flushout(stderr); + flusherr(); goto bail; } @@ -3475,10 +3504,17 @@ funcdone: } +static inline int +goodname(const char *p) +{ + return !*endofname(p); +} + /* * Search for a command. This is called before we fork so that the * location of the command will be available in the parent as well as - * the child. + * the child. The check for "goodname" is an overly conservative + * check that the name will not be subject to expansion. */ static void @@ -3487,7 +3523,9 @@ prehash(union node *n) struct cmdentry entry; if (n->type == NCMD && n->ncmd.args) - find_command(n->ncmd.args->narg.text, &entry, 0, pathval()); + if (goodname(n->ncmd.args->narg.text)) + find_command(n->ncmd.args->narg.text, &entry, 0, + pathval()); } @@ -3685,15 +3723,9 @@ tryexec(char *cmd, char **argv, char **envp) int flg_bb = 0; char *name = cmd; -#ifdef CONFIG_FEATURE_SH_APPLETS_ALWAYS_WIN - name = bb_get_last_path_component(name); - if(find_applet_by_name(name) != NULL) - flg_bb = 1; -#else if(strchr(name, '/') == NULL && find_applet_by_name(name) != NULL) { flg_bb = 1; } -#endif if(flg_bb) { char **ap; char **new; @@ -3729,7 +3761,10 @@ repeat: for (ap = argv; *ap; ap++) ; ap = new = ckmalloc((ap - argv + 2) * sizeof(char *)); - *ap++ = cmd = (char *)DEFAULT_SHELL; + ap[1] = cmd; + *ap = cmd = (char *)DEFAULT_SHELL; + ap += 2; + argv++; while ((*ap++ = *argv++)) ; argv = new; @@ -4492,10 +4527,9 @@ static char *exptilde(char *, char *, int); static void expbackq(union node *, int, int); static const char *subevalvar(char *, char *, int, int, int, int, int); static char *evalvar(char *, int); -static int varisset(char *, int); static void strtodest(const char *, int, int); static void memtodest(const char *p, size_t len, int syntax, int quotes); -static void varvalue(char *, int, int); +static ssize_t varvalue(char *, int, int); static void recordregion(int, int, int); static void removerecordregions(int); static void ifsbreakup(char *, struct arglist *); @@ -4503,7 +4537,7 @@ static void ifsfree(void); static void expandmeta(struct strlist *, int); static int patmatch(char *, const char *); -static int cvtnum(long); +static int cvtnum(arith_t); static size_t esclen(const char *, const char *); static char *scanleft(char *, char *, char *, char *, int, int); static char *scanright(char *, char *, char *, char *, int, int); @@ -4548,7 +4582,7 @@ expandhere(union node *arg, int fd) { herefd = fd; expandarg(arg, (struct arglist *)NULL, 0); - xwrite(fd, stackblock(), expdest - (char *)stackblock()); + bb_full_write(fd, stackblock(), expdest - (char *)stackblock()); } @@ -5108,9 +5142,8 @@ evalvar(char *p, int flag) char *var; int patloc; int c; - int set; int startloc; - size_t varlen; + ssize_t varlen; int easy; int quotes; int quoted; @@ -5121,48 +5154,22 @@ evalvar(char *p, int flag) quoted = varflags & VSQUOTE; var = p; easy = (!quoted || (*var == '@' && shellparam.nparam)); - varlen = 0; startloc = expdest - (char *)stackblock(); p = strchr(p, '=') + 1; - if (!is_name(*var)) { - set = varisset(var, varflags & VSNUL); - set--; - if (subtype == VSPLUS) - goto vsplus; - if (++set) { - varvalue(var, quoted, flag); - if (subtype == VSLENGTH) { - varlen = - expdest - (char *)stackblock() - - startloc; - STADJUST(-varlen, expdest); - goto vslen; - } - } - } else { - const char *val; again: - /* jump here after setting a variable with ${var=text} */ - val = lookupvar(var); - set = !val || ((varflags & VSNUL) && !*val); - if (subtype == VSPLUS) - goto vsplus; - if (--set) { - varlen = strlen(val); - if (subtype == VSLENGTH) - goto vslen; - memtodest( - val, varlen, quoted ? DQSYNTAX : BASESYNTAX, - quotes - ); - } - } + varlen = varvalue(var, varflags, flag); + if (varflags & VSNUL) + varlen--; + if (subtype == VSPLUS) { + varlen = -1 - varlen; + goto vsplus; + } if (subtype == VSMINUS) { vsplus: - if (!set) { + if (varlen < 0) { argstr( p, flag | EXP_TILDE | (quoted ? EXP_QWORD : EXP_WORD) @@ -5175,7 +5182,7 @@ vsplus: } if (subtype == VSASSIGN || subtype == VSQUESTION) { - if (!set) { + if (varlen < 0) { if (subevalvar(p, var, 0, subtype, startloc, varflags, 0)) { varflags &= ~VSNUL; @@ -5193,12 +5200,11 @@ vsplus: goto end; } - if (!set && uflag) + if (varlen < 0 && uflag) varunset(p, var, 0, 0); if (subtype == VSLENGTH) { -vslen: - cvtnum(varlen); + cvtnum(varlen > 0 ? varlen : 0); goto record; } @@ -5222,7 +5228,7 @@ record: } #endif - if (set) { + if (varlen >= 0) { /* * Terminate the string and start recording the pattern * right after it @@ -5248,7 +5254,7 @@ end: if ((c = *p++) == CTLESC) p++; else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) { - if (set) + if (varlen >= 0) argbackq = argbackq->next; } else if (c == CTLVAR) { if ((*p++ & VSTYPE) != VSNORMAL) @@ -5263,47 +5269,6 @@ end: } - -/* - * Test whether a specialized variable is set. - */ - -static int -varisset(char *name, int nulok) -{ - if (*name == '!') - return backgndpid != 0; - else if (*name == '@' || *name == '*') { - if (*shellparam.p == NULL) - return 0; - - if (nulok) { - char **av; - - for (av = shellparam.p; *av; av++) - if (**av != '\0') - return 1; - return 0; - } - } else if (is_digit(*name)) { - char *ap; - int num = atoi(name); - - if (num > shellparam.nparam) - return 0; - - if (num == 0) - ap = arg0; - else - ap = shellparam.p[num - 1]; - - if (nulok && (ap == NULL || *ap == '\0')) - return 0; - } - return 1; -} - - /* * Put a string on the stack. */ @@ -5338,19 +5303,24 @@ strtodest(const char *p, int syntax, int quotes) * Add the value of a specialized variable to the stack string. */ -static void -varvalue(char *name, int quoted, int flags) +static ssize_t +varvalue(char *name, int varflags, int flags) { int num; char *p; int i; - int sep; + int sep = 0; int sepq = 0; + ssize_t len = 0; char **ap; int syntax; - int allow_split = flags & EXP_FULL; + int quoted = varflags & VSQUOTE; + int subtype = varflags & VSTYPE; int quotes = flags & (EXP_FULL | EXP_CASE); + if (quoted && (flags & EXP_FULL)) + sep = 1 << CHAR_BIT; + syntax = quoted ? DQSYNTAX : BASESYNTAX; switch (*name) { case '$': @@ -5364,48 +5334,86 @@ varvalue(char *name, int quoted, int flags) goto numvar; case '!': num = backgndpid; + if (num == 0) + return -1; numvar: - cvtnum(num); + len = cvtnum(num); break; case '-': - for (i = 0 ; i < NOPTS ; i++) { - if (optlist[i]) - STPUTC(optletters(i), expdest); + p = makestrspace(NOPTS, expdest); + for (i = NOPTS - 1; i >= 0; i--) { + if (optlist[i]) { + USTPUTC(optletters(i), p); + len++; + } } + expdest = p; break; case '@': - if (allow_split && quoted) { - sep = 1 << CHAR_BIT; + if (sep) goto param; - } /* fall through */ case '*': sep = ifsset() ? ifsval()[0] : ' '; - if (quotes) { - sepq = (SIT(sep, syntax) == CCTL) || (SIT(sep, syntax) == CBACK); - } + if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK)) + sepq = 1; param: - for (ap = shellparam.p ; (p = *ap++) != NULL ; ) { - strtodest(p, syntax, quotes); - if (*ap && sep) { - p = expdest; + if (!(ap = shellparam.p)) + return -1; + while ((p = *ap++)) { + size_t partlen; + + partlen = strlen(p); + + len += partlen; + if (len > partlen && sep) { + char *q; + + len++; + if (subtype == VSPLUS || subtype == VSLENGTH) { + continue; + } + q = expdest; if (sepq) - STPUTC(CTLESC, p); - STPUTC(sep, p); - expdest = p; + STPUTC(CTLESC, q); + STPUTC(sep, q); + expdest = q; } + + if (!(subtype == VSPLUS || subtype == VSLENGTH)) + memtodest(p, partlen, syntax, quotes); } - break; + return len; case '0': - strtodest(arg0, syntax, quotes); - break; - default: + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': num = atoi(name); - if (num > 0 && num <= shellparam.nparam) { - strtodest(shellparam.p[num - 1], syntax, quotes); - } - break; + if (num < 0 || num > shellparam.nparam) + return -1; + p = num ? shellparam.p[num - 1] : arg0; + goto value; + default: + p = lookupvar(name); +value: + if (!p) + return -1; + + len = strlen(p); + if (!(subtype == VSPLUS || subtype == VSLENGTH)) + memtodest(p, len, syntax, quotes); + return len; } + + if (subtype == VSPLUS || subtype == VSLENGTH) + STADJUST(-len, expdest); + return len; } @@ -5900,12 +5908,16 @@ casematch(union node *pattern, char *val) */ static int -cvtnum(long num) +cvtnum(arith_t num) { int len; expdest = makestrspace(32, expdest); +#ifdef CONFIG_ASH_MATH_SUPPORT_64 + len = fmtstr(expdest, 32, "%lld", (long long) num); +#else len = fmtstr(expdest, 32, "%ld", num); +#endif STADJUST(len, expdest); return len; } @@ -6037,10 +6049,16 @@ retry: if (!iflag || parsefile->fd) nr = safe_read(parsefile->fd, buf, BUFSIZ - 1); else { + cmdedit_path_lookup = pathval(); nr = cmdedit_read_input((char *) cmdedit_prompt, buf); if(nr == 0) { /* Ctrl+C presend */ - raise(SIGINT); + if(trap[SIGINT]) { + buf[0] = '\n'; + buf[1] = 0; + raise(SIGINT); + return 1; + } goto retry; } if(nr < 0) { @@ -6678,25 +6696,28 @@ sprint_status(char *s, int status, int sigonly) int st; col = 0; - st = WEXITSTATUS(status); if (!WIFEXITED(status)) { - st = WSTOPSIG(status); #if JOBS - if (!WIFSTOPPED(status)) - st = WTERMSIG(status); + if (WIFSTOPPED(status)) + st = WSTOPSIG(status); + else #endif + st = WTERMSIG(status); if (sigonly) { if (st == SIGINT || st == SIGPIPE) goto out; +#if JOBS if (WIFSTOPPED(status)) goto out; +#endif } st &= 0x7f; - col = fmtstr(s, 32, u_signal_names(NULL, &st, 0)); + col = fmtstr(s, 32, strsignal(st)); if (WCOREDUMP(status)) { col += fmtstr(s + col, 16, " (core dumped)"); } } else if (!sigonly) { + st = WEXITSTATUS(status); if (st) col = fmtstr(s, 16, "Done(%d)", st); else @@ -7217,7 +7238,7 @@ forkshell(struct job *jp, union node *n, int mode) * the interactive program catches interrupts, the user doesn't want * these interrupts to also abort the loop. The approach we take here * is to have the shell ignore interrupt signals while waiting for a - * forground process to terminate, and then send itself an interrupt + * foreground process to terminate, and then send itself an interrupt * signal if the child process was terminated by an interrupt signal. * Unfortunately, some programs want to do a bit of cleanup and then * exit on interrupt; unless these processes terminate themselves by @@ -7442,6 +7463,8 @@ cmdtxt(union node *n) const char *p; char s[2]; + if (!n) + return; switch (n->type) { default: #if DEBUG @@ -7607,7 +7630,7 @@ cmdputs(const char *s) int quoted = 0; static const char *const vstype[16] = { nullstr, "}", "-", "+", "?", "=", - "#", "##", "%", "%%" + "%", "%%", "#", "##", nullstr }; nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc); @@ -7897,6 +7920,10 @@ ash_main(int argc, char **argv) trputs("Shell args: "); trargs(argv); #endif rootpid = getpid(); + +#ifdef CONFIG_ASH_RANDOM_SUPPORT + rseed = rootpid + ((time_t)time((time_t *)0)); +#endif rootshell = 1; init(); setstackmark(&smark); @@ -7939,7 +7966,7 @@ state2: state3: state = 4; if (minusc) - evalstring(minusc, 0); + evalstring(minusc); if (sflag || minusc == NULL) { #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY @@ -7981,8 +8008,8 @@ cmdloop(int top) int numeof = 0; TRACE(("cmdloop(%d) called\n", top)); - setstackmark(&smark); for (;;) { + setstackmark(&smark); if (pendingsigs) dotrap(); #if JOBS @@ -8013,13 +8040,11 @@ cmdloop(int top) evaltree(n, 0); } popstackmark(&smark); - setstackmark(&smark); - if (evalskip == SKIPFILE) { + if (evalskip) { evalskip = 0; break; } } - popstackmark(&smark); } @@ -8110,21 +8135,40 @@ find_dot_file(char *name) /* NOTREACHED */ } -int -dotcmd(int argc, char **argv) +static int dotcmd(int argc, char **argv) { + struct strlist *sp; + volatile struct shparam saveparam; + exitstatus = 0; - if (argc >= 2) { /* That's what SVR2 does */ + 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) { + saveparam = shellparam; + shellparam.malloc = 0; + shellparam.nparam = argc - 2; + shellparam.p = argv + 2; + }; + setinputfile(fullname, 1); commandname = fullname; cmdloop(0); popfile(); + + if (argc > 2) { + freeparam(&shellparam); + shellparam = saveparam; + }; + popstackmark(&smark); } return exitstatus; @@ -8359,7 +8403,7 @@ growstackstr(void) { size_t len = stackblocksize(); if (herefd >= 0 && len >= 1024) { - xwrite(herefd, stackblock(), len); + bb_full_write(herefd, stackblock(), len); return stackblock(); } growstackblock(); @@ -9024,6 +9068,27 @@ static void change_lc_ctype(const char *value) #endif +#ifdef CONFIG_ASH_RANDOM_SUPPORT +/* Roughly copied from bash.. */ +static void change_random(const char *value) +{ + if(value == NULL) { + /* "get", generate */ + char buf[16]; + + rseed = rseed * 1103515245 + 12345; + sprintf(buf, "%d", (unsigned int)((rseed & 32767))); + /* set without recursion */ + setvar(vrandom.text, buf, VNOFUNC); + vrandom.flags &= ~VNOFUNC; + } else { + /* set/reset */ + rseed = strtoul(value, (char **)NULL, 10); + } +} +#endif + + #ifdef CONFIG_ASH_GETOPTS static int getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff) @@ -9032,18 +9097,19 @@ getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *opt char c = '?'; int done = 0; int err = 0; - char s[10]; - char **optnext = optfirst + *param_optind - 1; + char s[12]; + char **optnext; + + if(*param_optind < 1) + return 1; + optnext = optfirst + *param_optind - 1; - if (*param_optind <= 1 || *optoff < 0 || !(*(optnext - 1)) || - strlen(*(optnext - 1)) < *optoff) + if (*param_optind <= 1 || *optoff < 0 || strlen(optnext[-1]) < *optoff) p = NULL; else - p = *(optnext - 1) + *optoff; + p = optnext[-1] + *optoff; if (p == NULL || *p == '\0') { /* Current word is done, advance */ - if (optnext == NULL) - return 1; p = *optnext; if (p == NULL || *p != '-' || *++p == '\0') { atend: @@ -9211,10 +9277,10 @@ flushall(void) } void -flushout(FILE *dest) +flusherr(void) { INTOFF; - fflush(dest); + fflush(stderr); INTON; } @@ -9258,20 +9324,6 @@ fmtstr(char *outbuf, size_t length, const char *fmt, ...) } -/* - * Version of write which resumes after a signal is caught. - */ - -static void -xwrite(int fd, const void *p, size_t n) -{ - ssize_t i; - - do { - i = bb_full_write(fd, p, n); - } while (i < 0 && errno == EINTR); -} - /* $NetBSD: parser.c,v 1.54 2002/11/24 22:35:42 christos Exp $ */ @@ -9313,11 +9365,6 @@ static void synerror(const char *) __attribute__((__noreturn__)); static void setprompt(int); -static inline int -goodname(const char *p) -{ - return !*endofname(p); -} static inline int isassignment(const char *p) @@ -10773,7 +10820,7 @@ noexpand(char *text) * more letters, underscores, and digits). */ -char * +static char * endofname(const char *name) { char *p; @@ -10933,7 +10980,7 @@ openhere(union node *redir) if (redir->type == NHERE) { len = strlen(redir->nhere.doc->narg.text); if (len <= PIPESIZE) { - xwrite(pip[1], redir->nhere.doc->narg.text, len); + bb_full_write(pip[1], redir->nhere.doc->narg.text, len); goto out; } } @@ -10947,7 +10994,7 @@ openhere(union node *redir) #endif signal(SIGPIPE, SIG_DFL); if (redir->type == NHERE) - xwrite(pip[1], redir->nhere.doc->narg.text, len); + bb_full_write(pip[1], redir->nhere.doc->narg.text, len); else expandhere(redir->nhere.doc, pip[1]); _exit(0); @@ -11770,7 +11817,7 @@ dotrap(void) p = trap[p - q + 1]; if (!p) continue; - evalstring(p, 0); + evalstring(p); exitstatus = savestatus; } } @@ -11853,16 +11900,17 @@ 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 (setjmp(loc.loc)) { + if (jmp) goto out; - } handler = &loc; if ((p = trap[0]) != NULL && *p != '\0') { trap[0] = NULL; - evalstring(p, 0); + evalstring(p); } flushall(); #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY @@ -11894,7 +11942,7 @@ static int vpcmp(const void *, const void *); static struct var **findvar(struct var **, const char *); /* - * Initialize the varable symbol tables and import the environment + * Initialize the variable symbol tables and import the environment */ @@ -11979,10 +12027,13 @@ setvareq(char *s, int flags) flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1)); vp = *findvar(vpp, s); if (vp) { - if (vp->flags & VREADONLY) { + if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) { + const char *n; + if (flags & VNOSAVE) free(s); - error("%.*s: is read only", strchrnul(s, '=') - s, s); + n = vp->text; + error("%.*s: is read only", strchrnul(n, '=') - n, n); } if (flags & VNOSET) @@ -12039,9 +12090,21 @@ lookupvar(const char *name) { struct var *v; - if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) { - return strchrnul(v->text, '=') + 1; + if ((v = *findvar(hashvar(name), name))) { +#ifdef DYNAMIC_VAR + /* + * Dynamic variables are implemented roughly the same way they are + * in bash. Namely, they're "special" so long as they aren't unset. + * As soon as they're unset, they're no longer dynamic, and dynamic + * lookup will no longer happen at that point. -- PFM. + */ + if((v->flags & VDYNAMIC)) + (*v->func)(NULL); +#endif + if(!(v->flags & VUNSET)) + return strchrnul(v->text, '=') + 1; } + return NULL; } @@ -12316,6 +12379,9 @@ unsetvar(const char *s) retval = 1; if (flags & VREADONLY) goto out; +#ifdef DYNAMIC_VAR + vp->flags &= ~VDYNAMIC; +#endif if (flags & VUNSET) goto ok; if ((flags & VSTRFIXED) == 0) { @@ -12432,10 +12498,10 @@ static int timescmd(int ac, char **av) } #ifdef CONFIG_ASH_MATH_SUPPORT -static int +static arith_t dash_arith(const char *s) { - long result; + arith_t result; int errcode = 0; INTOFF; @@ -12467,7 +12533,7 @@ static int letcmd(int argc, char **argv) { char **ap; - long i; + arith_t i; ap = argv + 1; if(!*ap) @@ -12483,13 +12549,13 @@ letcmd(int argc, char **argv) /* $NetBSD: miscbltin.c,v 1.31 2002/11/24 22:35:41 christos Exp $ */ /* - * Miscelaneous builtins. + * Miscellaneous builtins. */ #undef rflag #ifdef __GLIBC__ -#if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1 +#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 1 typedef enum __rlimit_resource rlim_t; #endif #endif @@ -12686,34 +12752,86 @@ static const struct limits limits[] = { { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' }, #endif #ifdef RLIMIT_NPROC - { "process(processes)", RLIMIT_NPROC, 1, 'p' }, + { "process", RLIMIT_NPROC, 1, 'p' }, #endif #ifdef RLIMIT_NOFILE - { "nofiles(descriptors)", RLIMIT_NOFILE, 1, 'n' }, + { "nofiles", RLIMIT_NOFILE, 1, 'n' }, #endif -#ifdef RLIMIT_VMEM - { "vmemory(kbytes)", RLIMIT_VMEM, 1024, 'v' }, +#ifdef RLIMIT_AS + { "vmemory(kbytes)", RLIMIT_AS, 1024, 'v' }, #endif -#ifdef RLIMIT_SWAP - { "swap(kbytes)", RLIMIT_SWAP, 1024, 'w' }, +#ifdef RLIMIT_LOCKS + { "locks", RLIMIT_LOCKS, 1, 'w' }, #endif { (char *) 0, 0, 0, '\0' } }; +enum limtype { SOFT = 0x1, HARD = 0x2 }; + +static void printlim(enum limtype how, const struct rlimit *limit, + const struct limits *l) +{ + rlim_t val; + + val = limit->rlim_max; + if (how & SOFT) + val = limit->rlim_cur; + + if (val == RLIM_INFINITY) + out1fmt("unlimited\n"); + else { + val /= l->factor; + out1fmt("%lld\n", (long long) val); + } +} + int ulimitcmd(int argc, char **argv) { int c; rlim_t val = 0; - enum { SOFT = 0x1, HARD = 0x2 } - how = SOFT | HARD; + enum limtype how = SOFT | HARD; const struct limits *l; int set, all = 0; int optc, what; struct rlimit limit; what = 'f'; - while ((optc = nextopt("HSatfdsmcnpl")) != '\0') + while ((optc = nextopt("HSa" +#ifdef RLIMIT_CPU + "t" +#endif +#ifdef RLIMIT_FSIZE + "f" +#endif +#ifdef RLIMIT_DATA + "d" +#endif +#ifdef RLIMIT_STACK + "s" +#endif +#ifdef RLIMIT_CORE + "c" +#endif +#ifdef RLIMIT_RSS + "m" +#endif +#ifdef RLIMIT_MEMLOCK + "l" +#endif +#ifdef RLIMIT_NPROC + "p" +#endif +#ifdef RLIMIT_NOFILE + "n" +#endif +#ifdef RLIMIT_AS + "v" +#endif +#ifdef RLIMIT_LOCKS + "w" +#endif + )) != '\0') switch (optc) { case 'H': how = HARD; @@ -12728,10 +12846,8 @@ ulimitcmd(int argc, char **argv) what = optc; } - for (l = limits; l->name && l->option != what; l++) + for (l = limits; l->option != what; l++) ; - if (!l->name) - error("internal error (%c)", what); set = *argptr ? 1 : 0; if (set) { @@ -12758,19 +12874,8 @@ ulimitcmd(int argc, char **argv) if (all) { for (l = limits; l->name; l++) { getrlimit(l->cmd, &limit); - if (how & SOFT) - val = limit.rlim_cur; - else if (how & HARD) - val = limit.rlim_max; - out1fmt("%-20s ", l->name); - if (val == RLIM_INFINITY) - out1fmt("unlimited\n"); - else - { - val /= l->factor; - out1fmt("%lld\n", (long long) val); - } + printlim(how, &limit, l); } return 0; } @@ -12784,18 +12889,7 @@ ulimitcmd(int argc, char **argv) if (setrlimit(l->cmd, &limit) < 0) error("error setting limit (%m)"); } else { - if (how & SOFT) - val = limit.rlim_cur; - else if (how & HARD) - val = limit.rlim_max; - - if (val == RLIM_INFINITY) - out1fmt("unlimited\n"); - else - { - val /= l->factor; - out1fmt("%lld\n", (long long) val); - } + printlim(how, &limit, l); } return 0; } @@ -12827,14 +12921,14 @@ ulimitcmd(int argc, char **argv) /* This is my infix parser/evaluator. It is optimized for size, intended * as a replacement for yacc-based parsers. However, it may well be faster - * than a comparable parser writen in yacc. The supported operators are + * than a comparable parser written in yacc. The supported operators are * listed in #defines below. Parens, order of operations, and error handling - * are supported. This code is threadsafe. The exact expression format should + * are supported. This code is thread safe. The exact expression format should * be that which POSIX specifies for shells. */ /* The code uses a simple two-stack algorithm. See * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html - * for a detailed explaination of the infix-to-postfix algorithm on which + * for a detailed explanation of the infix-to-postfix algorithm on which * this is based (this code differs in that it applies operators immediately * to the stack instead of adding them to a queue to end up with an * expression). */ @@ -12864,7 +12958,7 @@ ulimitcmd(int argc, char **argv) * parens and then checking that all binary ops and right parens are * preceded by a valid expression (NUM_TOKEN). * - * Note: It may be desireable to replace Aaron's test for whitespace with + * Note: It may be desirable to replace Aaron's test for whitespace with * ctype's isspace() if it is used by another busybox applet or if additional * whitespace chars should be considered. Look below the "#include"s for a * precompiler test. @@ -12890,7 +12984,7 @@ ulimitcmd(int argc, char **argv) * - realize comma separated - expr, expr * - realise ++expr --expr expr++ expr-- * - realise expr ? expr : expr (but, second expr calculate always) - * - allow hexdecimal and octal numbers + * - allow hexadecimal and octal numbers * - was restored loses XOR operator * - remove one goto label, added three ;-) * - protect $((num num)) as true zero expr (Manuel`s error) @@ -12905,7 +12999,7 @@ ulimitcmd(int argc, char **argv) typedef unsigned char operator; /* An operator's token id is a bit of a bitfield. The lower 5 bits are the - * precedence, and 3 high bits are an ID unique accross operators of that + * precedence, and 3 high bits are an ID unique across operators of that * precedence. The ID portion is so that multiple operators can have the * same precedence, ensuring that the leftmost one is evaluated first. * Consider * and /. */ @@ -13010,11 +13104,11 @@ static inline int is_right_associativity(operator prec) typedef struct ARITCH_VAR_NUM { - long val; - long contidional_second_val; + arith_t val; + arith_t contidional_second_val; char contidional_second_val_initialized; char *var; /* if NULL then is regular number, - else is varable name */ + else is variable name */ } v_n_t; @@ -13068,9 +13162,8 @@ static int arith_lookup_val(v_n_t *t) static inline int arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr) { - long numptr_val; v_n_t *numptr_m1; - long rez; + arith_t numptr_val, rez; int ret_arith_lookup_val; if (NUMPTR == numstack) goto err; /* There is no operator that can work @@ -13196,7 +13289,7 @@ arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr) goto err; } /* save to shell variable */ - sprintf(buf, "%ld", rez); + sprintf(buf, "%lld", (long long) rez); setvar(numptr_m1->var, buf, 0); /* after saving, make previous value for v++ or v-- */ if(op == TOK_POST_INC) @@ -13259,7 +13352,7 @@ static const char op_tokens[] = { #define endexpression &op_tokens[sizeof(op_tokens)-7] -extern long arith (const char *expr, int *perrcode) +static arith_t arith (const char *expr, int *perrcode) { register char arithval; /* Current character under analysis */ operator lasttok, op; @@ -13272,7 +13365,7 @@ extern long arith (const char *expr, int *perrcode) /* Stack of integers */ /* The proof that there can be no more than strlen(startbuf)/2+1 integers - * in any given correct or incorrect expression is left as an excersize to + * in any given correct or incorrect expression is left as an exercise to * the reader. */ v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)), *numstackptr = numstack;