//config: you to run the specified command or builtin,
//config: even when there is a function with the same name.
//config:
+//config:config ASH_EMBEDDED_SCRIPTS
+//config: bool "Embed scripts in the binary"
+//config: default y
+//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
+//config: help
+//config: Allow scripts to be compressed and embedded in the busybox
+//config: binary. The scripts should be placed in the 'embed' directory
+//config: at build time. Like applets, scripts can be run as
+//config: 'busybox SCRIPT ...' or by linking their name to the binary.
+//config:
+//config: This also allows applets to be implemented as scripts: place
+//config: the script in 'applets_sh' and a stub C file containing
+//config: configuration in the appropriate subsystem directory.
+//config:
//config:endif # ash options
//applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP))
#include <sys/times.h>
#include <sys/utsname.h> /* for setting $HOSTNAME */
#include "busybox.h" /* for applet_names */
+#if ENABLE_ASH_EMBEDDED_SCRIPTS
+# include "embedded_scripts.h"
+#else
+# define NUM_SCRIPTS 0
+#endif
/* So far, all bash compat is controlled by one config option */
/* Separate defines document which part of code implements what */
}
INT_OFF;
- nameeq = ckmalloc(namelen + vallen + 2);
+ nameeq = ckzalloc(namelen + vallen + 2);
p = mempcpy(nameeq, name, namelen);
if (val) {
*p++ = '=';
- p = mempcpy(p, val, vallen);
+ memcpy(p, val, vallen);
}
- *p = '\0';
vp = setvareq(nameeq, flags | VNOSAVE);
INT_ON;
if (quotes & QUOTES_ESC) {
int n = SIT(c, syntax);
if (n == CCTL
- || (((quotes & EXP_FULL) || syntax != BASESYNTAX)
- && n == CBACK
- )
+ || (syntax != BASESYNTAX && n == CBACK)
) {
USTPUTC(CTLESC, q);
}
}
}
} else {
- if (*p == '\\')
+ if (*p == '\\' && p[1])
esc++;
if (p[esc] == '/') {
if (metaflag)
return;
p = name;
do {
- if (*p == '\\')
+ if (*p == '\\' && p[1])
p++;
*enddir++ = *p;
} while (*p++);
if (name < start) {
p = name;
do {
- if (*p == '\\')
+ if (*p == '\\' && p[1])
p++;
*enddir++ = *p++;
} while (p < start);
#else
execve(cmd, argv, envp);
#endif
+
if (cmd != bb_busybox_exec_path && errno == ENOEXEC) {
/* Run "cmd" as a shell script:
* http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
/* Map to POSIX errors */
switch (e) {
- case EACCES:
+ default:
exerrno = 126;
break;
+ case ELOOP:
+ case ENAMETOOLONG:
case ENOENT:
+ case ENOTDIR:
exerrno = 127;
break;
- default:
- exerrno = 2;
- break;
}
exitstatus = exerrno;
TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
/*
* Execute a simple command.
*/
+static void unwindfiles(struct parsefile *stop);
static int
isassignment(const char *p)
{
"\0\0", bltincmd /* why three NULs? */
};
struct localvar_list *localvar_stop;
+ struct parsefile *file_stop;
struct redirtab *redir_stop;
struct stackmark smark;
union node *argp;
TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
setstackmark(&smark);
localvar_stop = pushlocalvars();
+ file_stop = g_parsefile;
back_exitstatus = 0;
cmdentry.cmdtype = CMDBUILTIN;
if (cmd->ncmd.redirect)
popredir(/*drop:*/ cmd_is_exec);
unwindredir(redir_stop);
+ unwindfiles(file_stop);
unwindlocalvars(localvar_stop);
if (lastarg) {
/* dsl: I think this is intended to be used to support
INT_ON;
}
+static void
+unwindfiles(struct parsefile *stop)
+{
+ while (g_parsefile != stop)
+ popfile();
+}
+
/*
* Return to top level.
*/
static void
popallfiles(void)
{
- while (g_parsefile != &basepf)
- popfile();
+ unwindfiles(&basepf);
}
/*
STPUTC(c, out);
c = pgetc_eatbnl();
} while (isdigit(c));
- } else {
+ } else if (c != '}') {
/* $[{[#]]<specialchar>[}] */
int cc = c;
}
USTPUTC(cc, out);
- }
+ } else
+ goto badsub;
if (c != '}' && subtype == VSLENGTH) {
/* ${#VAR didn't end with } */
heredoclist = NULL;
while (here) {
+ tokpushback = 0;
setprompt_if(needprompt, 2);
readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX,
here->eofmark, here->striptabs);
xargv = argv;
login_sh = xargv[0] && xargv[0][0] == '-';
+#if NUM_SCRIPTS > 0
+ if (minusc)
+ goto setarg0;
+#endif
arg0 = xargv[0];
/* if (xargv[0]) - mmm, this is always true! */
xargv++;
+ argptr = xargv;
for (i = 0; i < NOPTS; i++)
optlist[i] = 2;
- argptr = xargv;
if (options(/*cmdline:*/ 1, &login_sh)) {
/* it already printed err message */
raise_exception(EXERROR);
* is used to figure out how far we had gotten.
*/
int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+#if NUM_SCRIPTS > 0
+int ash_main(int argc, char **argv)
+#else
int ash_main(int argc UNUSED_PARAM, char **argv)
+#endif
+/* note: 'argc' is used only if embedded scripts are enabled */
{
volatile smallint state;
struct jmploc jmploc;
init();
setstackmark(&smark);
+
+#if NUM_SCRIPTS > 0
+ if (argc < 0)
+ /* Non-NULL minusc tells procargs that an embedded script is being run */
+ minusc = get_script_content(-argc - 1);
+#endif
login_sh = procargs(argv);
#if DEBUG
TRACE(("Shell args: "));