#if DEBUG
#define _GNU_SOURCE
#endif
-#include "busybox.h"
+#include "busybox.h" /* for struct bb_applet */
#include <paths.h>
#include <setjmp.h>
#include <fnmatch.h>
#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"
"a" "allexport",
"b" "notify",
"u" "nounset",
- "\0" "vi",
+ "\0" "vi"
#if DEBUG
- "\0" "nolog",
- "\0" "debug",
+ ,"\0" "nolog"
+ ,"\0" "debug"
#endif
};
#define optletters(n) optletters_optnames[(n)][0]
#define optnames(n) (&optletters_optnames[(n)][1])
-#define NOPTS (sizeof(optletters_optnames)/sizeof(optletters_optnames[0]))
+enum { NOPTS = ARRAY_SIZE(optletters_optnames) };
-static char optlist[NOPTS];
+static char optlist[NOPTS] ALIGN1;
#define eflag optlist[0]
#define fflag optlist[1]
/* ============ Misc data */
-#ifdef __GLIBC__
-/* glibc sucks */
-static int *dash_errno;
-#undef errno
-#define errno (*dash_errno)
-#endif
-
-static char nullstr[1]; /* zero length string */
-static const char homestr[] = "HOME";
-static const char snlfmt[] = "%s\n";
-static const char illnum[] = "Illegal number: %s";
+static char nullstr[1] ALIGN1; /* zero length string */
+static const char homestr[] ALIGN1 = "HOME";
+static const char snlfmt[] ALIGN1 = "%s\n";
+static const char illnum[] ALIGN1 = "Illegal number: %s";
-static char *minusc; /* argument to -c option */
+static char *minusc; /* argument to -c option */
-static int isloginsh;
/* pid of main shell */
static int rootpid;
/* shell level: 0 for the main shell, 1 for its children, and so on */
#define rootshell (!shlvl)
/* trap handler commands */
static char *trap[NSIG];
+static smallint isloginsh;
/* current value of signal */
static char sigmode[NSIG - 1];
/* indicates specified signal received */
#define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
#define VSLENGTH 0xa /* ${#var} */
-static const char dolatstr[] = { CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' };
+static const char dolatstr[] ALIGN1 = {
+ CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'
+};
#define NCMD 0
#define NPIPE 1
}
}
#ifdef O_APPEND
- flags = fcntl(fileno(tracefile), F_GETFL, 0);
+ flags = fcntl(fileno(tracefile), F_GETFL);
if (flags >= 0)
fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
#endif
first = 1;
for (np = cmd->ncmd.args; np; np = np->narg.next) {
- if (! first)
- putchar(' ');
+ if (!first)
+ putc(' ', fp);
sharg(np, fp);
first = 0;
}
for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
- if (! first)
- putchar(' ');
+ if (!first)
+ putc(' ', fp);
+ dftfd = 0;
switch (np->nfile.type) {
- case NTO: s = ">"; dftfd = 1; break;
- case NCLOBBER: s = ">|"; dftfd = 1; break;
- case NAPPEND: s = ">>"; dftfd = 1; break;
- case NTOFD: s = ">&"; dftfd = 1; break;
- case NFROM: s = "<"; dftfd = 0; break;
- case NFROMFD: s = "<&"; dftfd = 0; break;
- case NFROMTO: s = "<>"; dftfd = 0; break;
- default: s = "*error*"; dftfd = 0; break;
+ case NTO: s = ">>"+1; dftfd = 1; break;
+ case NCLOBBER: s = ">|"; dftfd = 1; break;
+ case NAPPEND: s = ">>"; dftfd = 1; break;
+ case NTOFD: s = ">&"; dftfd = 1; break;
+ case NFROM: s = "<"; break;
+ case NFROMFD: s = "<&"; break;
+ case NFROMTO: s = "<>"; break;
+ default: s = "*error*"; break;
}
if (np->nfile.fd != dftfd)
fprintf(fp, "%d", np->nfile.fd);
# define VDYNAMIC 0
#endif
-static const char defpathvar[] = "PATH=/usr/local/bin:/usr/bin:/sbin:/bin";
#ifdef IFS_BROKEN
-static const char defifsvar[] = "IFS= \t\n";
+static const char defifsvar[] ALIGN1 = "IFS= \t\n";
#define defifs (defifsvar + 4)
#else
-static const char defifs[] = " \t\n";
+static const char defifs[] ALIGN1 = " \t\n";
#endif
struct shparam {
{ NULL, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0", changemail },
{ NULL, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail },
#endif
- { NULL, VSTRFIXED|VTEXTFIXED, defpathvar, changepath },
+ { NULL, VSTRFIXED|VTEXTFIXED, bb_PATH_root_path, changepath },
{ NULL, VSTRFIXED|VTEXTFIXED, "PS1=$ ", NULL },
{ NULL, VSTRFIXED|VTEXTFIXED, "PS2=> ", NULL },
{ NULL, VSTRFIXED|VTEXTFIXED, "PS4=+ ", NULL },
#else
#define vrandom (&vps4)[1]
#endif
-#define defpath (defpathvar + 5)
/*
* The following macros access the values of the above variables.
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
vps1.text = "PS1=# ";
#endif
vp = varinit;
- end = vp + sizeof(varinit) / sizeof(varinit[0]);
+ end = vp + ARRAY_SIZE(varinit);
do {
vpp = hashvar(vp->text);
vp->next = *vpp;
/* ============ Prompt */
-static int doprompt; /* if set, prompt the user */
-static int needprompt; /* true if interactive and at start of line */
+static smallint doprompt; /* if set, prompt the user */
+static smallint needprompt; /* true if interactive and at start of line */
#if ENABLE_FEATURE_EDITING
static line_input_t *line_input_state;
/* ============ ... */
-#define IBUFSIZ (BUFSIZ + 1)
+#define IBUFSIZ COMMON_BUFSIZE
#define basebuf bb_common_bufsiz1 /* buffer for top level input file */
/* Syntax classes */
#define DQSYNTAX 1 /* in double quotes */
#define SQSYNTAX 2 /* in single quotes */
#define ARISYNTAX 3 /* in arithmetic */
+#define PSSYNTAX 4 /* prompt */
#if ENABLE_ASH_OPTIMIZE_FOR_SIZE
#define USE_SIT_FUNCTION
static int
SIT(int c, int syntax)
{
- static const char spec_symbls[] = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
+ static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
#if ENABLE_ASH_ALIAS
- static const char syntax_index_table[] = {
+ static const char syntax_index_table[] ALIGN1 = {
1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
11, 3 /* "}~" */
};
#else
- static const char syntax_index_table[] = {
+ static const char syntax_index_table[] ALIGN1 = {
0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */
2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
};
static pid_t backgndpid; /* pid of last background process */
-static int job_warning; /* user was warned about stopped jobs */
-#if JOBS
-static int jobctl; /* true if doing job control */
-#endif
+static smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */
static struct job *makejob(union node *, int);
static int forkshell(struct job *, union node *, int);
static int waitforjob(struct job *);
-#if ! JOBS
-#define setjobctl(on) /* do nothing */
+#if !JOBS
+enum { jobctl = 0 };
+#define setjobctl(on) do {} while (0)
#else
+static smallint jobctl; /* true if doing job control */
static void setjobctl(int);
-static void showjobs(FILE *, int);
#endif
/*
close(ofd);
if (fd < 0)
goto out;
- fcntl(fd, F_SETFD, FD_CLOEXEC);
+ close_on_exec_on(fd);
do { /* while we are in the background */
pgrp = tcgetpgrp(fd);
if (pgrp < 0) {
/* 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;
struct procstat *ps;
struct procstat *psend;
int col;
- int indent;
+ int indent_col;
char s[80];
ps = jp->ps;
}
col = fmtstr(s, 16, "[%d] ", jobno(jp));
- indent = col;
+ indent_col = col;
if (jp == curjob)
s[col - 2] = '+';
do {
/* for each process */
- col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;
+ col = fmtstr(s, 48, " |\n%*c%d ", indent_col, ' ', ps->pid) - 3;
start:
fprintf(out, "%s%*c%s",
s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
}
}
+/*
+ * Print a list of jobs. If "change" is nonzero, only print jobs whose
+ * statuses have changed since the last call to showjobs.
+ */
+static void
+showjobs(FILE *out, int mode)
+{
+ struct job *jp;
+
+ TRACE(("showjobs(%x) called\n", mode));
+
+ /* If not even one one job changed, there is nothing to do */
+ while (dowait(DOWAIT_NORMAL, NULL) > 0)
+ continue;
+
+ for (jp = curjob; jp; jp = jp->prev_job) {
+ if (!(mode & SHOW_CHANGED) || jp->changed) {
+ showjob(out, jp, mode);
+ }
+ }
+}
+
static int
jobscmd(int argc, char **argv)
{
int mode, m;
- FILE *out;
mode = 0;
while ((m = nextopt("lp"))) {
mode = SHOW_PGID;
}
- out = stdout;
argv = argptr;
if (*argv) {
do
- showjob(out, getjob(*argv,0), mode);
+ showjob(stdout, getjob(*argv,0), mode);
while (*++argv);
} else
- showjobs(out, mode);
+ showjobs(stdout, mode);
return 0;
}
-
-/*
- * Print a list of jobs. If "change" is nonzero, only print jobs whose
- * statuses have changed since the last call to showjobs.
- */
-static void
-showjobs(FILE *out, int mode)
-{
- struct job *jp;
-
- TRACE(("showjobs(%x) called\n", mode));
-
- /* If not even one one job changed, there is nothing to do */
- while (dowait(DOWAIT_NORMAL, NULL) > 0)
- continue;
-
- for (jp = curjob; jp; jp = jp->prev_job) {
- if (!(mode & SHOW_CHANGED) || jp->changed)
- showjob(out, jp, mode);
- }
-}
#endif /* JOBS */
static int
}
memset(jp, 0, sizeof(*jp));
#if JOBS
+ /* jp->jobctl is a bitfield.
+ * "jp->jobctl |= jobctl" likely to give awful code */
if (jobctl)
jp->jobctl = 1;
#endif
}
}
}
-/* lives far away from here, needed for forkchild */
+
+/* Lives far away from here, needed for forkchild */
static void closescript(void);
+
+/* Called after fork(), in child */
static void
forkchild(struct job *jp, union node *n, int mode)
{
jobless = 0;
}
+/* Called after fork(), in parent */
static void
forkparent(struct job *jp, union node *n, int mode, pid_t pid)
{
static char *
_rmescapes(char *str, int flag)
{
+ static const char qchars[] ALIGN1 = { CTLESC, CTLQUOTEMARK, '\0' };
+
char *p, *q, *r;
- static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
unsigned inquotes;
int notescaped;
int globbing;
p = buf;
}
- if (in.buf)
- free(in.buf);
+ free(in.buf);
if (in.fd >= 0) {
close(in.fd);
back_exitstatus = waitforjob(in.jp);
static void
argstr(char *p, int flag)
{
- static const char spclchars[] = {
+ static const char spclchars[] ALIGN1 = {
'=',
':',
CTLQUOTEMARK,
static void
expandmeta(struct strlist *str, int flag)
{
- static const char metachars[] = {
+ static const char metachars[] ALIGN1 = {
'*', '?', '[', 0
};
/* TODO - EXP_REDIR */
a = find_applet_by_name(cmd);
if (a) {
- if (a->noexec) {
- char **c = argv;
- while (*c) c++;
- current_applet = a;
- run_current_applet_and_exit(c - argv, argv);
- }
+ if (a->noexec)
+ run_appletstruct_and_exit(a, argv);
/* re-exec ourselves with the new arguments */
- execve(CONFIG_BUSYBOX_EXEC_PATH, argv, envp);
+ execve(bb_busybox_exec_path, argv, envp);
/* If they called chroot or otherwise made the binary no longer
* executable, fall through */
}
findkwd(const char *s)
{
return bsearch(s, tokname_array + KWDOFFSET,
- (sizeof(tokname_array) / sizeof(char *)) - KWDOFFSET,
- sizeof(char *), pstrcmp);
+ ARRAY_SIZE(tokname_array) - KWDOFFSET,
+ sizeof(tokname_array[0]), 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] && argv[1][0] == '-') {
+ i++;
+ verbose = 0;
+ }
+ while (i < argc) {
+ err |= describe_command(argv[i++], verbose);
}
return err;
}
#if !ENABLE_FEATURE_SH_EXTRA_QUIET
if (is_interactive > 1) {
/* Looks like they want an interactive shell */
- static smallint do_banner;
+ static smallint did_banner;
- if (!do_banner) {
+ if (!did_banner) {
out1fmt(
"\n\n"
- "%s Built-in shell (ash)\n"
+ "%s built-in shell (ash)\n"
"Enter 'help' for a list of built-in commands."
"\n\n",
- BB_BANNER);
- do_banner = 1;
+ bb_banner);
+ did_banner = 1;
}
}
#endif
do {
switch (c) {
case 'p':
- *path = defpath;
+ *path = bb_default_path;
break;
default:
/* run 'typecmd' for other options */
{ BUILTIN_REGULAR "wait", waitcmd },
};
-#define NUMBUILTINS (sizeof(builtintab) / sizeof(builtintab[0]))
#define COMMANDCMD (builtintab + 5 + \
2 * ENABLE_ASH_BUILTIN_TEST + \
struct builtincmd *bp;
bp = bsearch(
- name, builtintab, NUMBUILTINS, sizeof(builtintab[0]),
+ name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
pstrcmp
);
return bp;
INPUT_NOFILE_OK = 2,
};
-/*
- * NEOF is returned by parsecmd when it encounters an end of file. It
- * must be distinct from NULL, so we use the address of a variable that
- * happens to be handy.
- */
static int plinno = 1; /* input line number */
/* number of characters left in input buffer */
static int parsenleft; /* copy of parsefile->nleft */
if (nr < 0) {
if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
- int flags = fcntl(0, F_GETFL, 0);
+ int flags = fcntl(0, F_GETFL);
if (flags >= 0 && flags & O_NONBLOCK) {
flags &=~ O_NONBLOCK;
if (fcntl(0, F_SETFL, flags) >= 0) {
INT_OFF;
if (pf->fd >= 0)
close(pf->fd);
- if (pf->buf)
- free(pf->buf);
+ free(pf->buf);
while (pf->strpush)
popstring();
parsefile = pf->prev;
static void
setinputfd(int fd, int push)
{
- fcntl(fd, F_SETFD, FD_CLOEXEC);
+ close_on_exec_on(fd);
if (push) {
pushfile();
parsefile->buf = 0;
/* times of mailboxes */
static time_t mailtime[MAXMBOXES];
/* Set if MAIL or MAILPATH is changed. */
-static int mail_var_path_changed;
+static smallint mail_var_path_changed;
/*
* Print appropriate message(s) if mail has arrived.
static void
changemail(const char *val)
{
- mail_var_path_changed++;
+ mail_var_path_changed = 1;
}
#endif /* ASH_MAIL */
if (cmdline)
minusc = NULL;
while ((p = *argptr) != NULL) {
- argptr++;
c = *p++;
+ if (c != '-' && c != '+')
+ break;
+ argptr++;
+ val = 0; /* val = 0 if c == '+' */
if (c == '-') {
val = 1;
if (p[0] == '\0' || LONE_DASH(p)) {
}
break; /* "-" or "--" terminates options */
}
- } else if (c == '+') {
- val = 0;
- } else {
- argptr--;
- break;
}
+ /* first char was + or - */
while ((c = *p++) != '\0') {
+ /* bash 3.2 indeed handles -c CMD and +c CMD the same */
if (c == 'c' && cmdline) {
- minusc = p; /* command is after shell args*/
+ minusc = p; /* command is after shell args */
} else if (c == 'o') {
minus_o(*argptr, val);
if (*argptr)
argptr++;
- } else if (cmdline && (c == '-')) { // long options
+ } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
+ isloginsh = 1;
+ /* bash does not accept +-login, we also won't */
+ } else if (cmdline && val && (c == '-')) { /* long options */
if (strcmp(p, "login") == 0)
isloginsh = 1;
break;
/* ============ Shell parser */
-static int tokpushback; /* last token pushed back */
+/*
+ * NEOF is returned by parsecmd when it encounters an end of file. It
+ * must be distinct from NULL, so we use the address of a variable that
+ * happens to be handy.
+ */
+static smallint tokpushback; /* last token pushed back */
#define NEOF ((union node *)&tokpushback)
-static int parsebackquote; /* nonzero if we are inside backquotes */
+static smallint parsebackquote; /* nonzero if we are inside backquotes */
static int lasttoken; /* last token read */
static char *wordtext; /* text of last word returned by readtoken */
static struct nodelist *backquotelist;
static union node *redirnode;
static struct heredoc *heredoc;
-static int quoteflag; /* set if (part of) last token was quoted */
+static smallint quoteflag; /* set if (part of) last token was quoted */
static void raise_error_syntax(const char *) ATTRIBUTE_NORETURN;
static void
if (nlflag == 1)
return n1;
} else {
- tokpushback++;
+ tokpushback = 1;
}
checkkwd = CHKNL | CHKKWD | CHKALIAS;
if (peektoken())
default:
if (nlflag == 1)
raise_error_unexpected_syntax(-1);
- tokpushback++;
+ tokpushback = 1;
return n1;
}
}
} else if (t == TOR) {
t = NOR;
} else {
- tokpushback++;
+ tokpushback = 1;
return n1;
}
checkkwd = CHKNL | CHKKWD | CHKALIAS;
negate = !negate;
checkkwd = CHKKWD | CHKALIAS;
} else
- tokpushback++;
+ tokpushback = 1;
n1 = parse_command();
if (readtoken() == TPIPE) {
pipenode = stalloc(sizeof(struct npipe));
lp->next = NULL;
n1 = pipenode;
}
- tokpushback++;
+ tokpushback = 1;
if (negate) {
n2 = stalloc(sizeof(struct nnot));
n2->type = NNOT;
}
/* fall through */
default:
- tokpushback++;
+ tokpushback = 1;
goto out;
}
}
n2->nif.elsepart = list(0);
else {
n2->nif.elsepart = NULL;
- tokpushback++;
+ tokpushback = 1;
}
t = TFI;
break;
* that the original Bourne shell only allowed NL).
*/
if (lasttoken != TNL && lasttoken != TSEMI)
- tokpushback++;
+ tokpushback = 1;
}
checkkwd = CHKNL | CHKKWD | CHKALIAS;
if (readtoken() != TDO)
break;
case TWORD:
case TREDIR:
- tokpushback++;
+ tokpushback = 1;
return simplecmd();
}
rpp = &n2->nfile.next;
parsefname();
}
- tokpushback++;
+ tokpushback = 1;
*rpp = NULL;
if (redir) {
if (n1->type != NSUBSHELL) {
* will run code that appears at the end of readtoken1.
*/
-static int parsebackquote; /* nonzero if we are inside backquotes */
-
#define CHECKEND() {goto checkend; checkend_return:;}
#define PARSEREDIR() {goto parseredir; parseredir_return:;}
#define PARSESUB() {goto parsesub; parsesub_return:;}
static int
readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
{
+ /* NB: syntax parameter fits into smallint */
int c = firstc;
char *out;
int len;
char line[EOFMARKLEN + 1];
- struct nodelist *bqlist = 0;
- int quotef = 0;
- int dblquote = 0;
- int varnest = 0; /* levels of variables expansion */
- int arinest = 0; /* levels of arithmetic expansion */
- int parenlevel = 0; /* levels of parens in arithmetic */
- int dqvarnest = 0; /* levels of variables expansion within double quotes */
- int oldstyle = 0;
- int prevsyntax = 0; /* syntax before arithmetic */
+ struct nodelist *bqlist;
+ smallint quotef;
+ smallint dblquote;
+ smallint oldstyle;
+ smallint prevsyntax; /* syntax before arithmetic */
+#if ENABLE_ASH_EXPAND_PRMT
+ smallint pssyntax; /* we are expanding a prompt string */
+#endif
+ int varnest; /* levels of variables expansion */
+ int arinest; /* levels of arithmetic expansion */
+ int parenlevel; /* levels of parens in arithmetic */
+ int dqvarnest; /* levels of variables expansion within double quotes */
+
#if __GNUC__
/* Avoid longjmp clobbering */
(void) &out;
(void) &prevsyntax;
(void) &syntax;
#endif
-
startlinno = plinno;
- dblquote = 0;
- if (syntax == DQSYNTAX)
- dblquote = 1;
- quotef = 0;
bqlist = NULL;
+ quotef = 0;
+ oldstyle = 0;
+ prevsyntax = 0;
+#if ENABLE_ASH_EXPAND_PRMT
+ pssyntax = (syntax == PSSYNTAX);
+ if (pssyntax)
+ syntax = DQSYNTAX;
+#endif
+ dblquote = (syntax == DQSYNTAX);
varnest = 0;
arinest = 0;
parenlevel = 0;
if (doprompt)
setprompt(2);
} else {
+#if ENABLE_ASH_EXPAND_PRMT
+ if (c == '$' && pssyntax) {
+ USTPUTC(CTLESC, out);
+ USTPUTC('\\', out);
+ }
+#endif
if (dblquote &&
c != '\\' && c != '`' &&
c != '$' && (
if (SIT(c, SQSYNTAX) == CCTL)
USTPUTC(CTLESC, out);
USTPUTC(c, out);
- quotef++;
+ quotef = 1;
}
break;
case CSQUOTE:
syntax = BASESYNTAX;
dblquote = 0;
}
- quotef++;
+ quotef = 1;
goto quotemark;
}
break;
if (--arinest == 0) {
USTPUTC(CTLENDARI, out);
syntax = prevsyntax;
- if (syntax == DQSYNTAX)
- dblquote = 1;
- else
- dblquote = 0;
+ dblquote = (syntax == DQSYNTAX);
} else
USTPUTC(')', out);
} else {
int typeloc;
int flags;
char *p;
- static const char types[] = "}-+?=";
+ static const char types[] ALIGN1 = "}-+?=";
c = pgetc();
if (
*/
parsebackq: {
struct nodelist **nlpp;
- int savepbq;
+ smallint savepbq;
union node *n;
char *volatile str;
struct jmploc jmploc;
struct jmploc *volatile savehandler;
size_t savelen;
- int saveprompt = 0;
+ smallint saveprompt = 0;
+
#ifdef __GNUC__
(void) &saveprompt;
#endif
-
savepbq = parsebackquote;
if (setjmp(jmploc.loc)) {
- if (str)
- free(str);
+ free(str);
parsebackquote = 0;
exception_handler = savehandler;
longjmp(exception_handler->loc, 1);
#define NEW_xxreadtoken
#ifdef NEW_xxreadtoken
/* singles must be first! */
-static const char xxreadtoken_chars[7] = { '\n', '(', ')', '&', '|', ';', 0 };
+static const char xxreadtoken_chars[7] ALIGN1 = {
+ '\n', '(', ')', '&', '|', ';', 0
+};
-static const char xxreadtoken_tokens[] = {
+static const char xxreadtoken_tokens[] ALIGN1 = {
TNL, TLP, TRP, /* only single occurrence allowed */
TBACKGND, TPIPE, TSEMI, /* if single occurrence */
TEOF, /* corresponds to trailing nul */
- TAND, TOR, TENDCASE, /* if double occurrence */
+ TAND, TOR, TENDCASE /* if double occurrence */
};
#define xxreadtoken_doubles \
{
int t;
#if DEBUG
- int alreadyseen = tokpushback;
+ smallint alreadyseen = tokpushback;
#endif
#if ENABLE_ASH_ALIAS
int t;
t = readtoken();
- tokpushback++;
+ tokpushback = 1;
return tokname_array[t][0];
}
return NEOF;
if (t == TNL)
return NULL;
- tokpushback++;
+ tokpushback = 1;
return list(1);
}
/* XXX Fix (char *) cast. */
setinputstring((char *)ps);
- readtoken1(pgetc(), DQSYNTAX, nullstr, 0);
+ readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
popfile();
n.narg.type = NARG;
}
numeof++;
} else if (nflag == 0) {
- job_warning = (job_warning == 2) ? 1 : 0;
+ /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
+ job_warning >>= 1;
numeof = 0;
evaltree(n, 0);
}
static int
testcmd(int argc, char **argv)
{
- return bb_test(argc, argv);
+ return test_main(argc, argv);
}
#endif
return;
}
-#if ENABLE_FEATURE_SH_STANDALONE
- if (find_applet_by_name(name)) {
- entry->cmdtype = CMDNORMAL;
- entry->u.index = -1;
- return;
- }
-#endif
+/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
updatetbl = (path == pathval());
if (!updatetbl) {
}
}
+#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 */
loop:
while ((fullname = padvance(&path, name)) != NULL) {
stunalloc(fullname);
+ /* NB: code below will still use fullname
+ * despite it being "unallocated" */
idx++;
if (pathopt) {
if (prefix(pathopt, "builtin")) {
if (bcmd)
goto builtin_success;
continue;
- } else if (!(act & DO_NOFUNC) &&
- prefix(pathopt, "func")) {
+ } else if (!(act & DO_NOFUNC)
+ && prefix(pathopt, "func")) {
/* handled below */
} else {
/* ignore unimplemented options */
continue;
if (pathopt) { /* this is a %func directory */
stalloc(strlen(fullname) + 1);
+ /* NB: stalloc will return space pointed by fullname
+ * (because we don't have any intervening allocations
+ * between stunalloc above and this stalloc) */
readcmdfile(fullname);
cmdp = cmdlookup(name, 0);
if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
else
action = ckstrdup(action);
}
- if (trap[signo])
- free(trap[signo]);
+ free(trap[signo]);
trap[signo] = action;
if (signo != 0)
setsignal(signo);
int col, i;
out1fmt("\nBuilt-in commands:\n-------------------\n");
- for (col = 0, i = 0; i < NUMBUILTINS; i++) {
+ for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
builtintab[i].name + 1);
if (col > 60) {
#include <sys/times.h>
-static const unsigned char timescmd_str[] = {
+static const unsigned char timescmd_str[] ALIGN1 = {
' ', offsetof(struct tms, tms_utime),
'\n', offsetof(struct tms, tms_stime),
' ', offsetof(struct tms, tms_cutime),
#endif
#if ENABLE_ASH_READ_TIMEOUT
if (ts.tv_sec || ts.tv_usec) {
- FD_ZERO (&set);
- FD_SET (0, &set);
+// TODO: replace with poll, it is smaller
+ FD_ZERO(&set);
+ FD_SET(0, &set);
i = select(FD_SETSIZE, &set, NULL, NULL, &ts);
if (!i) {
static int
umaskcmd(int argc, char **argv)
{
- static const char permuser[3] = "ugo";
- static const char permmode[3] = "rwx";
- static const short int permmask[] = {
+ static const char permuser[3] ALIGN1 = "ugo";
+ static const char permmode[3] ALIGN1 = "rwx";
+ static const short permmask[] ALIGN2 = {
S_IRUSR, S_IWUSR, S_IXUSR,
S_IRGRP, S_IWGRP, S_IXGRP,
S_IROTH, S_IWOTH, S_IXOTH
}
/* longest must be first */
-static const char op_tokens[] = {
+static const char op_tokens[] ALIGN1 = {
'<','<','=',0, TOK_LSHIFT_ASSIGN,
'>','>','=',0, TOK_RSHIFT_ASSIGN,
'<','<', 0, TOK_LSHIFT,
struct jmploc jmploc;
struct stackmark smark;
-#ifdef __GLIBC__
- dash_errno = __errno_location();
-#endif
-
#if PROFILE
monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
#endif