return &blanks[sizeof(blanks) - i - 1];
}
#define debug_printf_clean(...) fprintf(stderr, __VA_ARGS__)
+#define DEBUG_CLEAN 1
#endif
glob_t glob_result; /* result of parameter globbing */
int is_stopped; /* is the program currently running? */
struct pipe *family; /* pointer back to the child's parent pipe */
- int sp; /* number of SPECIAL_VAR_SYMBOL */
+ //sp counting seems to be broken... so commented out, grep for '//sp:'
+ //sp: int sp; /* number of SPECIAL_VAR_SYMBOL */
int type;
};
-// sp counting seems to be broken...
/* argv vector may contain variable references (^Cvar^C, ^C0^C etc)
* and on execution these are substituted with their values.
* Substitution can make _several_ words out of one argv[n]!
static int b_addchr(o_string *o, int ch);
static void b_reset(o_string *o);
static int b_addqchr(o_string *o, int ch, int quote);
-//static int b_adduint(o_string *o, unsigned i);
/* in_str manipulations: */
static int static_get(struct in_str *i);
static int static_peek(struct in_str *i);
static void mark_closed(int fd);
static void close_all(void);
/* "run" the final data structures: */
-//TODO: remove indent argument from non-debug build!
+#if !defined(DEBUG_CLEAN)
+#define free_pipe_list(head, indent) free_pipe_list(head)
+#define free_pipe(pi, indent) free_pipe(pi)
+#endif
static int free_pipe_list(struct pipe *head, int indent);
static int free_pipe(struct pipe *pi, int indent);
/* really run the final data structures: */
static const char *lookup_param(const char *src);
static char *make_string(char **inp);
static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input);
-//static int parse_string(o_string *dest, struct p_context *ctx, const char *src);
static int parse_stream(o_string *dest, struct p_context *ctx, struct in_str *input0, const char *end_trigger);
/* setup: */
static int parse_stream_outer(struct in_str *inp, int parse_flag);
return EXIT_SUCCESS;
}
- name = strdup(name);
-
- if (name) {
+ name = xstrdup(name);
+ {
const char *value = strchr(name, '=');
if (!value) {
if (value) {
size_t ln = strlen(name);
- tmp = realloc(name, ln+strlen(value)+2);
- if (tmp == NULL)
- res = -1;
- else {
- sprintf(tmp+ln, "=%s", value);
- name = tmp;
- }
+ tmp = xrealloc(name, ln+strlen(value)+2);
+ sprintf(tmp+ln, "=%s", value);
+ name = tmp;
} else {
/* bash does not return an error when trying to export
* an undefined variable. Do likewise. */
/* It would be easy to drop a more restrictive policy
* in here, such as setting a maximum string length */
if (o->length + len > o->maxlen) {
- char *old_data = o->data;
/* assert(data == NULL || o->maxlen != 0); */
o->maxlen += (2*len > B_CHUNK ? 2*len : B_CHUNK);
- o->data = realloc(o->data, 1 + o->maxlen);
- if (o->data == NULL) {
- free(old_data);
- }
+ o->data = xrealloc(o->data, 1 + o->maxlen);
}
return o->data == NULL;
}
return b_addchr(o, ch);
}
-//static int b_adduint(o_string *o, unsigned i)
-//{
-// int r;
-// char buf[sizeof(unsigned)*3 + 1];
-// char *p = buf;
-// *(utoa_to_buf(i, buf, sizeof(buf))) = '\0';
-// /* no escape checking necessary */
-// do r = b_addchr(o, *p++); while (r == 0 && *p);
-// return r;
-//}
-//
static int static_get(struct in_str *i)
{
int ch = *i->p++;
const struct built_in_command *x;
for (i = 0; is_assignment(argv[i]); i++) {
- debug_printf("pid %d environment modification: %s\n",
+ debug_printf_exec("pid %d environment modification: %s\n",
getpid(), argv[i]);
// FIXME: vfork case??
p = insert_var_value(argv[i]);
}
}
- /* Check if the command matches any busybox internal commands
- * ("applets") here.
- * FIXME: This feature is not 100% safe, since
- * BusyBox is not fully reentrant, so we have no guarantee the things
- * from the .bss are still zeroed, or that things from .data are still
- * at their defaults. We could exec ourself from /proc/self/exe, but I
- * really dislike relying on /proc for things. We could exec ourself
- * from global_argv[0], but if we are in a chroot, we may not be able
- * to find ourself... */
+ /* Check if the command matches any busybox applets */
#if ENABLE_FEATURE_SH_STANDALONE
- debug_printf("running applet %s\n", argv[0]);
-// FIXME: check NOEXEC bit, and EXEC if not set!
- run_applet_and_exit(argv[0], argv);
-// is it ok that run_applet_and_exit() does exit(), not _exit()?
-// NB: IIRC on NOMMU we are after _vfork_, not fork!
+ if (strchr(argv[0], '/') == NULL) {
+ const struct bb_applet *a = find_applet_by_name(argv[0]);
+ if (a) {
+ if (a->noexec) {
+ current_applet = a;
+ debug_printf_exec("running applet '%s'\n", argv[0]);
+// is it ok that run_current_applet_and_exit() does exit(), not _exit()?
+ run_current_applet_and_exit(argv);
+ }
+ /* re-exec ourselves with the new arguments */
+ debug_printf_exec("re-execing applet '%s'\n", argv[0]);
+ execvp(CONFIG_BUSYBOX_EXEC_PATH, argv);
+ /* If they called chroot or otherwise made the binary no longer
+ * executable, fall through */
+ }
+ }
#endif
- debug_printf("exec of %s\n", argv[0]);
+
+ debug_printf_exec("execing '%s'\n", argv[0]);
execvp(argv[0], argv);
bb_perror_msg("cannot exec '%s'", argv[0]);
_exit(1);
// TODO: do we really need to have so many fields which are just dead weight
// at execution stage?
thejob->progs[i].pid = pi->progs[i].pid;
- //rest:
- //char **argv; /* program name and arguments */
- //struct pipe *group; /* if non-NULL, first in group or subshell */
- //int subshell; /* flag, non-zero if group must be forked */
- //struct redir_struct *redirects; /* I/O redirections */
- //glob_t glob_result; /* result of parameter globbing */
- //int is_stopped; /* is the program currently running? */
- //struct pipe *family; /* pointer back to the child's parent pipe */
- //int sp; /* number of SPECIAL_VAR_SYMBOL */
- //int type;
+ /* all other fields are not used and stay zero */
}
thejob->next = NULL;
thejob->cmdtext = xstrdup(get_cmdtext(pi));
if (childpid && errno != ECHILD)
bb_perror_msg("waitpid");
-
- /* move the shell to the foreground */
- //if (interactive_fd && tcsetpgrp(interactive_fd, getpgid(0)))
- // bb_perror_msg("tcsetpgrp-2");
return rcode;
}
}
if (single_fg && child->argv != NULL) {
- char **argv_expanded, **free_me;
+ char **argv_expanded;
char **argv = child->argv;
for (i = 0; is_assignment(argv[i]); i++)
for (i = 0; is_assignment(argv[i]); i++) {
p = insert_var_value(argv[i]);
if (p != argv[i]) {
- child->sp--;
+ //sp: child->sp--;
putenv(p);
} else {
putenv(xstrdup(p));
}
}
- free_me = NULL;
for (x = bltins; x->cmd; x++) {
if (strcmp(argv[i], x->cmd) == 0) {
if (x->function == builtin_exec && argv[i+1] == NULL) {
* This is perfect for work that comes after exec().
* Is it really safe for inline use? Experimentally,
* things seem to work with glibc. */
-// TODO: fflush(NULL)?
setup_redirects(child, squirrel);
debug_printf_exec(": builtin '%s' '%s'...\n", x->cmd, argv[i+1]);
- argv_expanded = argv + i;
- if (child->sp) /* btw we can do it unconditionally... */
- free_me = argv_expanded = do_variable_expansion(argv + i);
+ //sp: if (child->sp) /* btw we can do it unconditionally... */
+ argv_expanded = do_variable_expansion(argv + i);
rcode = x->function(argv_expanded);
- free(free_me);
+ free(argv_expanded);
restore_redirects(squirrel);
debug_printf_exec("run_pipe_real return %d\n", rcode);
return rcode;
setup_redirects(child, squirrel);
save_nofork_data(&nofork_save);
argv_expanded = argv + i;
- if (child->sp)
- free_me = argv_expanded = do_variable_expansion(argv + i);
+ //sp: if (child->sp)
+ argv_expanded = do_variable_expansion(argv + i);
debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", argv_expanded[0], argv_expanded[1]);
rcode = run_nofork_applet_prime(&nofork_save, a, argv_expanded);
- free(free_me);
+ free(argv_expanded);
restore_redirects(squirrel);
debug_printf_exec("run_pipe_real return %d\n", rcode);
return rcode;
}
}
#endif
- // in non-interactive case fatal sigs are already SIG_DFL
+ /* in non-interactive case fatal sigs are already SIG_DFL */
close_all();
if (nextin != 0) {
dup2(nextin, 0);
if (pi->pgrp < 0)
pi->pgrp = child->pid;
#endif
-
- /* Don't check for errors. The child may be dead already,
- * in which case setpgid returns error code EACCES. */
- //why we do it at all?? child does it itself
- //if (interactive_fd)
- // setpgid(child->pid, pi->pgrp);
-
if (nextin != 0)
close(nextin);
if (nextout != 1)
}
#endif
-// NB: called by pseudo_exec, and therefore must not modify any
-// global data until exec/_exit (we can be a child after vfork!)
+/* NB: called by pseudo_exec, and therefore must not modify any
+ * global data until exec/_exit (we can be a child after vfork!) */
static int run_list_real(struct pipe *pi)
{
#if ENABLE_HUSH_JOB
if (*s == '\\') s++;
cnt++;
}
- dest = malloc(cnt);
- if (!dest)
- return GLOB_NOSPACE;
+ dest = xmalloc(cnt);
if (!(flags & GLOB_APPEND)) {
pglob->gl_pathv = NULL;
pglob->gl_pathc = 0;
pglob->gl_offs = 0;
}
pathc = ++pglob->gl_pathc;
- pglob->gl_pathv = realloc(pglob->gl_pathv, (pathc+1) * sizeof(*pglob->gl_pathv));
- if (pglob->gl_pathv == NULL)
- return GLOB_NOSPACE;
+ pglob->gl_pathv = xrealloc(pglob->gl_pathv, (pathc+1) * sizeof(*pglob->gl_pathv));
pglob->gl_pathv[pathc-1] = dest;
pglob->gl_pathv[pathc] = NULL;
for (s = src; s && *s; s++, dest++) {
while (1) {
str += strcspn(str, ifs);
if (!*str) break;
- str++; // str += strspn(str, ifs); ?
- cnt++; // cnt += strspn(str, ifs); ?
+ str++; /* str += strspn(str, ifs); */
+ cnt++; /* cnt += strspn(str, ifs); - but this code is larger */
}
debug_printf_expand(" return %d\n", cnt);
return cnt;
if (flg_export > 0 || cur->flg_export > 1)
cur->flg_export = 1;
free((char*)cur->value);
- cur->value = strdup(value);
+ cur->value = xstrdup(value);
}
goto skip;
}
}
-// TODO: need simpler/generic rollback on malloc failure - see ash
- cur = malloc(sizeof(*cur));
- if (!cur) {
- result = -1;
- } else {
- cur->name = strdup(name);
- if (!cur->name) {
- free(cur);
- result = -1;
- } else {
- struct variables *bottom = top_vars;
- cur->value = strdup(value);
- cur->next = 0;
- cur->flg_export = flg_export;
- cur->flg_read_only = 0;
- while (bottom->next)
- bottom = bottom->next;
- bottom->next = cur;
- }
+ cur = xzalloc(sizeof(*cur));
+ cur->name = xstrdup(name);
+ cur->value = xstrdup(value);
+ /*cur->next = 0;*/
+ cur->flg_export = flg_export;
+ /*cur->flg_read_only = 0;*/
+ {
+ struct variables *bottom = top_vars;
+ while (bottom->next)
+ bottom = bottom->next;
+ bottom->next = cur;
}
skip:
if (result == 0 && cur->flg_export == 1) {
/*child->group = NULL;*/
/*child->glob_result.gl_pathv = NULL;*/
child->family = pi;
- /*child->sp = 0;*/
+ //sp: /*child->sp = 0;*/
child->type = ctx->parse_type;
ctx->child = child;
debug_printf_parse("handle_dollar entered: ch='%c'\n", ch);
if (isalpha(ch)) {
b_addchr(dest, SPECIAL_VAR_SYMBOL);
- ctx->child->sp++;
+ //sp: ctx->child->sp++;
while (1) {
debug_printf_parse(": '%c'\n", ch);
b_getch(input);
} else if (isdigit(ch)) {
make_one_char_var:
b_addchr(dest, SPECIAL_VAR_SYMBOL);
- ctx->child->sp++;
+ //sp: ctx->child->sp++;
debug_printf_parse(": '%c'\n", ch);
b_getch(input);
b_addchr(dest, ch | quote_mask);
goto make_one_char_var;
case '{':
b_addchr(dest, SPECIAL_VAR_SYMBOL);
- ctx->child->sp++;
+ //sp: ctx->child->sp++;
b_getch(input);
/* XXX maybe someone will try to escape the '}' */
while (1) {
return 0;
}
-//static int parse_string(o_string *dest, struct p_context *ctx, const char *src)
-//{
-// struct in_str foo;
-// setup_string_in_str(&foo, src);
-// return parse_stream(dest, ctx, &foo, NULL);
-//}
-//
/* return code is 0 for normal exit, 1 for syntax error */
static int parse_stream(o_string *dest, struct p_context *ctx,
struct in_str *input, const char *end_trigger)
opt = parse_string_outer(optarg, FLAG_PARSE_SEMICOLON);
goto final_return;
case 'i':
- // Well, we cannot just declare interactiveness,
- // we have to have some stuff (ctty, etc)
- /*interactive_fd++;*/
+ /* Well, we cannot just declare interactiveness,
+ * we have to have some stuff (ctty, etc) */
+ /* interactive_fd++; */
break;
case 'f':
fake_mode++;