/* 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;
}
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);
}
/*
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) {
if (i == EXINT)
j = SIGINT;
if (i == EXSIG)
- j = pendingsigs;
+ j = pendingsig;
if (j)
exit_status = j + 128;
exitstatus = exit_status;
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 */
}
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) {
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 */
if (cmdp && cmdp->rehash) { /* doing a rehash */
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);
}