#undef JOBS
#endif
-#if JOBS
+#if JOBS || defined(CONFIG_ASH_READ_NCHARS)
#include <termios.h>
#endif
* more fun than worrying about efficiency and portability. :-))
*/
-#define barrier() ({ __asm__ __volatile__ ("": : :"memory"); })
+#define xbarrier() ({ __asm__ __volatile__ ("": : :"memory"); })
#define INTOFF \
({ \
suppressint++; \
- barrier(); \
+ xbarrier(); \
0; \
})
#define SAVEINT(v) ((v) = suppressint)
#define RESTOREINT(v) \
({ \
- barrier(); \
+ xbarrier(); \
if ((suppressint = (v)) == 0 && intpending) onint(); \
0; \
})
#define EXSIGON() \
({ \
exsig++; \
- barrier(); \
+ xbarrier(); \
if (pendingsigs) \
exraise(EXSIG); \
0; \
#else
#define INTON \
({ \
- barrier(); \
+ xbarrier(); \
if (--suppressint == 0 && intpending) onint(); \
0; \
})
#define FORCEINTON \
({ \
- barrier(); \
+ xbarrier(); \
suppressint = 0; \
if (intpending) onint(); \
0; \
})
#endif /* CONFIG_ASH_OPTIMIZE_FOR_SIZE */
-/*
- * BSD setjmp saves the signal mask, which violates ANSI C and takes time,
- * so we use _setjmp instead.
- */
-
-#if defined(BSD) && !defined(__SVR4) && !defined(__GLIBC__)
-#define setjmp(jmploc) _setjmp(jmploc)
-#define longjmp(jmploc, val) _longjmp(jmploc, val)
-#endif
-
/* $NetBSD: expand.h,v 1.13 2002/11/24 22:35:40 christos Exp $ */
struct strlist {
#define __builtin_expect(x, expected_value) (x)
#endif
-#define likely(x) __builtin_expect((x),1)
+#define xlikely(x) __builtin_expect((x),1)
#define TEOF 0
#endif
static int dotcmd(int, char **);
static int evalcmd(int, char **);
+#ifdef CONFIG_ASH_BUILTIN_ECHO
+static int echocmd(int, char **);
+#endif
static int execcmd(int, char **);
static int exitcmd(int, char **);
static int exportcmd(int, char **);
/* unsigned flags; */
};
-#ifdef CONFIG_ASH_CMDCMD
-# ifdef JOBS
-# ifdef CONFIG_ASH_ALIAS
-# define COMMANDCMD (builtincmd + 7)
-# define EXECCMD (builtincmd + 10)
-# else
-# define COMMANDCMD (builtincmd + 6)
-# define EXECCMD (builtincmd + 9)
-# endif
-# else /* ! JOBS */
-# ifdef CONFIG_ASH_ALIAS
-# define COMMANDCMD (builtincmd + 6)
-# define EXECCMD (builtincmd + 9)
-# else
-# define COMMANDCMD (builtincmd + 5)
-# define EXECCMD (builtincmd + 8)
-# endif
-# endif /* JOBS */
-#else /* ! CONFIG_ASH_CMDCMD */
-# ifdef JOBS
-# ifdef CONFIG_ASH_ALIAS
-# define EXECCMD (builtincmd + 9)
-# else
-# define EXECCMD (builtincmd + 8)
-# endif
-# else /* ! JOBS */
-# ifdef CONFIG_ASH_ALIAS
-# define EXECCMD (builtincmd + 8)
-# else
-# define EXECCMD (builtincmd + 7)
-# endif
-# endif /* JOBS */
-#endif /* CONFIG_ASH_CMDCMD */
+
+#define COMMANDCMD (builtincmd + 5 + \
+ ENABLE_ASH_ALIAS + ENABLE_ASH_JOB_CONTROL)
+#define EXECCMD (builtincmd + 7 + \
+ ENABLE_ASH_CMDCMD + ENABLE_ASH_ALIAS + \
+ ENABLE_ASH_BUILTIN_ECHO + ENABLE_ASH_JOB_CONTROL)
#define BUILTIN_NOSPEC "0"
#define BUILTIN_SPECIAL "1"
#define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
#define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
+#define IS_BUILTIN_ASSIGN(builtincmd) ((builtincmd)->name[0] & 4)
static const struct builtincmd builtincmd[] = {
{ BUILTIN_SPEC_REG ".", dotcmd },
{ BUILTIN_REGULAR "command", commandcmd },
#endif
{ BUILTIN_SPEC_REG "continue", breakcmd },
+#ifdef CONFIG_ASH_BUILTIN_ECHO
+ { BUILTIN_REGULAR "echo", echocmd },
+#endif
{ BUILTIN_SPEC_REG "eval", evalcmd },
{ BUILTIN_SPEC_REG "exec", execcmd },
{ BUILTIN_SPEC_REG "exit", exitcmd },
{
char **envp;
char ppid[32];
+ const char *p;
+ struct stat st1, st2;
initvar();
- for (envp = environ ; *envp ; envp++) {
+ for (envp = environ ; envp && *envp ; envp++) {
if (strchr(*envp, '=')) {
setvareq(*envp, VEXPORT|VTEXTFIXED);
}
snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
setvar("PPID", ppid, 0);
- setpwd(0, 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);
}
}
#define bflag optlist[11]
#define uflag optlist[12]
#define qflag optlist[13]
+#define viflag optlist[14]
#ifdef DEBUG
-#define nolog optlist[14]
-#define debug optlist[15]
-#define NOPTS 16
-#else
-#define NOPTS 14
+#define nolog optlist[15]
+#define debug optlist[16]
+#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 $ */
-static const char *const optletters_optnames[NOPTS] = {
+static const char *const optletters_optnames[] = {
"e" "errexit",
"f" "noglob",
"I" "ignoreeof",
"b" "notify",
"u" "nounset",
"q" "quietprofile",
+ "\0" "vi",
#ifdef DEBUG
"\0" "nolog",
"\0" "debug",
#define optletters(n) optletters_optnames[(n)][0]
#define optnames(n) (&optletters_optnames[(n)][1])
+#define NOPTS (sizeof(optletters_optnames)/sizeof(optletters_optnames[0]))
static char optlist[NOPTS];
else if (dest[0] == '-' && dest[1] == '\0') {
dest = bltinlookup("OLDPWD");
flags |= CD_PRINT;
- goto step7;
}
if (!dest)
dest = nullstr;
static void
exvwarning(const char *msg, va_list ap)
{
- FILE *errs;
- const char *name;
- const char *fmt;
+ FILE *errs;
- errs = stderr;
- name = arg0;
- fmt = "%s: ";
- if (commandname) {
- name = commandname;
- fmt = "%s: %d: ";
- }
- fprintf(errs, fmt, name, startlinno);
- vfprintf(errs, msg, ap);
- outcslow('\n', errs);
+ errs = stderr;
+ fprintf(errs, "%s: ", arg0);
+ if (commandname) {
+ const char *fmt = (!iflag || parsefile->fd) ?
+ "%s: %d: " : "%s: ";
+ fprintf(errs, fmt, commandname, startlinno);
+ }
+ vfprintf(errs, msg, ap);
+ outcslow('\n', errs);
}
/*
}
#endif
+static inline int
+isassignment(const char *p)
+{
+ const char *q = endofname(p);
+ if (p == q)
+ return 0;
+ return *q == '=';
+}
+#ifdef CONFIG_ASH_EXPAND_PRMT
+static const char *expandstr(const char *ps);
+#else
+#define expandstr(s) s
+#endif
/*
* Execute a simple command.
int cmd_is_exec;
int status;
char **nargv;
+ struct builtincmd *bcmd;
+ int pseudovarflag = 0;
/* First expand the arguments. */
TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
*arglist.lastp = NULL;
argc = 0;
+ if (cmd->ncmd.args)
+ {
+ bcmd = find_builtin(cmd->ncmd.args->narg.text);
+ pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
+ }
+
for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
struct strlist **spp;
spp = arglist.lastp;
- expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
+ if (pseudovarflag && isassignment(argp->narg.text))
+ expandarg(argp, &arglist, EXP_VARTILDE);
+ else
+ expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
+
for (sp = *spp; sp; sp = sp->next)
argc++;
}
const char *p = " %s";
p++;
- dprintf(preverrout_fd, p, ps4val());
+ dprintf(preverrout_fd, p, expandstr(ps4val()));
sp = varlist.list;
for(n = 0; n < 2; n++) {
{
int repeated = 0;
#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
- int flg_bb = 0;
- char *name = cmd;
-
- if(strchr(name, '/') == NULL && find_applet_by_name(name) != NULL) {
- flg_bb = 1;
- }
- if(flg_bb) {
- char **ap;
- char **new;
-
- *argv = name;
- if(strcmp(name, "busybox")) {
- for (ap = argv; *ap; ap++);
- ap = new = xmalloc((ap - argv + 2) * sizeof(char *));
- *ap++ = cmd = "/bin/busybox";
- while ((*ap++ = *argv++));
- argv = new;
- repeated++;
- } else {
- cmd = "/bin/busybox";
- }
+ if(find_applet_by_name(cmd) != NULL) {
+ /* re-exec ourselves with the new arguments */
+ execve("/proc/self/exe",argv,envp);
+ /* If proc isn't mounted, try hardcoded path to busybox binary*/
+ execve("/bin/busybox",argv,envp);
+ /* If they called chroot or otherwise made the binary no longer
+ * executable, fall through */
}
#endif
ifsfirst.next = NULL;
ifslastp = NULL;
argstr(arg->narg.text, flag);
+ p = _STPUTC('\0', expdest);
+ expdest = p - 1;
if (arglist == NULL) {
return; /* here document expanded */
}
- STPUTC('\0', expdest);
- p = grabstackstr(expdest);
+ p = grabstackstr(p);
exparg.lastp = &exparg.list;
/*
* TODO - EXP_REDIR
size_t partlen;
partlen = strlen(p);
-
len += partlen;
- if (len > partlen && sep) {
+
+ if (!(subtype == VSPLUS || subtype == VSLENGTH))
+ memtodest(p, partlen, syntax, quotes);
+
+ if (*ap && sep) {
char *q;
len++;
STPUTC(sep, q);
expdest = q;
}
-
- if (!(subtype == VSPLUS || subtype == VSLENGTH))
- memtodest(p, partlen, syntax, quotes);
}
return len;
case '0':
static void pushfile(void);
-/*
- * Read a line from the script.
- */
-
-static inline char *
-pfgets(char *line, int len)
-{
- char *p = line;
- int nleft = len;
- int c;
-
- while (--nleft > 0) {
- c = pgetc2();
- if (c == PEOF) {
- if (p == line)
- return NULL;
- break;
- }
- *p++ = c;
- if (c == '\n')
- break;
- }
- *p = '\0';
- return line;
-}
-
-
/*
* Read a character from the script, returning PEOF on end of file.
* Nul characters in the input are silently discarded.
}
#endif
+/*
+ * Read a line from the script.
+ */
+
+static inline char *
+pfgets(char *line, int len)
+{
+ char *p = line;
+ int nleft = len;
+ int c;
+
+ while (--nleft > 0) {
+ c = pgetc2();
+ if (c == PEOF) {
+ if (p == line)
+ return NULL;
+ break;
+ }
+ *p++ = c;
+ if (c == '\n')
+ break;
+ }
+ *p = '\0';
+ return line;
+}
+
+
#ifdef CONFIG_FEATURE_COMMAND_EDITING
static const char *cmdedit_prompt;
if (!iflag || parsefile->fd)
nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
else {
+#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
cmdedit_path_lookup = pathval();
+#endif
nr = cmdedit_read_input((char *) cmdedit_prompt, buf);
if(nr == 0) {
/* Ctrl+C presend */
}
goto retry;
}
- if(nr < 0) {
+ if(nr < 0 && errno == 0) {
/* Ctrl+D presend */
nr = 0;
}
if (**argv == '%') {
jp = getjob(*argv, 0);
pid = -jp->ps[0].pid;
- } else
- pid = number(*argv);
+ } else {
+ pid = **argv == '-' ?
+ -number(*argv + 1) : number(*argv);
+ }
if (kill(pid, signo) != 0) {
- sh_warnx("%m\n");
+ sh_warnx("(%d) - %m", pid);
i = 1;
}
} while (*++argv);
jq--;
#define joff(p) ((struct job *)((char *)(p) + l))
#define jmove(p) (p) = (void *)((char *)(p) + offset)
- if (likely(joff(jp)->ps == &jq->ps0))
+ if (xlikely(joff(jp)->ps == &jq->ps0))
jmove(joff(jp)->ps);
if (joff(jp)->prev_job)
jmove(joff(jp)->prev_job);
char *nextc;
int subtype = 0;
int quoted = 0;
- static const char *const vstype[16] = {
- nullstr, "}", "-", "+", "?", "=",
- "%", "%%", "#", "##", nullstr
+ static const char vstype[VSTYPE + 1][4] = {
+ "", "}", "-", "+", "?", "=",
+ "%", "%%", "#", "##"
};
-
nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
p = s;
while ((c = *p++) != 0) {
goto dostr;
break;
case CTLENDVAR:
+ str = "\"}" + !(quoted & 1);
quoted >>= 1;
subtype = 0;
- if (quoted & 1) {
- str = "\"}";
- goto dostr;
- }
- c = '}';
- break;
+ goto dostr;
case CTLBACKQ:
str = "$(...)";
goto dostr;
case '=':
if (subtype == 0)
break;
+ if ((subtype & VSTYPE) != VSNORMAL)
+ quoted <<= 1;
str = vstype[subtype & VSTYPE];
if (subtype & VSNUL)
c = ':';
else
- c = *str++;
- if (c != '}')
- quoted <<= 1;
+ goto checkstr;
break;
case '\'':
case '\\':
break;
}
USTPUTC(c, nextc);
+checkstr:
if (!str)
continue;
dostr:
for (sp = cmdenviron; sp; sp = sp->next)
setvareq(bb_xstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
- if (argc >= 2) { /* That's what SVR2 does */
+ if (argc >= 2) { /* That's what SVR2 does */
char *fullname;
struct stackmark smark;
/* NOTREACHED */
}
+#ifdef CONFIG_ASH_BUILTIN_ECHO
+static int
+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 $ */
/*
#endif
setinteractive(iflag);
setjobctl(mflag);
+ setvimode(viflag);
}
static inline void
-static inline int
-isassignment(const char *p)
-{
- const char *q = endofname(p);
- if (p == q)
- return 0;
- return *q == '=';
-}
-
/*
* Read and parse a command. Returns NEOF on end of file. (NULL is a
while (here) {
if (needprompt) {
setprompt(2);
- needprompt = 0;
}
readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
here->eofmark, here->striptabs);
}
if (needprompt) {
setprompt(2);
- needprompt = 0;
}
startlinno = plinno;
for (;;) { /* until token or start of word found */
}
if (needprompt) {
setprompt(2);
- needprompt = 0;
}
startlinno = plinno;
for (;;) { /* until token or start of word found */
for (;;) {
if (needprompt) {
setprompt(2);
- needprompt = 0;
}
switch (pc = pgetc()) {
case '`':
* should be added here.
*/
+#ifdef CONFIG_ASH_EXPAND_PRMT
+static const char *
+expandstr(const char *ps)
+{
+ union node n;
+
+ /* XXX Fix (char *) cast. */
+ setinputstring((char *)ps);
+ readtoken1(pgetc(), DQSYNTAX, nullstr, 0);
+ popfile();
+
+ n.narg.type = NARG;
+ n.narg.next = NULL;
+ n.narg.text = wordtext;
+ n.narg.backquote = backquotelist;
+
+ expandarg(&n, NULL, 0);
+ return stackblock();
+}
+#endif
+
static void setprompt(int whichprompt)
{
const char *prompt;
+#ifdef CONFIG_ASH_EXPAND_PRMT
+ struct stackmark smark;
+#endif
+
+ needprompt = 0;
switch (whichprompt) {
case 1:
default: /* 0 */
prompt = nullstr;
}
- putprompt(prompt);
+#ifdef CONFIG_ASH_EXPAND_PRMT
+ setstackmark(&smark);
+ stalloc(stackblocksize());
+#endif
+ putprompt(expandstr(prompt));
+#ifdef CONFIG_ASH_EXPAND_PRMT
+ popstackmark(&smark);
+#endif
}
savestatus = exitstatus;
q = gotsig;
- while (pendingsigs = 0, barrier(), (p = memchr(q, 1, NSIG - 1))) {
+ while (pendingsigs = 0, xbarrier(), (p = memchr(q, 1, NSIG - 1))) {
*p = 0;
p = trap[p - q + 1];
if (!p)
evalstring(p);
}
flushall();
+ setjobctl(0);
#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
if (iflag && rootshell) {
const char *hp = lookupvar("HISTFILE");
INTOFF;
p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
*p++ = '\0';
- if (vallen) {
+ if (val) {
p[-1] = '=';
p = mempcpy(p, val, vallen);
}
int startword;
int status;
int i;
+#if defined(CONFIG_ASH_READ_NCHARS)
+ int nch_flag = 0;
+ int nchars = 0;
+ int silent = 0;
+ struct termios tty, old_tty;
+#endif
+#if defined(CONFIG_ASH_READ_TIMEOUT)
+ fd_set set;
+ struct timeval ts;
+
+ ts.tv_sec = ts.tv_usec = 0;
+#endif
rflag = 0;
prompt = NULL;
- while ((i = nextopt("p:r")) != '\0') {
- if (i == 'p')
+#if defined(CONFIG_ASH_READ_NCHARS) && defined(CONFIG_ASH_READ_TIMEOUT)
+ while ((i = nextopt("p:rt:n:s")) != '\0')
+#elif defined(CONFIG_ASH_READ_NCHARS)
+ while ((i = nextopt("p:rn:s")) != '\0')
+#elif defined(CONFIG_ASH_READ_TIMEOUT)
+ while ((i = nextopt("p:rt:")) != '\0')
+#else
+ while ((i = nextopt("p:r")) != '\0')
+#endif
+ {
+ switch(i) {
+ case 'p':
prompt = optionarg;
- else
+ break;
+#if defined(CONFIG_ASH_READ_NCHARS)
+ case 'n':
+ nchars = strtol(optionarg, &p, 10);
+ if (*p)
+ error("invalid count");
+ nch_flag = (nchars > 0);
+ break;
+ case 's':
+ silent = 1;
+ break;
+#endif
+#if defined(CONFIG_ASH_READ_TIMEOUT)
+ case 't':
+ ts.tv_sec = strtol(optionarg, &p, 10);
+ ts.tv_usec = 0;
+ if (*p == '.') {
+ char *p2;
+ if (*++p) {
+ int scale;
+ ts.tv_usec = strtol(p, &p2, 10);
+ if (*p2)
+ error("invalid timeout");
+ scale = p2 - p;
+ /* normalize to usec */
+ if (scale > 6)
+ error("invalid timeout");
+ while (scale++ < 6)
+ ts.tv_usec *= 10;
+ }
+ } else if (*p) {
+ error("invalid timeout");
+ }
+ if ( ! ts.tv_sec && ! ts.tv_usec)
+ error("invalid timeout");
+ break;
+#endif
+ case 'r':
rflag = 1;
+ break;
+ default:
+ break;
+ }
}
if (prompt && isatty(0)) {
out2str(prompt);
error("arg count");
if ((ifs = bltinlookup("IFS")) == NULL)
ifs = defifs;
+#if defined(CONFIG_ASH_READ_NCHARS)
+ if (nch_flag || silent) {
+ tcgetattr(0, &tty);
+ old_tty = tty;
+ if (nch_flag) {
+ tty.c_lflag &= ~ICANON;
+ tty.c_cc[VMIN] = nchars;
+ }
+ if (silent) {
+ tty.c_lflag &= ~(ECHO|ECHOK|ECHONL);
+
+ }
+ tcsetattr(0, TCSANOW, &tty);
+ }
+#endif
+#if defined(CONFIG_ASH_READ_TIMEOUT)
+ if (ts.tv_sec || ts.tv_usec) {
+ FD_ZERO (&set);
+ FD_SET (0, &set);
+
+ i = select (FD_SETSIZE, &set, NULL, NULL, &ts);
+ if (!i) {
+#if defined(CONFIG_ASH_READ_NCHARS)
+ if (nch_flag)
+ tcsetattr(0, TCSANOW, &old_tty);
+#endif
+ return 1;
+ }
+ }
+#endif
status = 0;
startword = 1;
backslash = 0;
STARTSTACKSTR(p);
- for (;;) {
+#if defined(CONFIG_ASH_READ_NCHARS)
+ while (!nch_flag || nchars--)
+#else
+ for (;;)
+#endif
+ {
if (read(0, &c, 1) != 1) {
status = 1;
break;
STPUTC(c, p);
}
}
+#if defined(CONFIG_ASH_READ_NCHARS)
+ if (nch_flag || silent)
+ tcsetattr(0, TCSANOW, &old_tty);
+#endif
+
STACKSTRNUL(p);
/* Remove trailing blanks */
while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
if(numptr_val < 0)
return -3; /* exponent less than 0 */
else {
- long c = 1;
+ arith_t c = 1;
if(numptr_val)
while(numptr_val--)
goto err;
}
/* save to shell variable */
- sprintf(buf, "%lld", (long long) rez);
+#ifdef CONFIG_ASH_MATH_SUPPORT_64
+ snprintf(buf, sizeof(buf), "%lld", rez);
+#else
+ snprintf(buf, sizeof(buf), "%ld", rez);
+#endif
setvar(numptr_m1->var, buf, 0);
/* after saving, make previous value for v++ or v-- */
if(op == TOK_POST_INC)
goto prologue;
}
if((p = endofname(expr)) != expr) {
- int var_name_size = (p-expr) + 1; /* trailing zero */
+ size_t var_name_size = (p-expr) + 1; /* trailing zero */
numstackptr->var = alloca(var_name_size);
safe_strncpy(numstackptr->var, expr, var_name_size);
continue;
} else if (is_digit(arithval)) {
numstackptr->var = NULL;
+#ifdef CONFIG_ASH_MATH_SUPPORT_64
+ numstackptr->val = strtoll(expr, (char **) &expr, 0);
+#else
numstackptr->val = strtol(expr, (char **) &expr, 0);
+#endif
goto num;
}
for(p = op_tokens; ; p++) {