* When debugging is on, debugging info will be written to ./trace and
* a quit signal will generate a core dump.
*/
+#define DEBUG 0
#define IFS_BROKEN
#include "busybox.h"
-#ifdef DEBUG
+#if DEBUG
#define _GNU_SOURCE
#endif
#include <time.h>
#include <fnmatch.h>
-#include "pwd_.h"
-
#ifdef CONFIG_ASH_JOB_CONTROL
#define JOBS 1
#else
-#undef JOBS
+#define JOBS 0
#endif
#if JOBS || defined(CONFIG_ASH_READ_NCHARS)
#error "Do not even bother, ash will not run on uClinux"
#endif
-#ifdef DEBUG
+#if DEBUG
#define _DIAGASSERT(assert_expr) assert(assert_expr)
#else
#define _DIAGASSERT(assert_expr)
static const char illnum[] = "Illegal number: %s";
static const char homestr[] = "HOME";
-#ifdef DEBUG
+#if DEBUG
#define TRACE(param) trace param
#define TRACEV(param) tracev param
#else
{ BUILTIN_REGULAR "wait", waitcmd },
};
-#define NUMBUILTINS (sizeof (builtincmd) / sizeof (struct builtincmd) )
-
+#define NUMBUILTINS (sizeof(builtincmd) / sizeof(builtincmd[0]))
struct cmdentry {
#endif
#ifdef CONFIG_LOCALE_SUPPORT
-#include <locale.h>
static void change_lc_all(const char *value);
static void change_lc_ctype(const char *value);
#endif
static struct var **hashvar(const char *);
-static inline int varequal(const char *a, const char *b) {
+static int varequal(const char *a, const char *b) {
return !varcmp(a, b);
}
* This routine initializes the builtin variables.
*/
-static inline void
-initvar(void)
+static void initvar(void)
{
struct var *vp;
struct var *end;
} while (++vp < end);
}
-static inline void
-init(void)
+static void init(void)
{
/* from input.c: */
static char *stputs(const char *, char *);
-static inline char *_STPUTC(int c, char *p) {
+static char *_STPUTC(int c, char *p) {
if (p == sstrend)
p = growstackstr();
*p++ = c;
#define uflag optlist[12]
#define viflag optlist[13]
-#ifdef DEBUG
+#if DEBUG
#define nolog optlist[14]
#define debug optlist[15]
#endif
"b" "notify",
"u" "nounset",
"\0" "vi",
-#ifdef DEBUG
+#if DEBUG
"\0" "nolog",
"\0" "debug",
#endif
/* show.h */
-#ifdef DEBUG
+#if DEBUG
static void showtree(union node *);
static void trace(const char *, ...);
static void tracev(const char *, va_list);
static void setinteractive(int);
static void exitshell(void) ATTRIBUTE_NORETURN;
+
+static int is_safe_applet(char *name)
+{
+ /* It isn't a bug to have non-existent applet here... */
+ /* ...just a waste of space... */
+ static const char safe_applets[][8] = {
+ "["
+ USE_AWK (, "awk" )
+ USE_CAT (, "cat" )
+ USE_CHMOD (, "chmod" )
+ USE_CHOWN (, "chown" )
+ USE_CP (, "cp" )
+ USE_CUT (, "cut" )
+ USE_DD (, "dd" )
+ USE_ECHO (, "echo" )
+ USE_FIND (, "find" )
+ USE_HEXDUMP(, "hexdump")
+ USE_LN (, "ln" )
+ USE_LS (, "ls" )
+ USE_MKDIR (, "mkdir" )
+ USE_RM (, "rm" )
+ USE_SORT (, "sort" )
+ USE_TEST (, "test" )
+ USE_TOUCH (, "touch" )
+ USE_XARGS (, "xargs" )
+ };
+ int n = sizeof(safe_applets) / sizeof(safe_applets[0]);
+ int i;
+ for (i = 0; i < n; i++)
+ if (strcmp(safe_applets[i], name) == 0)
+ return 1;
+
+ return 0;
+}
+
+
/*
* This routine is called when an error or an interrupt occurs in an
* interactive shell and control is returned to the main command loop.
INTOFF;
*app = freealias(*app);
INTON;
- return (0);
+ return 0;
}
- return (1);
+ return 1;
}
static void
struct alias *ap = *__lookupalias(name);
if (check && ap && (ap->flag & ALIASINUSE))
- return (NULL);
- return (ap);
+ return NULL;
+ return ap;
}
/*
for (ap = atab[i]; ap; ap = ap->next) {
printalias(ap);
}
- return (0);
+ return 0;
}
while ((n = *++argv) != NULL) {
if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
}
}
- return (ret);
+ return ret;
}
static int
while ((i = nextopt("a")) != '\0') {
if (i == 'a') {
rmaliases();
- return (0);
+ return 0;
}
}
for (i = 0; *argptr; argptr++) {
}
}
- return (i);
+ return i;
}
static struct alias *
dest = *argptr;
if (!dest)
dest = bltinlookup(homestr);
- else if (dest[0] == '-' && dest[1] == '\0') {
+ else if (LONE_DASH(dest)) {
dest = bltinlookup("OLDPWD");
flags |= CD_PRINT;
}
* cd command.
*/
-static inline const char *
-updatepwd(const char *dir)
+static const char * updatepwd(const char *dir)
{
char *new;
char *p;
}
p = strtok(cdcomppath, "/");
while (p) {
- switch(*p) {
+ switch (*p) {
case '.':
if (p[1] == '.' && p[2] == '\0') {
while (new > lim) {
* Find out what the current directory is. If we already know the current
* directory, this routine returns immediately.
*/
-static inline char *
-getpwd(void)
+static char * getpwd(void)
{
char *dir = getcwd(0, 0);
return dir ? dir : nullstr;
static void
exraise(int e)
{
-#ifdef DEBUG
+#if DEBUG
if (handler == NULL)
abort();
#endif
static void
exverror(int cond, const char *msg, va_list ap)
{
-#ifdef DEBUG
+#if DEBUG
if (msg) {
TRACE(("exverror(%d, \"", cond));
TRACEV((msg, ap));
getpid(), n, n->type, flags));
switch (n->type) {
default:
-#ifdef DEBUG
+#if DEBUG
out1fmt("Node type = %d\n", n->type);
fflush(stdout);
break;
for (redir = n ; redir ; redir = redir->nfile.next) {
struct arglist fn;
+ memset(&fn, 0, sizeof(struct arglist));
fn.lastp = &fn.list;
switch (redir->type) {
case NFROMTO:
case NTOFD:
if (redir->ndup.vname) {
expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
- fixredir(redir, fn.list->text, 1);
+ if (fn.list != NULL)
+ fixredir(redir, fn.list->text, 1);
+ else
+ sh_error("redir error");
}
break;
}
}
#ifdef CONFIG_ASH_CMDCMD
-static inline char **
-parse_command_args(char **argv, const char **path)
+static char ** parse_command_args(char **argv, const char **path)
{
char *cp, c;
}
#endif
-static inline int
-isassignment(const char *p)
+static int isassignment(const char *p)
{
const char *q = endofname(p);
if (p == q)
}
-static inline int
-goodname(const char *p)
+static int goodname(const char *p)
{
return !*endofname(p);
}
clearredir(1);
envp = environment();
- if (strchr(argv[0], '/') != NULL
+ if (strchr(argv[0], '/')
#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
- || find_applet_by_name(argv[0])
+ || find_applet_by_name(argv[0])
#endif
- ) {
+ ) {
tryexec(argv[0], argv, envp);
e = errno;
} else {
tryexec(char *cmd, char **argv, char **envp)
{
int repeated = 0;
+ struct BB_applet *a;
+ int argc = 0;
+ char **c;
+
+ if (strchr(cmd, '/') == NULL
+ && (a = find_applet_by_name(cmd)) != NULL
+ && is_safe_applet(cmd)
+ ) {
+ c = argv;
+ while (*c != NULL) {
+ c++; argc++;
+ }
+ applet_name = cmd;
+ exit(a->main(argc, argv));
+ }
#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
- if(find_applet_by_name(cmd) != NULL) {
+ if (find_applet_by_name(cmd) != NULL) {
/* re-exec ourselves with the new arguments */
execve(CONFIG_BUSYBOX_EXEC_PATH,argv,envp);
/* If they called chroot or otherwise made the binary no longer
}
#endif
+ if (is_safe_applet(name)) {
+ entry->cmdtype = CMDNORMAL;
+ entry->u.index = -1;
+ return;
+ }
+
updatetbl = (path == pathval());
if (!updatetbl) {
act |= DO_ALTPATH;
* the same name - except special builtins.
*/
-static inline void
-addcmdentry(char *name, struct cmdentry *entry)
+static void addcmdentry(char *name, struct cmdentry *entry)
{
struct tblentry *cmdp;
* Make a copy of a parse tree.
*/
-static inline struct funcnode *
-copyfunc(union node *n)
+static struct funcnode * copyfunc(union node *n)
{
struct funcnode *f;
size_t blocksize;
verify |= VERIFY_VERBOSE;
else if (c == 'v')
verify |= VERIFY_BRIEF;
-#ifdef DEBUG
+#if DEBUG
else if (c != 'p')
abort();
#endif
* Returns an stalloced string.
*/
-static inline char *
-preglob(const char *pattern, int quoted, int flag) {
+static char * preglob(const char *pattern, int quoted, int flag) {
flag |= RMESCAPE_GLOB;
if (quoted) {
flag |= RMESCAPE_QUOTED;
* Expand shell variables and backquotes inside a here document.
*/
-static inline void
-expandhere(union node *arg, int fd)
+static void expandhere(union node *arg, int fd)
{
herefd = fd;
expandarg(arg, (struct arglist *)NULL, 0);
name = p + 1;
while ((c = *++p) != '\0') {
- switch(c) {
+ switch (c) {
case CTLESC:
- return (startp);
+ return startp;
case CTLQUOTEMARK:
- return (startp);
+ return startp;
case ':':
if (flag & EXP_VARTILDE)
goto done;
startloc = expdest - (char *)stackblock();
strtodest(home, SQSYNTAX, quotes);
recordregion(startloc, expdest - (char *)stackblock(), 0);
- return (p);
+ return p;
lose:
*p = c;
- return (startp);
+ return startp;
}
while (*p != CTLARI) {
p--;
-#ifdef DEBUG
+#if DEBUG
if (p < start) {
sh_error("missing CTLARI (shouldn't happen)");
}
}
subtype -= VSTRIMRIGHT;
-#ifdef DEBUG
+#if DEBUG
if (subtype < 0 || subtype > 3)
abort();
#endif
goto end;
}
-#ifdef DEBUG
+#if DEBUG
switch (subtype) {
case VSTRIMLEFT:
case VSTRIMLEFTMAX:
* Returns true if the pattern matches the string.
*/
-static inline int
-patmatch(char *pattern, const char *string)
+static int patmatch(char *pattern, const char *string)
{
return pmatch(preglob(pattern, 0, 0), string);
}
}
q = r;
if (len > 0) {
- q = mempcpy(q, str, len);
+ q = memcpy(q, str, len) + len;
}
}
inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
return c;
}
#else
-static inline int pgetc2(void)
+static int pgetc2(void)
{
return pgetc_macro();
}
* Read a line from the script.
*/
-static inline char *
-pfgets(char *line, int len)
+static char * pfgets(char *line, int len)
{
char *p = line;
int nleft = len;
#else
static const char *cmdedit_prompt;
#endif
-static inline void putprompt(const char *s)
+static void putprompt(const char *s)
{
#ifdef CONFIG_ASH_EXPAND_PRMT
free(cmdedit_prompt);
- cmdedit_prompt = bb_xstrdup(s);
+ cmdedit_prompt = xstrdup(s);
#else
cmdedit_prompt = s;
#endif
}
#else
-static inline void putprompt(const char *s)
+static void putprompt(const char *s)
{
out2str(s);
}
#endif
-static inline int
-preadfd(void)
+static int preadfd(void)
{
int nr;
char *buf = parsefile->buf;
jpp = curp;
switch (mode) {
default:
-#ifdef DEBUG
+#if DEBUG
abort();
#endif
case CUR_DELETE:
while ((c = nextopt("ls:")) != '\0')
switch (c) {
default:
-#ifdef DEBUG
+#if DEBUG
abort();
#endif
case 'l':
}
#endif /* JOBS */
-#if defined(JOBS) || defined(DEBUG)
+#if JOBS || DEBUG
static int
jobno(const struct job *jp)
{
* Called with interrupts off.
*/
-static inline void
-forkchild(struct job *jp, union node *n, int mode)
+static void forkchild(struct job *jp, union node *n, int mode)
{
int oldlvl;
jobless = 0;
}
-static inline void
-forkparent(struct job *jp, union node *n, int mode, pid_t pid)
+static void forkparent(struct job *jp, union node *n, int mode, pid_t pid)
{
TRACE(("In parent shell: child = %d\n", pid));
if (!jp) {
* and the jobs command may give out of date information.
*/
-static inline int
-waitproc(int block, int *status)
+static int waitproc(int block, int *status)
{
int flags = 0;
if (*p == '\0')
continue;
for (q = p ; *q ; q++);
-#ifdef DEBUG
+#if DEBUG
if (q[-1] != '/')
abort();
#endif
goto state4;
}
handler = &jmploc;
-#ifdef DEBUG
+#if DEBUG
opentrace();
trputs("Shell args: "); trargs(argv);
#endif
#if PROFILE
monitor(0);
#endif
-#if GPROF
+#ifdef GPROF
{
extern void _mcleanup(void);
_mcleanup();
* search for the file, which is necessary to find sub-commands.
*/
-static inline char *
-find_dot_file(char *name)
+static char * find_dot_file(char *name)
{
char *fullname;
const char *path = pathval();
int status = 0;
for (sp = cmdenviron; sp; sp = sp->next)
- setvareq(bb_xstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
+ setvareq(xstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
if (argc >= 2) { /* That's what SVR2 does */
char *fullname;
static int
echocmd(int argc, char **argv)
{
- return bb_echo(argc, argv);
+ return bb_echo(argv);
}
#endif
void
stunalloc(pointer p)
{
-#ifdef DEBUG
+#if DEBUG
if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
write(2, "stunalloc\n", 10);
abort();
}
}
-static inline void
-grabstackblock(size_t len)
+static void grabstackblock(size_t len)
{
len = SHELL_ALIGN(len);
stacknxt += len;
stnputs(const char *s, size_t n, char *p)
{
p = makestrspace(n, p);
- p = mempcpy(p, s, n);
+ p = memcpy(p, s, n) + n;
return p;
}
q = p = makestrspace(len + 3, p);
*q++ = '\'';
- q = mempcpy(q, s, len);
+ q = memcpy(q, s, len) + len;
*q++ = '\'';
s += len;
q = p = makestrspace(len + 3, p);
*q++ = '"';
- q = mempcpy(q, s, len);
+ q = memcpy(q, s, len) + len;
*q++ = '"';
s += len;
static char *
-nodesavestr(char *s)
+nodesavestr(char *s)
{
- char *rtn = funcstring;
+ char *rtn = funcstring;
- funcstring = stpcpy(funcstring, s) + 1;
+ strcpy(funcstring, s);
+ funcstring += strlen(s) + 1;
return rtn;
}
void
optschanged(void)
{
-#ifdef DEBUG
+#if DEBUG
opentrace();
#endif
setinteractive(iflag);
setvimode(viflag);
}
-static inline void
-minus_o(char *name, int val)
+static void minus_o(char *name, int val)
{
int i;
argptr++;
if ((c = *p++) == '-') {
val = 1;
- if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
+ if (p[0] == '\0' || LONE_DASH(p)) {
if (!cmdline) {
/* "-" means turn off -x and -v */
if (p[0] == '\0')
goto out;
}
optnext++;
- if (p[0] == '-' && p[1] == '\0') /* check for "--" */
+ if (LONE_DASH(p)) /* check for "--" */
goto atend;
}
if (p == NULL || *p != '-' || *++p == '\0')
return '\0';
argptr++;
- if (p[0] == '-' && p[1] == '\0') /* check for "--" */
+ if (LONE_DASH(p)) /* check for "--" */
return '\0';
}
c = *p++;
if (is_digit(text[0]) && text[1] == '\0')
n->ndup.dupfd = digit_val(text[0]);
- else if (text[0] == '-' && text[1] == '\0')
+ else if (LONE_DASH(text))
n->ndup.dupfd = -1;
else {
readtoken(void)
{
int t;
-#ifdef DEBUG
+#if DEBUG
int alreadyseen = tokpushback;
#endif
}
out:
checkkwd = 0;
-#ifdef DEBUG
+#if DEBUG
if (!alreadyseen)
TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
else
TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
#endif
- return (t);
+ return t;
}
CHECKEND(); /* set c to PEOF if at end of here document */
for (;;) { /* until end of line or end of word */
CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
- switch(SIT(c, syntax)) {
+ switch (SIT(c, syntax)) {
case CNL: /* '\n' */
if (syntax == BASESYNTAX)
goto endword; /* exit outer loop */
* Open a file in noclobber mode.
* The code was copied from bash.
*/
-static inline int
-noclobberopen(const char *fname)
+static int noclobberopen(const char *fname)
{
int r, fd;
struct stat finfo, finfo2;
* the pipe without forking.
*/
-static inline int
-openhere(union node *redir)
+static int openhere(union node *redir)
{
int pip[2];
size_t len = 0;
goto ecreate;
break;
default:
-#ifdef DEBUG
+#if DEBUG
abort();
#endif
/* Fall through to eliminate warning. */
sh_error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
}
-static inline void
-dupredirect(union node *redir, int f)
+static void dupredirect(union node *redir, int f)
{
int fd = redir->nfile.fd;
/* show.c */
-#ifdef DEBUG
+#if DEBUG
static void shtree(union node *, int, char *, FILE*);
static void shcmd(union node *, FILE *);
static void sharg(union node *, FILE *);
return;
indent(ind, pfx, fp);
- switch(n->type) {
+ switch (n->type) {
case NSEMI:
s = "; ";
goto binop;
sh_error("%s: bad trap", *ap);
INTOFF;
if (action) {
- if (action[0] == '-' && action[1] == '\0')
+ if (LONE_DASH(action))
action = NULL;
else
action = savestr(action);
action = S_CATCH;
break;
case SIGQUIT:
-#ifdef DEBUG
+#if DEBUG
if (debug)
break;
#endif
}
}
#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
- {
- extern const struct BB_applet applets[];
- extern const size_t NUM_APPLETS;
-
- for (i = 0; i < NUM_APPLETS; i++) {
-
- col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
- if (col > 60) {
- out1fmt("\n");
- col = 0;
- }
+ for (i = 0; i < NUM_APPLETS; i++) {
+ col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
+ if (col > 60) {
+ out1fmt("\n");
+ col = 0;
}
}
#endif
vallen = strlen(val);
}
INTOFF;
- p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
+ nameeq = ckmalloc(namelen + vallen + 2);
+ p = memcpy(nameeq, name, namelen) + namelen;
if (val) {
*p++ = '=';
- p = mempcpy(p, val, vallen);
+ p = memcpy(p, val, vallen) + vallen;
}
*p = '\0';
setvareq(nameeq, flags | VNOSAVE);
* "-" as a special case.
*/
-static inline void
-mklocal(char *name)
+static void mklocal(char *name)
{
struct localvar *lvp;
struct var **vpp;
INTOFF;
lvp = ckmalloc(sizeof (struct localvar));
- if (name[0] == '-' && name[1] == '\0') {
+ if (LONE_DASH(name)) {
char *p;
p = ckmalloc(sizeof(optlist));
lvp->text = memcpy(p, optlist, sizeof(optlist));
}
INTON;
- return (result);
+ return result;
}
letcmd(int argc, char **argv)
{
char **ap;
- arith_t i;
+ arith_t i = 0;
ap = argv + 1;
if(!*ap)
i = dash_arith(*ap);
}
- return (!i);
+ return !i;
}
#endif /* CONFIG_ASH_MATH_SUPPORT */
#undef rflag
-#ifdef __GLIBC__
-#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
+#if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
typedef enum __rlimit_resource rlim_t;
#endif
-#endif
/*
while ((i = nextopt("p:r")) != '\0')
#endif
{
- switch(i) {
+ switch (i) {
case 'p':
prompt = optionarg;
break;
FD_ZERO (&set);
FD_SET (0, &set);
- i = select (FD_SETSIZE, &set, NULL, NULL, &ts);
+ i = select(FD_SETSIZE, &set, NULL, NULL, &ts);
if (!i) {
#if defined(CONFIG_ASH_READ_NCHARS)
if (nch_flag)
#define NUMPTR (*numstackptr)
-static inline int tok_have_assign(operator op)
+static int tok_have_assign(operator op)
{
operator prec = PREC(op);
prec == PREC_PRE || prec == PREC_POST);
}
-static inline int is_right_associativity(operator prec)
+static int is_right_associativity(operator prec)
{
return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) ||
prec == PREC(TOK_CONDITIONAL));
/* "applying" a token means performing it on the top elements on the integer
* stack. For a unary operator it will only change the top element, but a
* binary operator will pop two arguments and push a result */
-static inline int
-arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
+static int arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
{
v_n_t *numptr_m1;
arith_t numptr_val, rez;
/* protect geting var value, is number now */
numptr_m1->var = NULL;
return 0;
-err: return(-1);
+ err:
+ return -1;
}
/* longest must first */
* a number, since it evaluates to one). Think about it.
* It makes sense. */
if (lasttok != TOK_NUM) {
- switch(op) {
+ switch (op) {
case TOK_ADD:
op = TOK_UPLUS;
break;
#endif /* CONFIG_ASH_MATH_SUPPORT */
-#ifdef DEBUG
-const char *bb_applet_name = "debug stuff usage";
+#if DEBUG
+const char *applet_name = "debug stuff usage";
int main(int argc, char **argv)
{
return ash_main(argc, argv);