#if JOBS || ENABLE_ASH_READ_NCHARS
#include <termios.h>
#endif
+extern char **environ;
#if defined(__uClinux__)
#error "Do not even bother, ash will not run on uClinux"
static char *arg0; /* value of $0 */
-/* ============ Interrupts / exceptions
- *
+/* ============ Interrupts / exceptions */
+
+/*
* 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
/* do we generate EXSIG events */
static int exsig;
/* last pending signal */
-static volatile sig_atomic_t pendingsigs;
+static volatile sig_atomic_t pendingsig;
/*
* Sigmode records the current value of the signal handlers for the various
raise_interrupt(void)
{
int i;
+ sigset_t mask;
intpending = 0;
+ /* Signal is not automatically re-enabled after it is raised,
+ * do it ourself */
+ sigemptyset(&mask);
+ sigprocmask(SIG_SETMASK, &mask, 0);
+ /* pendingsig = 0; - now done in onsig() */
+
i = EXSIG;
if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
if (!(rootshell && iflag)) {
do { \
exsig++; \
xbarrier(); \
- if (pendingsigs) \
+ if (pendingsig) \
raise_exception(EXSIG); \
} while (0)
/* EXSIG is turned off by evalbltin(). */
onsig(int signo)
{
gotsig[signo - 1] = 1;
- pendingsigs = signo;
+ pendingsig = signo;
if (exsig || (signo == SIGINT && !trap[SIGINT])) {
- if (!suppressint)
+ if (!suppressint) {
+ pendingsig = 0;
raise_interrupt();
+ }
intpending = 1;
}
}
{
fprintf(stderr, "%s: ", arg0);
if (commandname) {
- const char *fmt = (!iflag || parsefile->fd) ?
- "%s: %d: " : "%s: ";
- fprintf(stderr, fmt, commandname, startlinno);
+ if (strcmp(arg0, commandname))
+ fprintf(stderr, "%s: ", commandname);
+ if (!iflag || parsefile->fd)
+ fprintf(stderr, "line %d: ", startlinno);
}
vfprintf(stderr, msg, ap);
outcslow('\n', stderr);
{
struct stack_block *sp;
+ if (!mark->stackp)
+ return;
+
INT_OFF;
markp = mark->marknext;
while (stackp != mark->stackp) {
c = *p++;
for (q = optstring; *q != c; ) {
if (*q == '\0')
- ash_msg_and_raise_error("Illegal option -%c", c);
+ ash_msg_and_raise_error("illegal option -%c", c);
if (*++q == ':')
q++;
}
if (*++q == ':') {
if (*p == '\0' && (p = *argptr++) == NULL)
- ash_msg_and_raise_error("No arg for -%c option", c);
+ ash_msg_and_raise_error("no arg for -%c option", c);
optionarg = p;
p = NULL;
}
static struct redirtab *redirlist;
static int nullredirs;
-extern char **environ;
static int preverrout_fd; /* save fd2 before print debug if xflag is set. */
#define VTABSIZE 39
{
if (ENABLE_ASH_EXPAND_PRMT) {
free((char*)cmdedit_prompt);
- cmdedit_prompt = xstrdup(s);
+ cmdedit_prompt = ckstrdup(s);
return;
}
cmdedit_prompt = s;
break;
}
break;
- } else if (p[1] == '\0')
+ }
+ if (p[1] == '\0')
break;
/* fall through */
default:
xtcsetpgrp(int fd, pid_t pgrp)
{
if (tcsetpgrp(fd, pgrp))
- ash_msg_and_raise_error("Cannot set tty process group (%m)");
+ ash_msg_and_raise_error("cannot set tty process group (%m)");
}
/*
/* turning job control off */
fd = ttyfd;
pgrp = initialpgrp;
- xtcsetpgrp(fd, pgrp);
+ /* was xtcsetpgrp, but this can make exiting ash
+ * with pty already deleted loop forever */
+ tcsetpgrp(fd, pgrp);
setpgid(0, pgrp);
setsignal(SIGTSTP);
setsignal(SIGTTOU);
static int
killcmd(int argc, char **argv)
{
- int signo = -1;
- int list = 0;
- int i;
- pid_t pid;
- struct job *jp;
-
- if (argc <= 1) {
- usage:
- ash_msg_and_raise_error(
-"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
-"kill -l [exitstatus]"
- );
- }
-
- if (**++argv == '-') {
- signo = get_signum(*argv + 1);
- if (signo < 0) {
- int c;
-
- while ((c = nextopt("ls:")) != '\0') {
- switch (c) {
- default:
-#if DEBUG
- abort();
-#endif
- case 'l':
- list = 1;
- break;
- case 's':
- signo = get_signum(optionarg);
- if (signo < 0) {
- ash_msg_and_raise_error(
- "invalid signal number or name: %s",
- optionarg
- );
- }
- break;
- }
- }
- argv = argptr;
- } else
- argv++;
- }
-
- if (!list && signo < 0)
- signo = SIGTERM;
-
- if ((signo < 0 || !*argv) ^ list) {
- goto usage;
- }
-
- if (list) {
- const char *name;
-
- if (!*argv) {
- for (i = 1; i < NSIG; i++) {
- name = get_signame(i);
- if (isdigit(*name))
- out1fmt(snlfmt, name);
+ if (argv[1] && strcmp(argv[1], "-l") != 0) {
+ int i = 1;
+ do {
+ if (argv[i][0] == '%') {
+ struct job *jp = getjob(argv[i], 0);
+ unsigned pid = jp->ps[0].pid;
+ /* Enough space for ' -NNN<nul>' */
+ argv[i] = alloca(sizeof(int)*3 + 3);
+ /* kill_main has matching code to expect
+ * leading space. Needed to not confuse
+ * negative pids with "kill -SIGNAL_NO" syntax */
+ sprintf(argv[i], " -%u", pid);
}
- return 0;
- }
- name = get_signame(signo);
- if (!isdigit(*name))
- ash_msg_and_raise_error("invalid signal number or exit status: %s", *argptr);
- out1fmt(snlfmt, name);
- return 0;
+ } while (argv[++i]);
}
-
- i = 0;
- do {
- if (**argv == '%') {
- jp = getjob(*argv, 0);
- pid = -jp->ps[0].pid;
- } else {
- pid = **argv == '-' ?
- -number(*argv + 1) : number(*argv);
- }
- if (kill(pid, signo) != 0) {
- ash_msg("(%d) - %m", pid);
- i = 1;
- }
- } while (*++argv);
-
- return i;
+ return kill_main(argc, argv);
}
static void
if (WIFSTOPPED(ps->status)) {
ps->status = -1;
}
- } while (ps++, --i);
+ ps++;
+ } while (--i);
out:
status = (mode == FORK_FG) ? waitforjob(jp) : 0;
INT_ON;
if (jp->nprocs == 0) {
close(0);
if (open(bb_dev_null, O_RDONLY) != 0)
- ash_msg_and_raise_error("Can't open %s", bb_dev_null);
+ ash_msg_and_raise_error("can't open %s", bb_dev_null);
}
}
if (!oldlvl && iflag) {
TRACE(("Fork failed, errno=%d", errno));
if (jp)
freejob(jp);
- ash_msg_and_raise_error("Cannot fork");
+ ash_msg_and_raise_error("cannot fork");
}
if (pid == 0)
forkchild(jp, n, mode);
size_t len = 0;
if (pipe(pip) < 0)
- ash_msg_and_raise_error("Pipe call failed");
+ ash_msg_and_raise_error("pipe call failed");
if (redir->type == NHERE) {
len = strlen(redir->nhere.doc->narg.text);
if (len <= PIPESIZE) {
return f;
ecreate:
- ash_msg_and_raise_error("cannot create %s: %s", fname, errmsg(errno, "Directory nonexistent"));
+ ash_msg_and_raise_error("cannot create %s: %s", fname, errmsg(errno, "nonexistent directory"));
eopen:
- ash_msg_and_raise_error("cannot open %s: %s", fname, errmsg(errno, "No such file"));
+ ash_msg_and_raise_error("cannot open %s: %s", fname, errmsg(errno, "no such file"));
}
/*
static char *
_rmescapes(char *str, int flag)
{
+ static const char qchars[] = { CTLESC, CTLQUOTEMARK, '\0' };
+
char *p, *q, *r;
- static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
unsigned inquotes;
int notescaped;
int globbing;
struct job *jp;
if (pipe(pip) < 0)
- ash_msg_and_raise_error("Pipe call failed");
+ ash_msg_and_raise_error("pipe call failed");
jp = makejob(n, 1);
if (forkshell(jp, n, FORK_NOJOB) == 0) {
FORCE_INT_ON;
/* ============ find_command */
-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;
-}
-
struct builtincmd {
const char *name;
int (*builtin)(int, char **);
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++;
+#if ENABLE_FEATURE_SH_STANDALONE
+ if (strchr(cmd, '/') == NULL) {
+ const struct bb_applet *a;
+
+ a = find_applet_by_name(cmd);
+ if (a) {
+ if (a->noexec) {
+ current_applet = a;
+ run_current_applet_and_exit(argv);
+ }
+ /* 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
+ * executable, fall through */
}
- applet_name = cmd;
- exit(a->main(argc, argv));
- }
-#if ENABLE_FEATURE_SH_STANDALONE_SHELL
- 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
- * executable, fall through */
}
#endif
;
ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
ap[1] = cmd;
- *ap = cmd = (char *)DEFAULT_SHELL;
+ ap[0] = cmd = (char *)DEFAULT_SHELL;
ap += 2;
argv++;
while ((*ap++ = *argv++))
clearredir(1);
envp = environment();
- if (strchr(argv[0], '/') || is_safe_applet(argv[0])
-#if ENABLE_FEATURE_SH_STANDALONE_SHELL
+ if (strchr(argv[0], '/')
+#if ENABLE_FEATURE_SH_STANDALONE
|| find_applet_by_name(argv[0])
#endif
) {
{
static char buf[16];
+//try this:
+//if (tok < TSEMI) return tokname_array[tok] + 1;
+//sprintf(buf, "\"%s\"", tokname_array[tok] + 1);
+//return buf;
+
if (tok >= TSEMI)
buf[0] = '"';
sprintf(buf + (tok >= TSEMI), "%s%c",
static int
pstrcmp(const void *a, const void *b)
{
- return strcmp((const char *) a, (*(const char *const *) b) + 1);
+ return strcmp((char*) a, (*(char**) b) + 1);
}
static const char *const *
findkwd(const char *s)
{
return bsearch(s, tokname_array + KWDOFFSET,
- (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
- sizeof(const char *), pstrcmp);
+ (sizeof(tokname_array) / sizeof(char *)) - KWDOFFSET,
+ sizeof(char *), pstrcmp);
}
/*
* Locate and print what a word is...
*/
-#if ENABLE_ASH_CMDCMD
static int
describe_command(char *command, int describe_command_verbose)
-#else
-#define describe_command_verbose 1
-static int
-describe_command(char *command)
-#endif
{
struct cmdentry entry;
struct tblentry *cmdp;
/* Then look at the aliases */
ap = lookupalias(command, 0);
if (ap != NULL) {
- if (describe_command_verbose) {
- out1fmt(" is an alias for %s", ap->val);
- } else {
+ if (!describe_command_verbose) {
out1str("alias ");
printalias(ap);
return 0;
}
+ out1fmt(" is an alias for %s", ap->val);
goto out;
}
#endif
static int
typecmd(int argc, char **argv)
{
- int i;
+ int i = 1;
int err = 0;
+ int verbose = 1;
- for (i = 1; i < argc; i++) {
-#if ENABLE_ASH_CMDCMD
- err |= describe_command(argv[i], 1);
-#else
- err |= describe_command(argv[i]);
-#endif
+ /* type -p ... ? (we don't bother checking for 'p') */
+ if (argv[1][0] == '-') {
+ i++;
+ verbose = 0;
+ }
+ while (i < argc) {
+ err |= describe_command(argv[i++], verbose);
}
return err;
}
int skip = 0;
savestatus = exitstatus;
- pendingsigs = 0;
+ pendingsig = 0;
xbarrier();
for (i = 0, q = gotsig; i < NSIG - 1; i++, q++) {
out:
if ((checkexit & exitstatus))
evalskip |= SKIPEVAL;
- else if (pendingsigs && dotrap())
+ else if (pendingsig && dotrap())
goto exexit;
if (flags & EV_EXIT) {
if (lp->next) {
if (pipe(pip) < 0) {
close(prevfd);
- ash_msg_and_raise_error("Pipe call failed");
+ ash_msg_and_raise_error("pipe call failed");
}
}
if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
return 0;
}
+static int
+falsecmd(int argc, char **argv)
+{
+ return 1;
+}
+
+static int
+truecmd(int argc, char **argv)
+{
+ return 0;
+}
+
+static int
+execcmd(int argc, char **argv)
+{
+ if (argc > 1) {
+ iflag = 0; /* exit on error */
+ mflag = 0;
+ optschanged();
+ shellexec(argv + 1, pathval(), 0);
+ }
+ return 0;
+}
+
+/*
+ * The return command.
+ */
+static int
+returncmd(int argc, char **argv)
+{
+ /*
+ * If called outside a function, do what ksh does;
+ * skip the rest of the file.
+ */
+ evalskip = funcnest ? SKIPFUNC : SKIPFILE;
+ return argv[1] ? number(argv[1]) : exitstatus;
+}
+
/* Forward declarations for builtintab[] */
-#if JOBS
-static int fg_bgcmd(int, char **);
-#endif
static int breakcmd(int, char **);
-#if ENABLE_ASH_CMDCMD
-static int commandcmd(int, char **);
-#endif
static int dotcmd(int, char **);
static int evalcmd(int, char **);
#if ENABLE_ASH_BUILTIN_ECHO
#if ENABLE_ASH_BUILTIN_TEST
static int testcmd(int, char **);
#endif
-static int execcmd(int, char **);
static int exitcmd(int, char **);
static int exportcmd(int, char **);
-static int falsecmd(int, char **);
#if ENABLE_ASH_GETOPTS
static int getoptscmd(int, char **);
#endif
-static int hashcmd(int, char **);
#if !ENABLE_FEATURE_SH_EXTRA_QUIET
static int helpcmd(int argc, char **argv);
#endif
-#if JOBS
-static int jobscmd(int, char **);
-#endif
#if ENABLE_ASH_MATH_SUPPORT
static int letcmd(int, char **);
#endif
-static int pwdcmd(int, char **);
static int readcmd(int, char **);
-static int returncmd(int, char **);
static int setcmd(int, char **);
static int shiftcmd(int, char **);
static int timescmd(int, char **);
static int trapcmd(int, char **);
-static int truecmd(int, char **);
-static int typecmd(int, char **);
static int umaskcmd(int, char **);
static int unsetcmd(int, char **);
-static int waitcmd(int, char **);
static int ulimitcmd(int, char **);
-#if JOBS
-static int killcmd(int, char **);
-#endif
#define BUILTIN_NOSPEC "0"
#define BUILTIN_SPECIAL "1"
if (i == EXINT)
j = SIGINT;
if (i == EXSIG)
- j = pendingsigs;
+ j = pendingsig;
if (j)
exit_status = j + 128;
exitstatus = exit_status;
}
-/*
- * Builtin commands. Builtin commands whose functions are closely
- * tied to evaluation are implemented here.
+/* ============ Builtin commands
+ *
+ * Builtin commands whose functions are closely tied to evaluation
+ * are implemented here.
*/
/*
* be an error to break out of more loops than exist, but it isn't
* in the standard shell so we don't make it one here.
*/
-
static int
breakcmd(int argc, char **argv)
{
if (n > loopnest)
n = loopnest;
if (n > 0) {
- evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
+ evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
skipcount = n;
}
return 0;
}
-/*
- * The return command.
- */
-static int
-returncmd(int argc, char **argv)
-{
- /*
- * If called outside a function, do what ksh does;
- * skip the rest of the file.
- */
- evalskip = funcnest ? SKIPFUNC : SKIPFILE;
- return argv[1] ? number(argv[1]) : exitstatus;
-}
-
-static int
-falsecmd(int argc, char **argv)
-{
- return 1;
-}
-
-static int
-truecmd(int argc, char **argv)
-{
- return 0;
-}
-
-static int
-execcmd(int argc, char **argv)
-{
- if (argc > 1) {
- iflag = 0; /* exit on error */
- mflag = 0;
- optschanged();
- shellexec(argv + 1, pathval(), 0);
- }
- return 0;
-}
-
/* ============ input.c
*
if (fd < 0) {
if (flags & INPUT_NOFILE_OK)
goto out;
- ash_msg_and_raise_error("Can't open %s", fname);
+ ash_msg_and_raise_error("can't open %s", fname);
}
if (fd < 10) {
fd2 = copyfd(fd, 10);
close(fd);
if (fd2 < 0)
- ash_msg_and_raise_error("Out of file descriptors");
+ ash_msg_and_raise_error("out of file descriptors");
fd = fd2;
}
setinputfd(fd, flags & INPUT_PUSH_FILE);
return;
}
}
- ash_msg_and_raise_error("Illegal option -o %s", name);
+ ash_msg_and_raise_error("illegal option -o %s", name);
}
out1str("Current option settings\n");
for (i = 0; i < NOPTS; i++)
return;
}
}
- ash_msg_and_raise_error("Illegal option -%c", flag);
+ ash_msg_and_raise_error("illegal option -%c", flag);
/* NOTREACHED */
}
static void
char **optbase;
if (argc < 3)
- ash_msg_and_raise_error("Usage: getopts optstring var [arg]");
+ ash_msg_and_raise_error("usage: getopts optstring var [arg]");
if (argc == 3) {
optbase = shellparam.p;
if (shellparam.optind > shellparam.nparam + 1) {
static void
raise_error_syntax(const char *msg)
{
- ash_msg_and_raise_error("Syntax error: %s", msg);
+ ash_msg_and_raise_error("syntax error: %s", msg);
/* NOTREACHED */
}
/*
- * called by editline -- any expansions to the prompt
- * should be added here.
+ * called by editline -- any expansions to the prompt should be added here.
*/
#if ENABLE_ASH_EXPAND_PRMT
static const char *
}
#endif
-
/*
* Execute a command or commands contained in a string.
*/
int status = 0;
for (sp = cmdenviron; sp; sp = sp->next)
- setvareq(xstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
+ setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
if (argc >= 2) { /* That's what SVR2 does */
char *fullname;
return;
}
-#if ENABLE_FEATURE_SH_STANDALONE_SHELL
- if (find_applet_by_name(name)) {
- entry->cmdtype = CMDNORMAL;
- entry->u.index = -1;
- return;
- }
-#endif
-
- if (is_safe_applet(name)) {
- entry->cmdtype = CMDNORMAL;
- entry->u.index = -1;
- return;
- }
+/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
updatetbl = (path == pathval());
if (!updatetbl) {
/* If %builtin not in path, check for builtin next */
bcmd = find_builtin(name);
- if (bcmd && (IS_BUILTIN_REGULAR(bcmd) || (
- act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc <= 0
- )))
- goto builtin_success;
+ if (bcmd) {
+ if (IS_BUILTIN_REGULAR(bcmd))
+ goto builtin_success;
+ if (act & DO_ALTPATH) {
+ if (!(act & DO_ALTBLTIN))
+ goto builtin_success;
+ } else if (builtinloc <= 0) {
+ goto builtin_success;
+ }
+ }
+
+#if ENABLE_FEATURE_SH_STANDALONE
+ if (find_applet_by_name(name)) {
+ entry->cmdtype = CMDNORMAL;
+ entry->u.index = -1;
+ return;
+ }
+#endif
/* We have to search path. */
prev = -1; /* where to start */
out1fmt("\nBuilt-in commands:\n-------------------\n");
for (col = 0, i = 0; i < NUMBUILTINS; i++) {
col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
- builtincmd[i].name + 1);
+ builtintab[i].name + 1);
if (col > 60) {
out1fmt("\n");
col = 0;
}
}
-#if ENABLE_FEATURE_SH_STANDALONE_SHELL
+#if ENABLE_FEATURE_SH_STANDALONE
for (i = 0; i < NUM_APPLETS; i++) {
col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
if (col > 60) {
} else {
mask = ~mask & 0777;
if (!bb_parse_mode(ap, &mask)) {
- ash_msg_and_raise_error("Illegal mode: %s", ap);
+ ash_msg_and_raise_error("illegal mode: %s", ap);
}
umask(~mask & 0777);
}