/* Enable job control. This allows you to run jobs in the background,
* which is great when ash is being used as an interactive shell, but
- * it completely useless for is all you are doing is running scripts.
+ * it completely useless for is all you are doing is running scripts.
* This adds about 2.5k on an x86 system. */
#define JOBS
* a little bit faster, but leaving this disabled will save you 2k. */
#undef ASH_BBAPPS_AS_BUILTINS
+/* Optimize size vs speed as size */
+#define ASH_OPTIMIZE_FOR_SIZE
+
/* Enable this to compile in extra debugging noise. When debugging is
* on, debugging info will be written to $HOME/trace and a quit signal
* will generate a core dump. */
#include "busybox.h"
#include "cmdedit.h"
-/* if BB_PWD is defined, then disable ASH_PWD to save space */
-#ifdef BB_PWD
-#undef ASH_PWD
-#endif
-
-
/*
* This file was generated by the mksyntax program.
*/
#define _DIAGASSERT(x)
-#define ATABSIZE 39
+
#define S_DFL 1 /* default signal handling (SIG_DFL) */
#define S_CATCH 2 /* signal is caught */
/* flags passed to redirect */
#define REDIR_PUSH 01 /* save previous values of file descriptors */
-#define REDIR_BACKQ 02 /* save the command output in memory */
+#define REDIR_BACKQ 02 /* save the command output to pipe */
/*
* BSD setjmp saves the signal mask, which violates ANSI C and takes time,
static volatile int intpending;
#define INTOFF suppressint++
-#ifdef ASH_BBAPPS_AS_BUILTINS
+#ifndef ASH_OPTIMIZE_FOR_SIZE
#define INTON { if (--suppressint == 0 && intpending) onint(); }
+#define FORCEINTON {suppressint = 0; if (intpending) onint();}
#else
static void __inton (void);
+static void forceinton (void);
#define INTON __inton()
+#define FORCEINTON forceinton()
#endif
-#define FORCEINTON {suppressint = 0; if (intpending) onint();}
+
#define CLEAR_PENDING_INT intpending = 0
#define int_pending() intpending
static void stunalloc (pointer);
static void ungrabstackstr (char *, char *);
static char * growstackstr(void);
+static char * makestrspace(size_t newlen);
static char *sstrdup (const char *);
/*
#define stackblock() stacknxt
#define stackblocksize() stacknleft
#define STARTSTACKSTR(p) p = stackblock(), sstrnleft = stackblocksize()
+
#define STPUTC(c, p) (--sstrnleft >= 0? (*p++ = (c)) : (p = growstackstr(), *p++ = (c)))
#define CHECKSTRSPACE(n, p) { if (sstrnleft < n) p = makestrspace(n); }
-#define USTPUTC(c, p) (--sstrnleft, *p++ = (c))
#define STACKSTRNUL(p) (sstrnleft == 0? (p = growstackstr(), *p = '\0') : (*p = '\0'))
+
+
+#define USTPUTC(c, p) (--sstrnleft, *p++ = (c))
#define STUNPUTC(p) (++sstrnleft, --p)
#define STTOPC(p) p[-1]
#define STADJUST(amount, p) (p += (amount), sstrnleft -= (amount))
#define ckfree(p) free((pointer)(p))
-static char * makestrspace(size_t newlen);
#ifdef DEBUG
#define TRACE(param) trace param
int optoff; /* used by getopts */
};
-struct output {
-#ifdef USE_GLIBC_STDIO
- FILE *stream;
-#endif
- char *nextc;
- int nleft;
- char *buf;
- int bufsize;
- int fd;
- short flags;
-};
-
-#define OUTBUFSIZ BUFSIZ
-#define MEM_OUT -3 /* output to dynamically allocated memory */
-
-
-#ifdef USE_GLIBC_STDIO
-static struct output output = {NULL, NULL, 0, NULL, 0, 1, 0};
-static struct output errout = {NULL, NULL, 0, NULL, 0, 2, 0};
-static struct output memout = {NULL, NULL, 0, NULL, 0, MEM_OUT, 0};
-#else
-static struct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0};
-static struct output errout = {NULL, 0, NULL, 0, 2, 0};
-static struct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0};
-#endif
-static struct output *out1 = &output;
-static struct output *out2 = &errout;
-
-#ifndef USE_GLIBC_STDIO
-static void outcslow (char, struct output *);
-#endif
static void flushall (void);
-static void flushout (struct output *);
-static void freestdout (void);
-static void outfmt (struct output *, const char *, ...)
- __attribute__((__format__(__printf__,2,3)));
+static void out2fmt (const char *, ...)
+ __attribute__((__format__(__printf__,1,2)));
static void out1fmt (const char *, ...)
__attribute__((__format__(__printf__,1,2)));
-static void fmtstr (char *, size_t, const char *, ...)
- __attribute__((__format__(__printf__,3,4)));
-#ifndef USE_GLIBC_STDIO
-static void doformat (struct output *, const char *, va_list);
-#endif
static int xwrite (int, const char *, int);
-#ifdef USE_GLIBC_STDIO
-static void initstreams (void);
-static void openmemout (void);
-static int __closememout (void);
-#endif
-static void outstr(const char *p, struct output *file);
+static void outstr (const char *p, FILE *file) { fputs(p, file); }
+static void out1str(const char *p) { outstr(p, stdout); }
+static void out2str(const char *p) { outstr(p, stderr); }
-#define OUTPUT_ERR 01 /* error occurred on output */
-
-#ifdef USE_GLIBC_STDIO
-#define outc(c, o) putc((c), (o)->stream)
-#define doformat(d, f, a) vfprintf((d)->stream, (f), (a))
-#else
-#define outc(c, file) (--(file)->nleft < 0? outcslow((c), (file)) : (*(file)->nextc = (c), (file)->nextc++))
-#endif
-#define out1c(c) outc((c), out1)
-#define out2c(c) outc((c), out2)
-#define out1str(s) outstr((s), out1)
-#define out2str(s) outstr((s), out2)
-#define outerr(f) ((f)->flags & OUTPUT_ERR)
+#define out2c(c) putc((c), stderr)
/* syntax table used when not in quotes */
static const char basesyntax[257] = {
#define ALIASINUSE 1
#define ALIASDEAD 2
+#define ATABSIZE 39
+
struct alias {
struct alias *next;
char *name;
while ((n = *++argv) != NULL) {
if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
if ((ap = *__lookupalias(n)) == NULL) {
- outfmt(out2, "%s: %s not found\n", "alias", n);
+ out2fmt("%s: %s not found\n", "alias", n);
ret = 1;
} else
printalias(ap);
}
for (i = 0; *argptr; argptr++) {
if (unalias(*argptr)) {
- outfmt(out2, "%s: %s not found\n", "unalias", *argptr);
+ out2fmt("%s: %s not found\n", "unalias", *argptr);
i = 1;
}
}
static int hashcmd (int, char **);
static int jobscmd (int, char **);
static int localcmd (int, char **);
-#ifdef ASH_PWD
+#ifndef BB_PWD
static int pwdcmd (int, char **);
#endif
static int readcmd (int, char **);
{ BUILTIN_REGULAR "bg", bgcmd },
#endif
{ BUILTIN_SPECIAL "break", breakcmd },
- { BUILTIN_SPECIAL "builtin", bltincmd }, /* Do not disable this builtin ever or bad things happen */
+ { BUILTIN_SPECIAL "builtin", bltincmd },
{ BUILTIN_REGULAR "cd", cdcmd },
#ifdef ASH_BBAPPS_AS_BUILTINS
{ BUILTIN_NOSPEC "chdir", cdcmd },
{ BUILTIN_NOSPEC "let", expcmd },
#endif
{ BUILTIN_ASSIGN "local", localcmd },
-#ifdef ASH_PWD
+#ifndef BB_PWD
{ BUILTIN_NOSPEC "pwd", pwdcmd },
#endif
{ BUILTIN_REGULAR "read", readcmd },
}
-#ifdef ASH_PWD
+#ifndef BB_PWD
static int
pwdcmd(argc, argv)
int argc;
#endif
if (msg) {
if (commandname)
- outfmt(&errout, "%s: ", commandname);
- doformat(&errout, msg, ap);
-#if FLUSHERR
- outc('\n', &errout);
-#else
- outcslow('\n', &errout);
-#endif
+ out2fmt("%s: ", commandname);
+ vfprintf(stderr, msg, ap);
+ out2c('\n');
}
flushall();
exraise(cond);
return strerror(e);
}
- fmtstr(buf, sizeof buf, "error %d", e);
+ snprintf(buf, sizeof buf, "error %d", e);
return buf;
}
-#ifndef ASH_BBAPPS_AS_BUILTINS
+#ifdef ASH_OPTIMIZE_FOR_SIZE
static void
__inton() {
if (--suppressint == 0 && intpending) {
onint();
}
}
+static void forceinton (void) {
+ suppressint = 0;
+ if (intpending)
+ onint();
+}
#endif
/* flags in argument to evaltree */
static void evalsubshell (union node *, int);
static void expredir (union node *);
static void evalpipe (union node *);
-#ifdef notyet
-static void evalcommand (union node *, int, struct backcmd *);
-#else
static void evalcommand (union node *, int);
-#endif
static void prehash (union node *);
static void eprintlist (struct strlist *);
(bcmd = find_builtin(n->narg.text)) &&
IS_BUILTIN_SPECIAL(bcmd)
) {
- outfmt(out2, "%s is a special built-in\n", n->narg.text);
+ out2fmt("%s is a special built-in\n", n->narg.text);
exitstatus = 1;
break;
}
checkexit = 1;
break;
case NCMD:
-#ifdef notyet
- evalcommand(n, flags, (struct backcmd *)NULL);
-#else
evalcommand(n, flags);
-#endif
checkexit = 1;
break;
#ifdef DEBUG
default:
out1fmt("Node type = %d\n", n->type);
-#ifndef USE_GLIBC_STDIO
- flushout(out1);
-#endif
break;
#endif
}
}
-
/*
* Compute the names of the files in a redirection list.
*/
exitstatus = 0;
goto out;
}
-#ifdef notyet
- /*
- * For now we disable executing builtins in the same
- * context as the shell, because we are not keeping
- * enough state to recover from changes that are
- * supposed only to affect subshells. eg. echo "`cd /`"
- */
- if (n->type == NCMD) {
- exitstatus = oexitstatus;
- evalcommand(n, EV_BACKCMD, result);
- } else
-#endif
- {
- exitstatus = 0;
- if (pipe(pip) < 0)
- error("Pipe call failed");
- jp = makejob(n, 1);
- if (forkshell(jp, n, FORK_NOJOB) == 0) {
- FORCEINTON;
- close(pip[0]);
- if (pip[1] != 1) {
- close(1);
- dup_as_newfd(pip[1], 1);
- close(pip[1]);
- }
- eflag = 0;
- evaltree(n, EV_EXIT);
+ exitstatus = 0;
+ if (pipe(pip) < 0)
+ error("Pipe call failed");
+ jp = makejob(n, 1);
+ if (forkshell(jp, n, FORK_NOJOB) == 0) {
+ FORCEINTON;
+ close(pip[0]);
+ if (pip[1] != 1) {
+ close(1);
+ dup_as_newfd(pip[1], 1);
+ close(pip[1]);
}
- close(pip[1]);
- result->fd = pip[0];
- result->jp = jp;
+ eflag = 0;
+ evaltree(n, EV_EXIT);
}
+ close(pip[1]);
+ result->fd = pip[0];
+ result->jp = jp;
out:
popstackmark(&smark);
TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
}
static void
-#ifdef notyet
-evalcommand(cmd, flags, backcmd)
- union node *cmd;
- int flags;
- struct backcmd *backcmd;
-#else
-evalcommand(cmd, flags)
- union node *cmd;
- int flags;
-#endif
+evalcommand(union node *cmd, int flags)
{
struct stackmark smark;
union node *argp;
char **envp;
struct strlist *sp;
int mode;
-#ifdef notyet
- int pip[2];
-#endif
struct cmdentry cmdentry;
struct job *jp;
char *volatile savecmdname;
/* Print the command if xflag is set. */
if (xflag) {
-#ifdef FLUSHERR
- outc('+', &errout);
-#else
- outcslow('+', &errout);
-#endif
+ out2c('+');
eprintlist(varlist.list);
eprintlist(arglist.list);
-#ifdef FLUSHERR
- outc('\n', &errout);
- flushout(&errout);
-#else
- outcslow('\n', &errout);
-#endif
+ out2c('\n');
}
/* Now locate the command. */
find_command(argv[0], &cmdentry, findflag, path);
if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */
exitstatus = 127;
-#ifdef FLUSHERR
- flushout(&errout);
-#endif
goto out;
}
/* implement bltin and command here */
if (--argc == 0)
goto found;
if (!(bcmd = find_builtin(*argv))) {
- outfmt(&errout, "%s: not found\n", *argv);
+ out2fmt("%s: not found\n", *argv);
exitstatus = 127;
-#ifdef FLUSHERR
- flushout(&errout);
-#endif
goto out;
}
cmdentry.u.cmd = bcmd;
/* Fork off a child process if necessary. */
if (cmd->ncmd.backgnd
|| (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0)
-#ifdef notyet
- || ((flags & EV_BACKCMD) != 0
- && (cmdentry.cmdtype != CMDBUILTIN
- || cmdentry.u.bcmd == DOTCMD
- || cmdentry.u.bcmd == EVALCMD))
-#endif
) {
jp = makejob(cmd, 1);
mode = cmd->ncmd.backgnd;
-#ifdef notyet
- if (flags & EV_BACKCMD) {
- mode = FORK_NOJOB;
- if (pipe(pip) < 0)
- error("Pipe call failed");
- }
-#endif
if (forkshell(jp, cmd, mode) != 0)
goto parent; /* at end of routine */
-#ifdef notyet
- if (flags & EV_BACKCMD) {
- FORCEINTON;
- close(pip[0]);
- if (pip[1] != 1) {
- close(1);
- dup_as_newfd(pip[1], 1);
- close(pip[1]);
- }
- }
-#endif
flags |= EV_EXIT;
}
trputs("builtin command: "); trargs(argv);
#endif
mode = (cmdentry.u.cmd == EXECCMD)? 0 : REDIR_PUSH;
-#ifdef notyet
- if (flags == EV_BACKCMD) {
-#ifdef USE_GLIBC_STDIO
- openmemout();
-#else
- memout.nleft = 0;
- memout.nextc = memout.buf;
- memout.bufsize = 64;
-#endif
- mode |= REDIR_BACKQ;
- }
-#endif
redirect(cmd->ncmd.redirect, mode);
savecmdname = commandname;
if (IS_BUILTIN_SPECIAL(firstbltin)) {
exitstatus = (*cmdentry.u.cmd->builtinfunc)(argc, argv);
flushall();
cmddone:
- exitstatus |= outerr(out1);
- out1 = &output;
- out2 = &errout;
- freestdout();
cmdenviron = NULL;
if (e != EXSHELLPROC) {
commandname = savecmdname;
}
if (cmdentry.u.cmd != EXECCMD)
popredir();
-#ifdef notyet
- if (flags == EV_BACKCMD) {
- INTOFF;
-#ifdef USE_GLIBC_STDIO
- if (__closememout())
- error("__closememout() failed: %m");
-#endif
- backcmd->buf = memout.buf;
-#ifdef USE_GLIBC_STDIO
- backcmd->nleft = memout.bufsize;
-#else
- backcmd->nleft = memout.nextc - memout.buf;
-#endif
- memout.buf = NULL;
- INTON;
- }
-#endif
} else {
#ifdef DEBUG
trputs("normal command: "); trargs(argv);
INTOFF;
exitstatus = waitforjob(jp);
INTON;
-#ifdef notyet
- } else if (mode == 2) {
- backcmd->fd = pip[0];
- close(pip[1]);
- backcmd->jp = jp;
-#endif
}
out:
eprintlist(struct strlist *sp)
{
for (; sp; sp = sp->next) {
- outfmt(&errout, " %s",sp->text);
+ out2fmt(" %s",sp->text);
}
}
/*
* Nul characters in the input are silently discarded.
*/
-#ifdef ASH_BBAPPS_AS_BUILTINS
+#ifndef ASH_OPTIMIZE_FOR_SIZE
#define pgetc_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
static int
pgetc(void)
{
int e;
+#ifdef BB_FEATURE_SH_STANDALONE_SHELL
+ char *name = cmd;
+ char** argv_l=argv;
+ int argc_l;
+#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN
+ name = get_last_path_component(name);
+#endif
+ argv_l=envp;
+ for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++)
+ putenv(*argv_l);
+ argv_l=argv;
+ for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++);
+ optind = 1;
+ run_applet_by_name(name, argc_l, argv);
+#endif
execve(cmd, argv, envp);
e = errno;
if (e == ENOEXEC) {
if (cmdp && updatetbl)
delete_cmd_entry();
if (act & DO_ERR)
- outfmt(out2, "%s: %s\n", name, errmsg(e, E_EXEC));
+ out2fmt("%s: %s\n", name, errmsg(e, E_EXEC));
entry->cmdtype = CMDUNKNOWN;
return;
}
out:
- out1c('\n');
+ putchar('\n');
return 0;
}
#endif
verbose_verify_only = 1;
break;
default:
- outfmt(out2,
+ out2fmt(
"command: nextopt returned character code 0%o\n", c);
return EX_SOFTWARE;
}
if (default_path + verify_only + verbose_verify_only > 1 ||
!*argptr) {
- outfmt(out2,
+ out2fmt(
"command [-p] command [arg ...]\n");
- outfmt(out2,
+ out2fmt(
"command {-v|-V} command\n");
return EX_USAGE;
}
if (quotes)
rmescapes(p+2);
result = arith(p+2);
- fmtstr(p, 12, "%d", result);
+ snprintf(p, 12, "%d", result);
while (*p++)
;
case VSQUESTION:
if (*p != CTLENDVAR) {
- outfmt(&errout, snlfmt, startp);
+ out2fmt(snlfmt, startp);
error((char *)NULL);
}
error("%.*s: parameter %snot set", p - str - 1,
basepf.nextc = basepf.buf = basebuf;
}
- /* from output.c: */
- {
-#ifdef USE_GLIBC_STDIO
- initstreams();
-#endif
- }
-
/* from var.c: */
{
char **envp;
}
}
- fmtstr(ppid, sizeof(ppid), "%d", (int) getppid());
+ snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
setvar("PPID", ppid, 0);
}
}
popredir();
}
- /* from output.c: */
- {
- out1 = &output;
- out2 = &errout;
-#ifdef USE_GLIBC_STDIO
- if (memout.stream != NULL)
- __closememout();
-#endif
- if (memout.buf != NULL) {
- ckfree(memout.buf);
- memout.buf = NULL;
- }
- }
}
}
if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
return PEOF;
- flushout(&output);
-#ifdef FLUSHERR
- flushout(&errout);
-#endif
+ flushall();
again:
if (parselleft <= 0) {
if (vflag) {
out2str(parsenextc);
-#ifdef FLUSHERR
- flushout(out2);
-#endif
}
*q = savec;
return fd0_redirected != 0;
}
-/*
- * We also keep track of where fileno2 goes.
- */
-static int fileno2 = 2;
-
static int openredirect (union node *);
static void dupredirect (union node *, int, char[10 ]);
static int openhere (union node *);
if (enable) {
do { /* while we are in the background */
#ifdef OLD_TTY_DRIVER
- if (ioctl(fileno2, TIOCGPGRP, (char *)&initialpgrp) < 0) {
+ if (ioctl(2, TIOCGPGRP, (char *)&initialpgrp) < 0) {
#else
- initialpgrp = tcgetpgrp(fileno2);
+ initialpgrp = tcgetpgrp(2);
if (initialpgrp < 0) {
#endif
out2str("sh: can't access tty; job cenabletrol turned off\n");
}
} while (0);
#ifdef OLD_TTY_DRIVER
- if (ioctl(fileno2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) {
+ if (ioctl(2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) {
out2str("sh: need new tty driver to run job cenabletrol; job cenabletrol turned off\n");
mflag = 0;
return;
setsignal(SIGTTIN);
setpgid(0, rootpid);
#ifdef OLD_TTY_DRIVER
- ioctl(fileno2, TIOCSPGRP, (char *)&rootpid);
+ ioctl(2, TIOCSPGRP, (char *)&rootpid);
#else
- tcsetpgrp(fileno2, rootpid);
+ tcsetpgrp(2, rootpid);
#endif
} else { /* turning job cenabletrol off */
setpgid(0, initialpgrp);
#ifdef OLD_TTY_DRIVER
- ioctl(fileno2, TIOCSPGRP, (char *)&initialpgrp);
+ ioctl(2, TIOCSPGRP, (char *)&initialpgrp);
#else
- tcsetpgrp(fileno2, initialpgrp);
+ tcsetpgrp(2, initialpgrp);
#endif
setsignal(SIGTSTP);
setsignal(SIGTTOU);
error("job not created under job control");
pgrp = jp->ps[0].pid;
#ifdef OLD_TTY_DRIVER
- ioctl(fileno2, TIOCSPGRP, (char *)&pgrp);
+ ioctl(2, TIOCSPGRP, (char *)&pgrp);
#else
- tcsetpgrp(fileno2, pgrp);
+ tcsetpgrp(2, pgrp);
#endif
restartjob(jp);
INTOFF;
procno = jp->nprocs;
for (ps = jp->ps ; ; ps++) { /* for each process */
if (ps == jp->ps)
- fmtstr(s, 64, "[%d] %ld ", jobno,
+ snprintf(s, 64, "[%d] %ld ", jobno,
(long)ps->pid);
else
- fmtstr(s, 64, " %ld ",
+ snprintf(s, 64, " %ld ",
(long)ps->pid);
out1str(s);
col = strlen(s);
if (ps->status == -1) {
/* don't print anything */
} else if (WIFEXITED(ps->status)) {
- fmtstr(s, 64, "Exit %d",
+ snprintf(s, 64, "Exit %d",
WEXITSTATUS(ps->status));
} else {
#ifdef JOBS
if ((i & 0x7F) < NSIG && sys_siglist[i & 0x7F])
strcpy(s, sys_siglist[i & 0x7F]);
else
- fmtstr(s, 64, "Signal %d", i & 0x7F);
+ snprintf(s, 64, "Signal %d", i & 0x7F);
if (WCOREDUMP(ps->status))
strcat(s, " (core dumped)");
}
if (mode == FORK_FG) {
/*** this causes superfluous TIOCSPGRPS ***/
#ifdef OLD_TTY_DRIVER
- if (ioctl(fileno2, TIOCSPGRP, (char *)&pgrp) < 0)
+ if (ioctl(2, TIOCSPGRP, (char *)&pgrp) < 0)
error("TIOCSPGRP failed, errno=%d", errno);
#else
- if (tcsetpgrp(fileno2, pgrp) < 0)
+ if (tcsetpgrp(2, pgrp) < 0)
error("tcsetpgrp failed, errno=%d", errno);
#endif
}
#ifdef JOBS
if (jp->jobctl) {
#ifdef OLD_TTY_DRIVER
- if (ioctl(fileno2, TIOCSPGRP, (char *)&mypgrp) < 0)
+ if (ioctl(2, TIOCSPGRP, (char *)&mypgrp) < 0)
error("TIOCSPGRP failed, errno=%d\n", errno);
#else
- if (tcsetpgrp(fileno2, mypgrp) < 0)
+ if (tcsetpgrp(2, mypgrp) < 0)
error("tcsetpgrp failed, errno=%d\n", errno);
#endif
}
if (sig != 0 && sig != SIGINT && sig != SIGPIPE) {
if (thisjob != job)
- outfmt(out2, "%d: ", pid);
+ out2fmt("%d: ", pid);
#ifdef JOBS
if (sig == SIGTSTP && rootshell && iflag)
- outfmt(out2, "%%%ld ",
+ out2fmt("%%%ld ",
(long)(job - jobtab + 1));
#endif
if (sig < NSIG && sys_siglist[sig])
out2str(sys_siglist[sig]);
else
- outfmt(out2, "Signal %d", sig);
+ out2fmt("Signal %d", sig);
if (core)
out2str(" - core dumped");
out2c('\n');
-#ifdef FLUSHERR
- flushout(&errout);
-#endif
} else {
TRACE(("Not printing status: status=%d, sig=%d\n",
status, sig));
if (stat(p, &statb) < 0)
statb.st_size = 0;
if (statb.st_size > mailtime[i] && ! silent) {
- outfmt(
- &errout, snlfmt,
- pathopt? pathopt : "you have mail"
- );
+ out2fmt(snlfmt,
+ pathopt? pathopt : "you have mail");
}
mailtime[i] = statb.st_size;
}
reset();
if (exception == EXINT) {
out2c('\n');
-#ifdef FLUSHERR
- flushout(out2);
-#endif
}
popstackmark(&smark);
FORCEINTON; /* enable interrupts */
inter++;
showjobs(1);
chkmail(0);
- flushout(&output);
+ flushall();
}
n = parsecmd(inter);
/* showtree(n); DEBUG */
err |= setvarsafe("OPTARG", s, 0);
}
else {
- outfmt(&errout, "Illegal option -%c\n", c);
+ out2fmt("Illegal option -%c\n", c);
(void) unsetvar("OPTARG");
}
c = '?';
c = ':';
}
else {
- outfmt(&errout, "No arg for -%c option\n", c);
+ out2fmt("No arg for -%c option\n", c);
(void) unsetvar("OPTARG");
c = '?';
}
p = NULL;
out:
*optoff = p ? p - *(optnext - 1) : -1;
- fmtstr(s, sizeof(s), "%d", *myoptind);
+ snprintf(s, sizeof(s), "%d", *myoptind);
err |= setvarsafe("OPTIND", s, VNOFUNC);
s[0] = c;
s[1] = '\0';
return c;
}
-
-/*
- * Shell output routines. We use our own output routines because:
- * When a builtin command is interrupted we have to discard
- * any pending output.
- * When a builtin command appears in back quotes, we want to
- * save the output of the command in a region obtained
- * via malloc, rather than doing a fork and reading the
- * output of the command via a pipe.
- * Our output routines may be smaller than the stdio routines.
- */
-
-
-
-#ifndef USE_GLIBC_STDIO
-static void __outstr (const char *, size_t, struct output*);
-#endif
-
-
-#ifndef USE_GLIBC_STDIO
-static void
-__outstr(const char *p, size_t len, struct output *dest) {
- if (!dest->bufsize) {
- dest->nleft = 0;
- } else if (dest->buf == NULL) {
- if (len > dest->bufsize && dest->fd == MEM_OUT) {
- dest->bufsize = len;
- }
- INTOFF;
- dest->buf = ckmalloc(dest->bufsize);
- dest->nextc = dest->buf;
- dest->nleft = dest->bufsize;
- INTON;
- } else if (dest->fd == MEM_OUT) {
- int offset;
-
- offset = dest->bufsize;
- INTOFF;
- if (dest->bufsize >= len) {
- dest->bufsize <<= 1;
- } else {
- dest->bufsize += len;
- }
- dest->buf = ckrealloc(dest->buf, dest->bufsize);
- dest->nleft = dest->bufsize - offset;
- dest->nextc = dest->buf + offset;
- INTON;
- } else {
- flushout(dest);
- }
-
- if (len < dest->nleft) {
- dest->nleft -= len;
- memcpy(dest->nextc, p, len);
- dest->nextc += len;
- return;
- }
-
- if (xwrite(dest->fd, p, len) < len)
- dest->flags |= OUTPUT_ERR;
-}
-#endif
-
-
-static void
-outstr(const char *p, struct output *file)
-{
-#ifdef USE_GLIBC_STDIO
- INTOFF;
- fputs(p, file->stream);
- INTON;
-#else
- size_t len;
-
- if (!*p) {
- return;
- }
- len = strlen(p);
- if ((file->nleft -= len) > 0) {
- memcpy(file->nextc, p, len);
- file->nextc += len;
- return;
- }
- __outstr(p, len, file);
-#endif
-}
-
-
-#ifndef USE_GLIBC_STDIO
-
-
-static void
-outcslow(c, dest)
- char c;
- struct output *dest;
- {
- __outstr(&c, 1, dest);
-}
-#endif
-
-
static void
flushall() {
- flushout(&output);
-#ifdef FLUSHERR
- flushout(&errout);
-#endif
-}
-
-
-static void
-flushout(dest)
- struct output *dest;
- {
-#ifdef USE_GLIBC_STDIO
INTOFF;
- fflush(dest->stream);
+ fflush(stdout);
INTON;
-#else
- size_t len;
-
- len = dest->nextc - dest->buf;
- if (dest->buf == NULL || !len || dest->fd < 0)
- return;
- dest->nextc = dest->buf;
- dest->nleft = dest->bufsize;
- if (xwrite(dest->fd, dest->buf, len) < len)
- dest->flags |= OUTPUT_ERR;
-#endif
-}
-
-
-static void
-freestdout() {
- if (output.buf) {
- INTOFF;
- ckfree(output.buf);
- output.buf = NULL;
- output.nleft = 0;
- INTON;
- }
- output.flags = 0;
}
static void
-#ifdef __STDC__
-outfmt(struct output *file, const char *fmt, ...)
-#else
-static void
-outfmt(va_alist)
- va_dcl
-#endif
+out2fmt(const char *fmt, ...)
{
va_list ap;
-#ifndef __STDC__
- struct output *file;
- const char *fmt;
-
- va_start(ap);
- file = va_arg(ap, struct output *);
- fmt = va_arg(ap, const char *);
-#else
va_start(ap, fmt);
-#endif
- doformat(file, fmt, ap);
+ vfprintf(stderr, fmt, ap);
va_end(ap);
}
static void
-#ifdef __STDC__
out1fmt(const char *fmt, ...)
-#else
-out1fmt(va_alist)
- va_dcl
-#endif
{
va_list ap;
-#ifndef __STDC__
- const char *fmt;
-
- va_start(ap);
- fmt = va_arg(ap, const char *);
-#else
va_start(ap, fmt);
-#endif
- doformat(out1, fmt, ap);
+ vfprintf(stdout, fmt, ap);
va_end(ap);
}
-static void
-#ifdef __STDC__
-fmtstr(char *outbuf, size_t length, const char *fmt, ...)
-#else
-fmtstr(va_alist)
- va_dcl
-#endif
-{
- va_list ap;
-#ifndef __STDC__
- char *outbuf;
- size_t length;
- const char *fmt;
-
- va_start(ap);
- outbuf = va_arg(ap, char *);
- length = va_arg(ap, size_t);
- fmt = va_arg(ap, const char *);
-#else
- va_start(ap, fmt);
-#endif
- INTOFF;
- vsnprintf(outbuf, length, fmt, ap);
- INTON;
-}
-
-#ifndef USE_GLIBC_STDIO
-
-static void
-doformat(struct output *dest, const char *f, va_list ap)
-{
- char *pm;
- int size = BUFSIZ;
-
- while(size) {
- int nchars;
-
- pm = xmalloc(size);
- nchars = vsnprintf(pm, size, f, ap);
- if(nchars > -1) {
- outstr(pm, dest);
- size = 0;
- }
- else
- size *= 2;
- free(pm);
- }
-}
-#endif
-
-
-
/*
* Version of write which resumes after a signal is caught.
*/
}
-#ifdef USE_GLIBC_STDIO
-static void initstreams() {
- output.stream = stdout;
- errout.stream = stderr;
-}
-
-
-static void
-openmemout() {
- INTOFF;
- memout.stream = open_memstream(&memout.buf, &memout.bufsize);
- INTON;
-}
-
-
-static int
-__closememout() {
- int error;
- error = fclose(memout.stream);
- memout.stream = NULL;
- return error;
-}
-#endif
/*
* Shell command parser.
*/
c = pgetc_macro();
switch (c) {
case ' ': case '\t':
+#ifdef ASH_ALIAS
case PEOA:
+#endif
continue;
case '#':
while ((c = pgetc()) != '\n' && c != PEOF);
default:
if (varnest == 0)
goto endword; /* exit outer loop */
- if (c != PEOA) {
+#ifdef ASH_ALIAS
+ if (c != PEOA)
+#endif
USTPUTC(c, out);
- }
+
}
c = pgetc_macro();
}
char msg[64];
if (token >= 0) {
- fmtstr(msg, 64, "%s unexpected (expecting %s)",
+ snprintf(msg, 64, "%s unexpected (expecting %s)",
tokname[lasttoken], tokname[token]);
} else {
- fmtstr(msg, 64, "%s unexpected", tokname[lasttoken]);
+ snprintf(msg, 64, "%s unexpected", tokname[lasttoken]);
}
synerror(msg);
/* NOTREACHED */
synerror(const char *msg)
{
if (commandname)
- outfmt(&errout, "%s: %d: ", commandname, startlinno);
- outfmt(&errout, "Syntax error: %s\n", msg);
+ out2fmt("%s: %d: ", commandname, startlinno);
+ out2fmt("Syntax error: %s\n", msg);
error((char *)NULL);
/* NOTREACHED */
}
* called by editline -- any expansions to the prompt
* should be added here.
*/
-static const char *
+static inline const char *
getprompt(void *unused)
{
switch (whichprompt) {
* old file descriptors are stashed away so that the redirection can be
* undone by calling popredir. If the REDIR_BACKQ flag is set, then the
* standard output, and the standard error if it becomes a duplicate of
- * stdout, is saved in memory.
+ * stdout.
*/
static void
INTOFF;
newfd = openredirect(n);
- if (((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) ||
- (fd == fileno2)) {
+ if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
if (newfd == fd) {
try++;
} else if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
if (flags & REDIR_PUSH) {
sv->renamed[fd] = i;
}
- if (fd == fileno2) {
- fileno2 = i;
- }
}
} else if (fd != newfd) {
close(fd);
dupredirect(n, newfd, memory);
INTON;
}
- if (memory[1])
- out1 = &memout;
- if (memory[2])
- out2 = &memout;
}
dup_as_newfd(rp->renamed[i], i);
close(rp->renamed[i]);
}
- if (rp->renamed[i] == fileno2) {
- fileno2 = i;
- }
}
}
redirlist = rp->next;
for (i = 0 ; i < 10 ; i++) {
if (rp->renamed[i] >= 0) {
close(rp->renamed[i]);
- if (rp->renamed[i] == fileno2) {
- fileno2 = -1;
- }
}
rp->renamed[i] = EMPTY;
}
}
- if (fileno2 != 2 && fileno2 >= 0) {
- close(fileno2);
- fileno2 = -1;
- }
}
/*
* Copyright (c) 1999 Herbert Xu <herbert@debian.org>
* This file contains code for the times builtin.
- * $Id: ash.c,v 1.5 2001/07/05 05:24:12 andersen Exp $
+ * $Id: ash.c,v 1.6 2001/07/06 04:26:23 andersen Exp $
*/
static int timescmd (int argc, char **argv)
{
/* Enable job control. This allows you to run jobs in the background,
* which is great when ash is being used as an interactive shell, but
- * it completely useless for is all you are doing is running scripts.
+ * it completely useless for is all you are doing is running scripts.
* This adds about 2.5k on an x86 system. */
#define JOBS
* a little bit faster, but leaving this disabled will save you 2k. */
#undef ASH_BBAPPS_AS_BUILTINS
+/* Optimize size vs speed as size */
+#define ASH_OPTIMIZE_FOR_SIZE
+
/* Enable this to compile in extra debugging noise. When debugging is
* on, debugging info will be written to $HOME/trace and a quit signal
* will generate a core dump. */
#include "busybox.h"
#include "cmdedit.h"
-/* if BB_PWD is defined, then disable ASH_PWD to save space */
-#ifdef BB_PWD
-#undef ASH_PWD
-#endif
-
-
/*
* This file was generated by the mksyntax program.
*/
#define _DIAGASSERT(x)
-#define ATABSIZE 39
+
#define S_DFL 1 /* default signal handling (SIG_DFL) */
#define S_CATCH 2 /* signal is caught */
/* flags passed to redirect */
#define REDIR_PUSH 01 /* save previous values of file descriptors */
-#define REDIR_BACKQ 02 /* save the command output in memory */
+#define REDIR_BACKQ 02 /* save the command output to pipe */
/*
* BSD setjmp saves the signal mask, which violates ANSI C and takes time,
static volatile int intpending;
#define INTOFF suppressint++
-#ifdef ASH_BBAPPS_AS_BUILTINS
+#ifndef ASH_OPTIMIZE_FOR_SIZE
#define INTON { if (--suppressint == 0 && intpending) onint(); }
+#define FORCEINTON {suppressint = 0; if (intpending) onint();}
#else
static void __inton (void);
+static void forceinton (void);
#define INTON __inton()
+#define FORCEINTON forceinton()
#endif
-#define FORCEINTON {suppressint = 0; if (intpending) onint();}
+
#define CLEAR_PENDING_INT intpending = 0
#define int_pending() intpending
static void stunalloc (pointer);
static void ungrabstackstr (char *, char *);
static char * growstackstr(void);
+static char * makestrspace(size_t newlen);
static char *sstrdup (const char *);
/*
#define stackblock() stacknxt
#define stackblocksize() stacknleft
#define STARTSTACKSTR(p) p = stackblock(), sstrnleft = stackblocksize()
+
#define STPUTC(c, p) (--sstrnleft >= 0? (*p++ = (c)) : (p = growstackstr(), *p++ = (c)))
#define CHECKSTRSPACE(n, p) { if (sstrnleft < n) p = makestrspace(n); }
-#define USTPUTC(c, p) (--sstrnleft, *p++ = (c))
#define STACKSTRNUL(p) (sstrnleft == 0? (p = growstackstr(), *p = '\0') : (*p = '\0'))
+
+
+#define USTPUTC(c, p) (--sstrnleft, *p++ = (c))
#define STUNPUTC(p) (++sstrnleft, --p)
#define STTOPC(p) p[-1]
#define STADJUST(amount, p) (p += (amount), sstrnleft -= (amount))
#define ckfree(p) free((pointer)(p))
-static char * makestrspace(size_t newlen);
#ifdef DEBUG
#define TRACE(param) trace param
int optoff; /* used by getopts */
};
-struct output {
-#ifdef USE_GLIBC_STDIO
- FILE *stream;
-#endif
- char *nextc;
- int nleft;
- char *buf;
- int bufsize;
- int fd;
- short flags;
-};
-
-#define OUTBUFSIZ BUFSIZ
-#define MEM_OUT -3 /* output to dynamically allocated memory */
-
-
-#ifdef USE_GLIBC_STDIO
-static struct output output = {NULL, NULL, 0, NULL, 0, 1, 0};
-static struct output errout = {NULL, NULL, 0, NULL, 0, 2, 0};
-static struct output memout = {NULL, NULL, 0, NULL, 0, MEM_OUT, 0};
-#else
-static struct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0};
-static struct output errout = {NULL, 0, NULL, 0, 2, 0};
-static struct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0};
-#endif
-static struct output *out1 = &output;
-static struct output *out2 = &errout;
-
-#ifndef USE_GLIBC_STDIO
-static void outcslow (char, struct output *);
-#endif
static void flushall (void);
-static void flushout (struct output *);
-static void freestdout (void);
-static void outfmt (struct output *, const char *, ...)
- __attribute__((__format__(__printf__,2,3)));
+static void out2fmt (const char *, ...)
+ __attribute__((__format__(__printf__,1,2)));
static void out1fmt (const char *, ...)
__attribute__((__format__(__printf__,1,2)));
-static void fmtstr (char *, size_t, const char *, ...)
- __attribute__((__format__(__printf__,3,4)));
-#ifndef USE_GLIBC_STDIO
-static void doformat (struct output *, const char *, va_list);
-#endif
static int xwrite (int, const char *, int);
-#ifdef USE_GLIBC_STDIO
-static void initstreams (void);
-static void openmemout (void);
-static int __closememout (void);
-#endif
-static void outstr(const char *p, struct output *file);
+static void outstr (const char *p, FILE *file) { fputs(p, file); }
+static void out1str(const char *p) { outstr(p, stdout); }
+static void out2str(const char *p) { outstr(p, stderr); }
-#define OUTPUT_ERR 01 /* error occurred on output */
-
-#ifdef USE_GLIBC_STDIO
-#define outc(c, o) putc((c), (o)->stream)
-#define doformat(d, f, a) vfprintf((d)->stream, (f), (a))
-#else
-#define outc(c, file) (--(file)->nleft < 0? outcslow((c), (file)) : (*(file)->nextc = (c), (file)->nextc++))
-#endif
-#define out1c(c) outc((c), out1)
-#define out2c(c) outc((c), out2)
-#define out1str(s) outstr((s), out1)
-#define out2str(s) outstr((s), out2)
-#define outerr(f) ((f)->flags & OUTPUT_ERR)
+#define out2c(c) putc((c), stderr)
/* syntax table used when not in quotes */
static const char basesyntax[257] = {
#define ALIASINUSE 1
#define ALIASDEAD 2
+#define ATABSIZE 39
+
struct alias {
struct alias *next;
char *name;
while ((n = *++argv) != NULL) {
if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
if ((ap = *__lookupalias(n)) == NULL) {
- outfmt(out2, "%s: %s not found\n", "alias", n);
+ out2fmt("%s: %s not found\n", "alias", n);
ret = 1;
} else
printalias(ap);
}
for (i = 0; *argptr; argptr++) {
if (unalias(*argptr)) {
- outfmt(out2, "%s: %s not found\n", "unalias", *argptr);
+ out2fmt("%s: %s not found\n", "unalias", *argptr);
i = 1;
}
}
static int hashcmd (int, char **);
static int jobscmd (int, char **);
static int localcmd (int, char **);
-#ifdef ASH_PWD
+#ifndef BB_PWD
static int pwdcmd (int, char **);
#endif
static int readcmd (int, char **);
{ BUILTIN_REGULAR "bg", bgcmd },
#endif
{ BUILTIN_SPECIAL "break", breakcmd },
- { BUILTIN_SPECIAL "builtin", bltincmd }, /* Do not disable this builtin ever or bad things happen */
+ { BUILTIN_SPECIAL "builtin", bltincmd },
{ BUILTIN_REGULAR "cd", cdcmd },
#ifdef ASH_BBAPPS_AS_BUILTINS
{ BUILTIN_NOSPEC "chdir", cdcmd },
{ BUILTIN_NOSPEC "let", expcmd },
#endif
{ BUILTIN_ASSIGN "local", localcmd },
-#ifdef ASH_PWD
+#ifndef BB_PWD
{ BUILTIN_NOSPEC "pwd", pwdcmd },
#endif
{ BUILTIN_REGULAR "read", readcmd },
}
-#ifdef ASH_PWD
+#ifndef BB_PWD
static int
pwdcmd(argc, argv)
int argc;
#endif
if (msg) {
if (commandname)
- outfmt(&errout, "%s: ", commandname);
- doformat(&errout, msg, ap);
-#if FLUSHERR
- outc('\n', &errout);
-#else
- outcslow('\n', &errout);
-#endif
+ out2fmt("%s: ", commandname);
+ vfprintf(stderr, msg, ap);
+ out2c('\n');
}
flushall();
exraise(cond);
return strerror(e);
}
- fmtstr(buf, sizeof buf, "error %d", e);
+ snprintf(buf, sizeof buf, "error %d", e);
return buf;
}
-#ifndef ASH_BBAPPS_AS_BUILTINS
+#ifdef ASH_OPTIMIZE_FOR_SIZE
static void
__inton() {
if (--suppressint == 0 && intpending) {
onint();
}
}
+static void forceinton (void) {
+ suppressint = 0;
+ if (intpending)
+ onint();
+}
#endif
/* flags in argument to evaltree */
static void evalsubshell (union node *, int);
static void expredir (union node *);
static void evalpipe (union node *);
-#ifdef notyet
-static void evalcommand (union node *, int, struct backcmd *);
-#else
static void evalcommand (union node *, int);
-#endif
static void prehash (union node *);
static void eprintlist (struct strlist *);
(bcmd = find_builtin(n->narg.text)) &&
IS_BUILTIN_SPECIAL(bcmd)
) {
- outfmt(out2, "%s is a special built-in\n", n->narg.text);
+ out2fmt("%s is a special built-in\n", n->narg.text);
exitstatus = 1;
break;
}
checkexit = 1;
break;
case NCMD:
-#ifdef notyet
- evalcommand(n, flags, (struct backcmd *)NULL);
-#else
evalcommand(n, flags);
-#endif
checkexit = 1;
break;
#ifdef DEBUG
default:
out1fmt("Node type = %d\n", n->type);
-#ifndef USE_GLIBC_STDIO
- flushout(out1);
-#endif
break;
#endif
}
}
-
/*
* Compute the names of the files in a redirection list.
*/
exitstatus = 0;
goto out;
}
-#ifdef notyet
- /*
- * For now we disable executing builtins in the same
- * context as the shell, because we are not keeping
- * enough state to recover from changes that are
- * supposed only to affect subshells. eg. echo "`cd /`"
- */
- if (n->type == NCMD) {
- exitstatus = oexitstatus;
- evalcommand(n, EV_BACKCMD, result);
- } else
-#endif
- {
- exitstatus = 0;
- if (pipe(pip) < 0)
- error("Pipe call failed");
- jp = makejob(n, 1);
- if (forkshell(jp, n, FORK_NOJOB) == 0) {
- FORCEINTON;
- close(pip[0]);
- if (pip[1] != 1) {
- close(1);
- dup_as_newfd(pip[1], 1);
- close(pip[1]);
- }
- eflag = 0;
- evaltree(n, EV_EXIT);
+ exitstatus = 0;
+ if (pipe(pip) < 0)
+ error("Pipe call failed");
+ jp = makejob(n, 1);
+ if (forkshell(jp, n, FORK_NOJOB) == 0) {
+ FORCEINTON;
+ close(pip[0]);
+ if (pip[1] != 1) {
+ close(1);
+ dup_as_newfd(pip[1], 1);
+ close(pip[1]);
}
- close(pip[1]);
- result->fd = pip[0];
- result->jp = jp;
+ eflag = 0;
+ evaltree(n, EV_EXIT);
}
+ close(pip[1]);
+ result->fd = pip[0];
+ result->jp = jp;
out:
popstackmark(&smark);
TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
}
static void
-#ifdef notyet
-evalcommand(cmd, flags, backcmd)
- union node *cmd;
- int flags;
- struct backcmd *backcmd;
-#else
-evalcommand(cmd, flags)
- union node *cmd;
- int flags;
-#endif
+evalcommand(union node *cmd, int flags)
{
struct stackmark smark;
union node *argp;
char **envp;
struct strlist *sp;
int mode;
-#ifdef notyet
- int pip[2];
-#endif
struct cmdentry cmdentry;
struct job *jp;
char *volatile savecmdname;
/* Print the command if xflag is set. */
if (xflag) {
-#ifdef FLUSHERR
- outc('+', &errout);
-#else
- outcslow('+', &errout);
-#endif
+ out2c('+');
eprintlist(varlist.list);
eprintlist(arglist.list);
-#ifdef FLUSHERR
- outc('\n', &errout);
- flushout(&errout);
-#else
- outcslow('\n', &errout);
-#endif
+ out2c('\n');
}
/* Now locate the command. */
find_command(argv[0], &cmdentry, findflag, path);
if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */
exitstatus = 127;
-#ifdef FLUSHERR
- flushout(&errout);
-#endif
goto out;
}
/* implement bltin and command here */
if (--argc == 0)
goto found;
if (!(bcmd = find_builtin(*argv))) {
- outfmt(&errout, "%s: not found\n", *argv);
+ out2fmt("%s: not found\n", *argv);
exitstatus = 127;
-#ifdef FLUSHERR
- flushout(&errout);
-#endif
goto out;
}
cmdentry.u.cmd = bcmd;
/* Fork off a child process if necessary. */
if (cmd->ncmd.backgnd
|| (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0)
-#ifdef notyet
- || ((flags & EV_BACKCMD) != 0
- && (cmdentry.cmdtype != CMDBUILTIN
- || cmdentry.u.bcmd == DOTCMD
- || cmdentry.u.bcmd == EVALCMD))
-#endif
) {
jp = makejob(cmd, 1);
mode = cmd->ncmd.backgnd;
-#ifdef notyet
- if (flags & EV_BACKCMD) {
- mode = FORK_NOJOB;
- if (pipe(pip) < 0)
- error("Pipe call failed");
- }
-#endif
if (forkshell(jp, cmd, mode) != 0)
goto parent; /* at end of routine */
-#ifdef notyet
- if (flags & EV_BACKCMD) {
- FORCEINTON;
- close(pip[0]);
- if (pip[1] != 1) {
- close(1);
- dup_as_newfd(pip[1], 1);
- close(pip[1]);
- }
- }
-#endif
flags |= EV_EXIT;
}
trputs("builtin command: "); trargs(argv);
#endif
mode = (cmdentry.u.cmd == EXECCMD)? 0 : REDIR_PUSH;
-#ifdef notyet
- if (flags == EV_BACKCMD) {
-#ifdef USE_GLIBC_STDIO
- openmemout();
-#else
- memout.nleft = 0;
- memout.nextc = memout.buf;
- memout.bufsize = 64;
-#endif
- mode |= REDIR_BACKQ;
- }
-#endif
redirect(cmd->ncmd.redirect, mode);
savecmdname = commandname;
if (IS_BUILTIN_SPECIAL(firstbltin)) {
exitstatus = (*cmdentry.u.cmd->builtinfunc)(argc, argv);
flushall();
cmddone:
- exitstatus |= outerr(out1);
- out1 = &output;
- out2 = &errout;
- freestdout();
cmdenviron = NULL;
if (e != EXSHELLPROC) {
commandname = savecmdname;
}
if (cmdentry.u.cmd != EXECCMD)
popredir();
-#ifdef notyet
- if (flags == EV_BACKCMD) {
- INTOFF;
-#ifdef USE_GLIBC_STDIO
- if (__closememout())
- error("__closememout() failed: %m");
-#endif
- backcmd->buf = memout.buf;
-#ifdef USE_GLIBC_STDIO
- backcmd->nleft = memout.bufsize;
-#else
- backcmd->nleft = memout.nextc - memout.buf;
-#endif
- memout.buf = NULL;
- INTON;
- }
-#endif
} else {
#ifdef DEBUG
trputs("normal command: "); trargs(argv);
INTOFF;
exitstatus = waitforjob(jp);
INTON;
-#ifdef notyet
- } else if (mode == 2) {
- backcmd->fd = pip[0];
- close(pip[1]);
- backcmd->jp = jp;
-#endif
}
out:
eprintlist(struct strlist *sp)
{
for (; sp; sp = sp->next) {
- outfmt(&errout, " %s",sp->text);
+ out2fmt(" %s",sp->text);
}
}
/*
* Nul characters in the input are silently discarded.
*/
-#ifdef ASH_BBAPPS_AS_BUILTINS
+#ifndef ASH_OPTIMIZE_FOR_SIZE
#define pgetc_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
static int
pgetc(void)
{
int e;
+#ifdef BB_FEATURE_SH_STANDALONE_SHELL
+ char *name = cmd;
+ char** argv_l=argv;
+ int argc_l;
+#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN
+ name = get_last_path_component(name);
+#endif
+ argv_l=envp;
+ for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++)
+ putenv(*argv_l);
+ argv_l=argv;
+ for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++);
+ optind = 1;
+ run_applet_by_name(name, argc_l, argv);
+#endif
execve(cmd, argv, envp);
e = errno;
if (e == ENOEXEC) {
if (cmdp && updatetbl)
delete_cmd_entry();
if (act & DO_ERR)
- outfmt(out2, "%s: %s\n", name, errmsg(e, E_EXEC));
+ out2fmt("%s: %s\n", name, errmsg(e, E_EXEC));
entry->cmdtype = CMDUNKNOWN;
return;
}
out:
- out1c('\n');
+ putchar('\n');
return 0;
}
#endif
verbose_verify_only = 1;
break;
default:
- outfmt(out2,
+ out2fmt(
"command: nextopt returned character code 0%o\n", c);
return EX_SOFTWARE;
}
if (default_path + verify_only + verbose_verify_only > 1 ||
!*argptr) {
- outfmt(out2,
+ out2fmt(
"command [-p] command [arg ...]\n");
- outfmt(out2,
+ out2fmt(
"command {-v|-V} command\n");
return EX_USAGE;
}
if (quotes)
rmescapes(p+2);
result = arith(p+2);
- fmtstr(p, 12, "%d", result);
+ snprintf(p, 12, "%d", result);
while (*p++)
;
case VSQUESTION:
if (*p != CTLENDVAR) {
- outfmt(&errout, snlfmt, startp);
+ out2fmt(snlfmt, startp);
error((char *)NULL);
}
error("%.*s: parameter %snot set", p - str - 1,
basepf.nextc = basepf.buf = basebuf;
}
- /* from output.c: */
- {
-#ifdef USE_GLIBC_STDIO
- initstreams();
-#endif
- }
-
/* from var.c: */
{
char **envp;
}
}
- fmtstr(ppid, sizeof(ppid), "%d", (int) getppid());
+ snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
setvar("PPID", ppid, 0);
}
}
popredir();
}
- /* from output.c: */
- {
- out1 = &output;
- out2 = &errout;
-#ifdef USE_GLIBC_STDIO
- if (memout.stream != NULL)
- __closememout();
-#endif
- if (memout.buf != NULL) {
- ckfree(memout.buf);
- memout.buf = NULL;
- }
- }
}
}
if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
return PEOF;
- flushout(&output);
-#ifdef FLUSHERR
- flushout(&errout);
-#endif
+ flushall();
again:
if (parselleft <= 0) {
if (vflag) {
out2str(parsenextc);
-#ifdef FLUSHERR
- flushout(out2);
-#endif
}
*q = savec;
return fd0_redirected != 0;
}
-/*
- * We also keep track of where fileno2 goes.
- */
-static int fileno2 = 2;
-
static int openredirect (union node *);
static void dupredirect (union node *, int, char[10 ]);
static int openhere (union node *);
if (enable) {
do { /* while we are in the background */
#ifdef OLD_TTY_DRIVER
- if (ioctl(fileno2, TIOCGPGRP, (char *)&initialpgrp) < 0) {
+ if (ioctl(2, TIOCGPGRP, (char *)&initialpgrp) < 0) {
#else
- initialpgrp = tcgetpgrp(fileno2);
+ initialpgrp = tcgetpgrp(2);
if (initialpgrp < 0) {
#endif
out2str("sh: can't access tty; job cenabletrol turned off\n");
}
} while (0);
#ifdef OLD_TTY_DRIVER
- if (ioctl(fileno2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) {
+ if (ioctl(2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) {
out2str("sh: need new tty driver to run job cenabletrol; job cenabletrol turned off\n");
mflag = 0;
return;
setsignal(SIGTTIN);
setpgid(0, rootpid);
#ifdef OLD_TTY_DRIVER
- ioctl(fileno2, TIOCSPGRP, (char *)&rootpid);
+ ioctl(2, TIOCSPGRP, (char *)&rootpid);
#else
- tcsetpgrp(fileno2, rootpid);
+ tcsetpgrp(2, rootpid);
#endif
} else { /* turning job cenabletrol off */
setpgid(0, initialpgrp);
#ifdef OLD_TTY_DRIVER
- ioctl(fileno2, TIOCSPGRP, (char *)&initialpgrp);
+ ioctl(2, TIOCSPGRP, (char *)&initialpgrp);
#else
- tcsetpgrp(fileno2, initialpgrp);
+ tcsetpgrp(2, initialpgrp);
#endif
setsignal(SIGTSTP);
setsignal(SIGTTOU);
error("job not created under job control");
pgrp = jp->ps[0].pid;
#ifdef OLD_TTY_DRIVER
- ioctl(fileno2, TIOCSPGRP, (char *)&pgrp);
+ ioctl(2, TIOCSPGRP, (char *)&pgrp);
#else
- tcsetpgrp(fileno2, pgrp);
+ tcsetpgrp(2, pgrp);
#endif
restartjob(jp);
INTOFF;
procno = jp->nprocs;
for (ps = jp->ps ; ; ps++) { /* for each process */
if (ps == jp->ps)
- fmtstr(s, 64, "[%d] %ld ", jobno,
+ snprintf(s, 64, "[%d] %ld ", jobno,
(long)ps->pid);
else
- fmtstr(s, 64, " %ld ",
+ snprintf(s, 64, " %ld ",
(long)ps->pid);
out1str(s);
col = strlen(s);
if (ps->status == -1) {
/* don't print anything */
} else if (WIFEXITED(ps->status)) {
- fmtstr(s, 64, "Exit %d",
+ snprintf(s, 64, "Exit %d",
WEXITSTATUS(ps->status));
} else {
#ifdef JOBS
if ((i & 0x7F) < NSIG && sys_siglist[i & 0x7F])
strcpy(s, sys_siglist[i & 0x7F]);
else
- fmtstr(s, 64, "Signal %d", i & 0x7F);
+ snprintf(s, 64, "Signal %d", i & 0x7F);
if (WCOREDUMP(ps->status))
strcat(s, " (core dumped)");
}
if (mode == FORK_FG) {
/*** this causes superfluous TIOCSPGRPS ***/
#ifdef OLD_TTY_DRIVER
- if (ioctl(fileno2, TIOCSPGRP, (char *)&pgrp) < 0)
+ if (ioctl(2, TIOCSPGRP, (char *)&pgrp) < 0)
error("TIOCSPGRP failed, errno=%d", errno);
#else
- if (tcsetpgrp(fileno2, pgrp) < 0)
+ if (tcsetpgrp(2, pgrp) < 0)
error("tcsetpgrp failed, errno=%d", errno);
#endif
}
#ifdef JOBS
if (jp->jobctl) {
#ifdef OLD_TTY_DRIVER
- if (ioctl(fileno2, TIOCSPGRP, (char *)&mypgrp) < 0)
+ if (ioctl(2, TIOCSPGRP, (char *)&mypgrp) < 0)
error("TIOCSPGRP failed, errno=%d\n", errno);
#else
- if (tcsetpgrp(fileno2, mypgrp) < 0)
+ if (tcsetpgrp(2, mypgrp) < 0)
error("tcsetpgrp failed, errno=%d\n", errno);
#endif
}
if (sig != 0 && sig != SIGINT && sig != SIGPIPE) {
if (thisjob != job)
- outfmt(out2, "%d: ", pid);
+ out2fmt("%d: ", pid);
#ifdef JOBS
if (sig == SIGTSTP && rootshell && iflag)
- outfmt(out2, "%%%ld ",
+ out2fmt("%%%ld ",
(long)(job - jobtab + 1));
#endif
if (sig < NSIG && sys_siglist[sig])
out2str(sys_siglist[sig]);
else
- outfmt(out2, "Signal %d", sig);
+ out2fmt("Signal %d", sig);
if (core)
out2str(" - core dumped");
out2c('\n');
-#ifdef FLUSHERR
- flushout(&errout);
-#endif
} else {
TRACE(("Not printing status: status=%d, sig=%d\n",
status, sig));
if (stat(p, &statb) < 0)
statb.st_size = 0;
if (statb.st_size > mailtime[i] && ! silent) {
- outfmt(
- &errout, snlfmt,
- pathopt? pathopt : "you have mail"
- );
+ out2fmt(snlfmt,
+ pathopt? pathopt : "you have mail");
}
mailtime[i] = statb.st_size;
}
reset();
if (exception == EXINT) {
out2c('\n');
-#ifdef FLUSHERR
- flushout(out2);
-#endif
}
popstackmark(&smark);
FORCEINTON; /* enable interrupts */
inter++;
showjobs(1);
chkmail(0);
- flushout(&output);
+ flushall();
}
n = parsecmd(inter);
/* showtree(n); DEBUG */
err |= setvarsafe("OPTARG", s, 0);
}
else {
- outfmt(&errout, "Illegal option -%c\n", c);
+ out2fmt("Illegal option -%c\n", c);
(void) unsetvar("OPTARG");
}
c = '?';
c = ':';
}
else {
- outfmt(&errout, "No arg for -%c option\n", c);
+ out2fmt("No arg for -%c option\n", c);
(void) unsetvar("OPTARG");
c = '?';
}
p = NULL;
out:
*optoff = p ? p - *(optnext - 1) : -1;
- fmtstr(s, sizeof(s), "%d", *myoptind);
+ snprintf(s, sizeof(s), "%d", *myoptind);
err |= setvarsafe("OPTIND", s, VNOFUNC);
s[0] = c;
s[1] = '\0';
return c;
}
-
-/*
- * Shell output routines. We use our own output routines because:
- * When a builtin command is interrupted we have to discard
- * any pending output.
- * When a builtin command appears in back quotes, we want to
- * save the output of the command in a region obtained
- * via malloc, rather than doing a fork and reading the
- * output of the command via a pipe.
- * Our output routines may be smaller than the stdio routines.
- */
-
-
-
-#ifndef USE_GLIBC_STDIO
-static void __outstr (const char *, size_t, struct output*);
-#endif
-
-
-#ifndef USE_GLIBC_STDIO
-static void
-__outstr(const char *p, size_t len, struct output *dest) {
- if (!dest->bufsize) {
- dest->nleft = 0;
- } else if (dest->buf == NULL) {
- if (len > dest->bufsize && dest->fd == MEM_OUT) {
- dest->bufsize = len;
- }
- INTOFF;
- dest->buf = ckmalloc(dest->bufsize);
- dest->nextc = dest->buf;
- dest->nleft = dest->bufsize;
- INTON;
- } else if (dest->fd == MEM_OUT) {
- int offset;
-
- offset = dest->bufsize;
- INTOFF;
- if (dest->bufsize >= len) {
- dest->bufsize <<= 1;
- } else {
- dest->bufsize += len;
- }
- dest->buf = ckrealloc(dest->buf, dest->bufsize);
- dest->nleft = dest->bufsize - offset;
- dest->nextc = dest->buf + offset;
- INTON;
- } else {
- flushout(dest);
- }
-
- if (len < dest->nleft) {
- dest->nleft -= len;
- memcpy(dest->nextc, p, len);
- dest->nextc += len;
- return;
- }
-
- if (xwrite(dest->fd, p, len) < len)
- dest->flags |= OUTPUT_ERR;
-}
-#endif
-
-
-static void
-outstr(const char *p, struct output *file)
-{
-#ifdef USE_GLIBC_STDIO
- INTOFF;
- fputs(p, file->stream);
- INTON;
-#else
- size_t len;
-
- if (!*p) {
- return;
- }
- len = strlen(p);
- if ((file->nleft -= len) > 0) {
- memcpy(file->nextc, p, len);
- file->nextc += len;
- return;
- }
- __outstr(p, len, file);
-#endif
-}
-
-
-#ifndef USE_GLIBC_STDIO
-
-
-static void
-outcslow(c, dest)
- char c;
- struct output *dest;
- {
- __outstr(&c, 1, dest);
-}
-#endif
-
-
static void
flushall() {
- flushout(&output);
-#ifdef FLUSHERR
- flushout(&errout);
-#endif
-}
-
-
-static void
-flushout(dest)
- struct output *dest;
- {
-#ifdef USE_GLIBC_STDIO
INTOFF;
- fflush(dest->stream);
+ fflush(stdout);
INTON;
-#else
- size_t len;
-
- len = dest->nextc - dest->buf;
- if (dest->buf == NULL || !len || dest->fd < 0)
- return;
- dest->nextc = dest->buf;
- dest->nleft = dest->bufsize;
- if (xwrite(dest->fd, dest->buf, len) < len)
- dest->flags |= OUTPUT_ERR;
-#endif
-}
-
-
-static void
-freestdout() {
- if (output.buf) {
- INTOFF;
- ckfree(output.buf);
- output.buf = NULL;
- output.nleft = 0;
- INTON;
- }
- output.flags = 0;
}
static void
-#ifdef __STDC__
-outfmt(struct output *file, const char *fmt, ...)
-#else
-static void
-outfmt(va_alist)
- va_dcl
-#endif
+out2fmt(const char *fmt, ...)
{
va_list ap;
-#ifndef __STDC__
- struct output *file;
- const char *fmt;
-
- va_start(ap);
- file = va_arg(ap, struct output *);
- fmt = va_arg(ap, const char *);
-#else
va_start(ap, fmt);
-#endif
- doformat(file, fmt, ap);
+ vfprintf(stderr, fmt, ap);
va_end(ap);
}
static void
-#ifdef __STDC__
out1fmt(const char *fmt, ...)
-#else
-out1fmt(va_alist)
- va_dcl
-#endif
{
va_list ap;
-#ifndef __STDC__
- const char *fmt;
-
- va_start(ap);
- fmt = va_arg(ap, const char *);
-#else
va_start(ap, fmt);
-#endif
- doformat(out1, fmt, ap);
+ vfprintf(stdout, fmt, ap);
va_end(ap);
}
-static void
-#ifdef __STDC__
-fmtstr(char *outbuf, size_t length, const char *fmt, ...)
-#else
-fmtstr(va_alist)
- va_dcl
-#endif
-{
- va_list ap;
-#ifndef __STDC__
- char *outbuf;
- size_t length;
- const char *fmt;
-
- va_start(ap);
- outbuf = va_arg(ap, char *);
- length = va_arg(ap, size_t);
- fmt = va_arg(ap, const char *);
-#else
- va_start(ap, fmt);
-#endif
- INTOFF;
- vsnprintf(outbuf, length, fmt, ap);
- INTON;
-}
-
-#ifndef USE_GLIBC_STDIO
-
-static void
-doformat(struct output *dest, const char *f, va_list ap)
-{
- char *pm;
- int size = BUFSIZ;
-
- while(size) {
- int nchars;
-
- pm = xmalloc(size);
- nchars = vsnprintf(pm, size, f, ap);
- if(nchars > -1) {
- outstr(pm, dest);
- size = 0;
- }
- else
- size *= 2;
- free(pm);
- }
-}
-#endif
-
-
-
/*
* Version of write which resumes after a signal is caught.
*/
}
-#ifdef USE_GLIBC_STDIO
-static void initstreams() {
- output.stream = stdout;
- errout.stream = stderr;
-}
-
-
-static void
-openmemout() {
- INTOFF;
- memout.stream = open_memstream(&memout.buf, &memout.bufsize);
- INTON;
-}
-
-
-static int
-__closememout() {
- int error;
- error = fclose(memout.stream);
- memout.stream = NULL;
- return error;
-}
-#endif
/*
* Shell command parser.
*/
c = pgetc_macro();
switch (c) {
case ' ': case '\t':
+#ifdef ASH_ALIAS
case PEOA:
+#endif
continue;
case '#':
while ((c = pgetc()) != '\n' && c != PEOF);
default:
if (varnest == 0)
goto endword; /* exit outer loop */
- if (c != PEOA) {
+#ifdef ASH_ALIAS
+ if (c != PEOA)
+#endif
USTPUTC(c, out);
- }
+
}
c = pgetc_macro();
}
char msg[64];
if (token >= 0) {
- fmtstr(msg, 64, "%s unexpected (expecting %s)",
+ snprintf(msg, 64, "%s unexpected (expecting %s)",
tokname[lasttoken], tokname[token]);
} else {
- fmtstr(msg, 64, "%s unexpected", tokname[lasttoken]);
+ snprintf(msg, 64, "%s unexpected", tokname[lasttoken]);
}
synerror(msg);
/* NOTREACHED */
synerror(const char *msg)
{
if (commandname)
- outfmt(&errout, "%s: %d: ", commandname, startlinno);
- outfmt(&errout, "Syntax error: %s\n", msg);
+ out2fmt("%s: %d: ", commandname, startlinno);
+ out2fmt("Syntax error: %s\n", msg);
error((char *)NULL);
/* NOTREACHED */
}
* called by editline -- any expansions to the prompt
* should be added here.
*/
-static const char *
+static inline const char *
getprompt(void *unused)
{
switch (whichprompt) {
* old file descriptors are stashed away so that the redirection can be
* undone by calling popredir. If the REDIR_BACKQ flag is set, then the
* standard output, and the standard error if it becomes a duplicate of
- * stdout, is saved in memory.
+ * stdout.
*/
static void
INTOFF;
newfd = openredirect(n);
- if (((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) ||
- (fd == fileno2)) {
+ if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
if (newfd == fd) {
try++;
} else if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
if (flags & REDIR_PUSH) {
sv->renamed[fd] = i;
}
- if (fd == fileno2) {
- fileno2 = i;
- }
}
} else if (fd != newfd) {
close(fd);
dupredirect(n, newfd, memory);
INTON;
}
- if (memory[1])
- out1 = &memout;
- if (memory[2])
- out2 = &memout;
}
dup_as_newfd(rp->renamed[i], i);
close(rp->renamed[i]);
}
- if (rp->renamed[i] == fileno2) {
- fileno2 = i;
- }
}
}
redirlist = rp->next;
for (i = 0 ; i < 10 ; i++) {
if (rp->renamed[i] >= 0) {
close(rp->renamed[i]);
- if (rp->renamed[i] == fileno2) {
- fileno2 = -1;
- }
}
rp->renamed[i] = EMPTY;
}
}
- if (fileno2 != 2 && fileno2 >= 0) {
- close(fileno2);
- fileno2 = -1;
- }
}
/*
* Copyright (c) 1999 Herbert Xu <herbert@debian.org>
* This file contains code for the times builtin.
- * $Id: ash.c,v 1.5 2001/07/05 05:24:12 andersen Exp $
+ * $Id: ash.c,v 1.6 2001/07/06 04:26:23 andersen Exp $
*/
static int timescmd (int argc, char **argv)
{