#define SPECIAL_VAR_SYMBOL 3
-typedef enum redir_type {
- REDIRECT_INVALID = 0,
- REDIRECT_INPUT = 1,
- REDIRECT_OVERWRITE = 2,
- REDIRECT_APPEND = 3,
- REDIRECT_HEREDOC = 4,
- REDIRECT_IO = 5,
- REDIRECT_HEREDOC2 = 6, /* REDIRECT_HEREDOC after heredoc load */
-} redir_type;
-
/* The descrip member of this structure is only used to make
* debugging output pretty */
static const struct {
struct redir_struct {
struct redir_struct *next;
char *rd_filename; /* filename */
- int fd; /* file descriptor being redirected */
- int dup; /* -1, or file descriptor being duplicated */
- smallint /*enum redir_type*/ rd_type;
+ int rd_fd; /* file descriptor being redirected */
+ int rd_dup; /* -1, or file descriptor being duplicated */
+ smallint rd_type; /* (enum redir_type) */
+ /* note: for heredocs, rd_filename contains heredoc delimiter,
+ * and subsequently heredoc itself; and rd_dup is
+ * "do we need to trim leading tabs?" bool flag
+ */
};
+typedef enum redir_type {
+ REDIRECT_INVALID = 0,
+ REDIRECT_INPUT = 1,
+ REDIRECT_OVERWRITE = 2,
+ REDIRECT_APPEND = 3,
+ REDIRECT_HEREDOC = 4,
+ REDIRECT_IO = 5,
+ REDIRECT_HEREDOC2 = 6, /* REDIRECT_HEREDOC after heredoc is loaded */
+} redir_type;
+
struct command {
pid_t pid; /* 0 if exited */
}
#if ENABLE_HUSH_JOB
+/* After [v]fork, in child: do not restore tty pgrp on xfunc death */
+#define disable_restore_tty_pgrp_on_exit() (die_sleep = 0)
+/* After [v]fork, in parent: do not restore tty pgrp on xfunc death */
+#define enable_restore_tty_pgrp_on_exit() (die_sleep = -1)
+
/* Restores tty foreground process group, and exits.
* May be called as signal handler for fatal signal
* (will faithfully resend signal to itself, producing correct exit state)
kill_myself_with_sig(sig); /* does not return */
}
+#else
+
+#define disable_restore_tty_pgrp_on_exit() ((void)0)
+#define enable_restore_tty_pgrp_on_exit() ((void)0)
+
#endif
/* Restores tty foreground process group, and exits. */
{
o_addblock(o, str, strlen(str));
}
+static void nommu_addchr(o_string *o, int ch)
+{
+ if (o)
+ o_addchr(o, ch);
+}
+#else
+#define nommu_addchr(o, str) ((void)0)
#endif
static void o_addstr_with_NUL(o_string *o, const char *str)
/* Okay, pipe buffer was not big enough */
/* Note: we must not create a stray child (bastard? :)
- * for the unsuspecting parent process. We create a grandchild
- * and exit before we exec the process which consumes heredoc
+ * for the unsuspecting parent process. Child creates a grandchild
+ * and exits before parent execs the process which consumes heredoc
* (that exec happens after we return from this function) */
pid = vfork();
if (pid < 0)
/* grandchild */
close(fd); /* read side of the pipe */
#if BB_MMU
- full_write(pair.wr, heredoc, len);
+ full_write(pair.wr, heredoc, len); /* may loop or block */
_exit(0);
#else
/* Delegate blocking writes to another process */
-# if ENABLE_HUSH_JOB
- die_sleep = 0; /* do not restore tty pgrp on xfunc death */
-# endif
+ disable_restore_tty_pgrp_on_exit();
xmove_fd(pair.wr, STDOUT_FILENO);
re_execute_shell(heredoc, 1);
#endif
}
/* parent */
-#if ENABLE_HUSH_JOB
- die_sleep = -1; /* restore tty pgrp on xfunc death */
-#endif
+ enable_restore_tty_pgrp_on_exit();
clean_up_after_re_execute();
close(pair.wr);
- wait(NULL); /* wiat till child has died */
+ wait(NULL); /* wait till child has died */
}
/* squirrel != NULL means we squirrel away copies of stdin, stdout,
for (redir = prog->redirects; redir; redir = redir->next) {
if (redir->rd_type == REDIRECT_HEREDOC2) {
- if (squirrel && redir->fd < 3) {
- squirrel[redir->fd] = dup(redir->fd);
+ if (squirrel && redir->rd_fd < 3) {
+ squirrel[redir->rd_fd] = dup(redir->rd_fd);
}
/* for REDIRECT_HEREDOC2, rd_filename holds _contents_
* of the heredoc */
debug_printf_parse("set heredoc '%s'\n",
redir->rd_filename);
- setup_heredoc(redir->fd, redir->rd_filename);
+ setup_heredoc(redir->rd_fd, redir->rd_filename);
continue;
}
- if (redir->dup == -1) {
+ if (redir->rd_dup == -1) {
char *p;
if (redir->rd_filename == NULL) {
/* Something went wrong in the parse.
return 1;
}
} else {
- openfd = redir->dup;
+ openfd = redir->rd_dup;
}
- if (openfd != redir->fd) {
- if (squirrel && redir->fd < 3) {
- squirrel[redir->fd] = dup(redir->fd);
+ if (openfd != redir->rd_fd) {
+ if (squirrel && redir->rd_fd < 3) {
+ squirrel[redir->rd_fd] = dup(redir->rd_fd);
}
if (openfd == -3) {
/* "-" means "close me" and we use -3 for that */
- close(redir->fd);
+ close(redir->rd_fd);
} else {
- dup2(openfd, redir->fd);
- if (redir->dup == -1)
+ dup2(openfd, redir->rd_fd);
+ if (redir->rd_dup == -1)
close(openfd);
}
}
#endif
for (r = command->redirects; r; r = rnext) {
debug_printf_clean("%s redirect %d%s", indenter(indent), r->fd, redir_table[r->rd_type].descrip);
- if (r->dup == -1) {
+ if (r->rd_dup == -1) {
/* guard against the case >$FOO, where foo is unset or blank */
if (r->rd_filename) {
debug_printf_clean(" %s\n", r->rd_filename);
r->rd_filename = NULL;
}
} else {
- debug_printf_clean("&%d\n", r->dup);
+ debug_printf_clean("&%d\n", r->rd_dup);
}
rnext = r->next;
free(r);
command->pid = BB_MMU ? fork() : vfork();
if (!command->pid) { /* child */
#if ENABLE_HUSH_JOB
- die_sleep = 0; /* do not restore tty pgrp on xfunc death */
+ disable_restore_tty_pgrp_on_exit();
/* Every child adds itself to new process group
* with pgid == pid_of_first_child_in_pipe */
}
/* parent or error */
-#if ENABLE_HUSH_JOB
- die_sleep = -1; /* restore tty pgrp on xfunc death */
-#endif
+ enable_restore_tty_pgrp_on_exit();
#if !BB_MMU
/* Clean up after vforked child */
clean_up_after_re_execute();
return -1;
ch = i_getch(input); /* get the & */
-#if !BB_MMU
- o_addchr(as_string, ch);
-#endif
+ nommu_addchr(as_string, ch);
ch = i_peek(input);
if (ch == '-') {
ch = i_getch(input);
-#if !BB_MMU
- o_addchr(as_string, ch);
-#endif
+ nommu_addchr(as_string, ch);
return -3; /* "-" represents "close me" */
}
d = 0;
d = d*10 + (ch-'0');
ok = 1;
ch = i_getch(input);
-#if !BB_MMU
- o_addchr(as_string, ch);
-#endif
+ nommu_addchr(as_string, ch);
ch = i_peek(input);
}
if (ok) return d;
dup_num = redirect_dup_num(&ctx->as_string, input);
if (dup_num == -2)
return 1; /* syntax error */
+ } else {
+ int ch = i_peek(input);
+ dup_num = (ch == '-');
+ if (dup_num) { /* <<-... */
+ ch = i_getch(input);
+ nommu_addchr(&ctx->as_string, ch);
+ ch = i_peek(input);
+ }
+ /* <<[-] word is the same as <<[-]word */
+ while (ch == ' ' || ch == '\t') {
+ ch = i_getch(input);
+ nommu_addchr(&ctx->as_string, ch);
+ ch = i_peek(input);
+ }
}
-//TODO: else { check for <<-word }
if (style == REDIRECT_OVERWRITE && dup_num == -1) {
int ch = i_peek(input);
* >| and > are the same for now. Just eat |.
*/
ch = i_getch(input);
-#if !BB_MMU
- o_addchr(&ctx->as_string, ch);
-#endif
+ nommu_addchr(&ctx->as_string, ch);
}
}
/* redir->next = NULL; */
/* redir->rd_filename = NULL; */
redir->rd_type = style;
- redir->fd = (fd == -1) ? redir_table[style].default_fd : fd;
+ redir->rd_fd = (fd == -1) ? redir_table[style].default_fd : fd;
- debug_printf_parse("redirect type %d %s\n", redir->fd, redir_table[style].descrip);
+ debug_printf_parse("redirect type %d %s\n", redir->rd_fd, redir_table[style].descrip);
- redir->dup = dup_num;
- if (dup_num != -1) {
+ redir->rd_dup = dup_num;
+ if (style != REDIRECT_HEREDOC && dup_num != -1) {
/* Erik had a check here that the file descriptor in question
* is legit; I postpone that to "run time"
* A "-" representation of "close me" shows up as a -3 here */
- debug_printf_parse("duplicating redirect '%d>&%d'\n", redir->fd, redir->dup);
+ debug_printf_parse("duplicating redirect '%d>&%d'\n", redir->rd_fd, redir->rd_dup);
} else {
/* Set ctx->pending_redirect, so we know what to do at the
* end of the next parsed word. */
return num;
}
-//TODO: add NOMMU as_string fill
-static char *fetch_till_str(struct in_str *input, const char *word)
+#if BB_MMU
+#define fetch_till_str(as_string, input, word, skip_tabs) \
+ fetch_till_str(input, word, skip_tabs)
+#endif
+static char *fetch_till_str(o_string *as_string,
+ struct in_str *input,
+ const char *word,
+ int skip_tabs)
{
o_string heredoc = NULL_O_STRING;
int past_EOL = 0;
int ch;
+ goto jump_in;
while (1) {
ch = i_getch(input);
- if (ch == EOF) {
- o_free_unsafe(&heredoc);
- return NULL;
- }
+ nommu_addchr(as_string, ch);
if (ch == '\n') {
if (strcmp(heredoc.data + past_EOL, word) == 0) {
heredoc.data[past_EOL] = '\0';
debug_printf_parse("parsed heredoc '%s'\n", heredoc.data);
return heredoc.data;
}
- past_EOL = heredoc.length + 1;
+ do {
+ o_addchr(&heredoc, ch);
+ past_EOL = heredoc.length;
+ jump_in:
+ do {
+ ch = i_getch(input);
+ nommu_addchr(as_string, ch);
+ } while (skip_tabs && ch == '\t');
+ } while (ch == '\n');
+ }
+ if (ch == EOF) {
+ o_free_unsafe(&heredoc);
+ return NULL;
}
o_addchr(&heredoc, ch);
+ nommu_addchr(as_string, ch);
}
}
pi->num_cmds,
cmd->argv ? cmd->argv[0] : "NONE");
for (i = 0; i < pi->num_cmds; i++) {
- struct redir_struct *redirect = cmd->redirects;
+ struct redir_struct *redir = cmd->redirects;
debug_printf_parse("fetch_heredocs: %d cmd argv0:'%s'\n",
i, cmd->argv ? cmd->argv[0] : "NONE");
- while (redirect) {
- if (redirect->rd_type == REDIRECT_HEREDOC) {
+ while (redir) {
+ if (redir->rd_type == REDIRECT_HEREDOC) {
char *p;
if (heredoc_cnt <= 0)
return 1; /* error */
- redirect->rd_type = REDIRECT_HEREDOC2;
- p = fetch_till_str(input, redirect->rd_filename);
+ redir->rd_type = REDIRECT_HEREDOC2;
+ /* redir->dup is (ab)used to indicate <<- */
+ p = fetch_till_str(&ctx->as_string, input,
+ redir->rd_filename, redir->rd_dup);
if (!p)
return 1; /* unexpected EOF */
- free(redirect->rd_filename);
- redirect->rd_filename = p;
+ free(redir->rd_filename);
+ redir->rd_filename = p;
heredoc_cnt--;
}
- redirect = redirect->next;
+ redir = redir->next;
}
cmd++;
}
bb_perror_msg_and_die(BB_MMU ? "fork" : "vfork");
if (pid == 0) { /* child */
-#if ENABLE_HUSH_JOB
- die_sleep = 0; /* do not restore tty pgrp on xfunc death */
-#endif
+ disable_restore_tty_pgrp_on_exit();
/* Process substitution is not considered to be usual
* 'command execution'.
* SUSv3 says ctrl-Z should be ignored, ctrl-C should not.
}
/* parent */
-#if ENABLE_HUSH_JOB
- die_sleep = -1; /* restore tty pgrp on xfunc death */
-#endif
+ enable_restore_tty_pgrp_on_exit();
clean_up_after_re_execute();
close(channel[1]);
pf = fdopen(channel[0], "r");
debug_printf_parse("handle_dollar entered: ch='%c'\n", ch);
if (isalpha(ch)) {
ch = i_getch(input);
-#if !BB_MMU
- if (as_string) o_addchr(as_string, ch);
-#endif
+ nommu_addchr(as_string, ch);
make_var:
o_addchr(dest, SPECIAL_VAR_SYMBOL);
while (1) {
if (!isalnum(ch) && ch != '_')
break;
ch = i_getch(input);
-#if !BB_MMU
- if (as_string) o_addchr(as_string, ch);
-#endif
+ nommu_addchr(as_string, ch);
}
o_addchr(dest, SPECIAL_VAR_SYMBOL);
} else if (isdigit(ch)) {
make_one_char_var:
ch = i_getch(input);
-#if !BB_MMU
- if (as_string) o_addchr(as_string, ch);
-#endif
+ nommu_addchr(as_string, ch);
o_addchr(dest, SPECIAL_VAR_SYMBOL);
debug_printf_parse(": '%c'\n", ch);
o_addchr(dest, ch | quote_mask);
o_addchr(dest, SPECIAL_VAR_SYMBOL);
ch = i_getch(input);
-#if !BB_MMU
- if (as_string) o_addchr(as_string, ch);
-#endif
+ nommu_addchr(as_string, ch);
/* XXX maybe someone will try to escape the '}' */
expansion = 0;
first_char = true;
all_digits = false;
while (1) {
ch = i_getch(input);
-#if !BB_MMU
- if (as_string) o_addchr(as_string, ch);
-#endif
+ nommu_addchr(as_string, ch);
if (ch == '}')
break;
int pos;
# endif
ch = i_getch(input);
-# if !BB_MMU
- if (as_string) o_addchr(as_string, ch);
-# endif
+ nommu_addchr(as_string, ch);
# if ENABLE_SH_MATH_SUPPORT
if (i_peek(input) == '(') {
ch = i_getch(input);
-# if !BB_MMU
- if (as_string) o_addchr(as_string, ch);
-# endif
+ nommu_addchr(as_string, ch);
o_addchr(dest, SPECIAL_VAR_SYMBOL);
o_addchr(dest, /*quote_mask |*/ '+');
# if !BB_MMU
#endif
case '_':
ch = i_getch(input);
-#if !BB_MMU
- if (as_string) o_addchr(as_string, ch);
-#endif
+ nommu_addchr(as_string, ch);
ch = i_peek(input);
if (isalnum(ch)) { /* it's $_name or $_123 */
ch = '_';
again:
ch = i_getch(input);
-#if !BB_MMU
- if (as_string && ch != EOF) o_addchr(as_string, ch);
-#endif
+ if (ch != EOF)
+ nommu_addchr(as_string, ch);
if (ch == dquote_end) { /* may be only '"' or EOF */
dest->nonnull = 1;
if (dest->o_assignment == NOT_ASSIGNMENT)
#endif
return pi;
}
-#if !BB_MMU
- o_addchr(&ctx.as_string, ch);
-#endif
+ nommu_addchr(&ctx.as_string, ch);
is_ifs = strchr(G.ifs, ch);
is_special = strchr("<>;&|(){}#'" /* special outside of "str" */
"\\$\"" USE_HUSH_TICK("`") /* always special */
i_getch(input);
/* note: we do not add it to &ctx.as_string */
}
-#if !BB_MMU
//TODO: go back one char?
- o_addchr(&ctx.as_string, '\n');
-#endif
+ nommu_addchr(&ctx.as_string, '\n');
} else {
o_addQchr(&dest, ch);
}
o_addchr(&dest, '\\');
ch = i_getch(input);
o_addchr(&dest, ch);
-#if !BB_MMU
- o_addchr(&ctx.as_string, ch);
-#endif
+ nommu_addchr(&ctx.as_string, ch);
break;
case '$':
if (handle_dollar(&ctx.as_string, &dest, input) != 0) {
syntax("unterminated '");
goto parse_error;
}
-#if !BB_MMU
- o_addchr(&ctx.as_string, ch);
-#endif
+ nommu_addchr(&ctx.as_string, ch);
if (ch == '\'')
break;
if (dest.o_assignment == NOT_ASSIGNMENT)
if (next == '>') {
redir_style = REDIRECT_APPEND;
ch = i_getch(input);
-#if !BB_MMU
- o_addchr(&ctx.as_string, ch);
-#endif
+ nommu_addchr(&ctx.as_string, ch);
}
#if 0
else if (next == '(') {
heredoc_cnt++;
debug_printf_parse("++heredoc_cnt=%d\n", heredoc_cnt);
ch = i_getch(input);
-#if !BB_MMU
- o_addchr(&ctx.as_string, ch);
-#endif
+ nommu_addchr(&ctx.as_string, ch);
} else if (next == '>') {
redir_style = REDIRECT_IO;
ch = i_getch(input);
-#if !BB_MMU
- o_addchr(&ctx.as_string, ch);
-#endif
+ nommu_addchr(&ctx.as_string, ch);
}
#if 0
else if (next == '(') {
if (ch != ';')
break;
ch = i_getch(input);
-#if !BB_MMU
- o_addchr(&ctx.as_string, ch);
-#endif
+ nommu_addchr(&ctx.as_string, ch);
if (ctx.ctx_res_w == RES_CASEI) {
ctx.ctx_dsemicolon = 1;
ctx.ctx_res_w = RES_MATCH;
}
if (next == '&') {
ch = i_getch(input);
-#if !BB_MMU
- o_addchr(&ctx.as_string, ch);
-#endif
+ nommu_addchr(&ctx.as_string, ch);
done_pipe(&ctx, PIPE_AND);
} else {
done_pipe(&ctx, PIPE_BG);
#endif
if (next == '|') { /* || */
ch = i_getch(input);
-#if !BB_MMU
- o_addchr(&ctx.as_string, ch);
-#endif
+ nommu_addchr(&ctx.as_string, ch);
done_pipe(&ctx, PIPE_OR);
} else {
/* we could pick up a file descriptor choice here
tcsetpgrp(G_interactive_fd, getpid());
/* -1 is special - makes xfuncs longjmp, not exit
* (we reset die_sleep = 0 whereever we [v]fork) */
- die_sleep = -1;
+ enable_restore_tty_pgrp_on_exit(); /* sets die_sleep = -1 */
if (setjmp(die_jmp)) {
/* xfunc has failed! die die die */
hush_exit(xfunc_error_retval);