|
|
|
@ -357,6 +357,9 @@
|
|
|
|
|
#else
|
|
|
|
|
# define CLEAR_RANDOM_T(rnd) ((void)0)
|
|
|
|
|
#endif
|
|
|
|
|
#ifndef O_CLOEXEC
|
|
|
|
|
# define O_CLOEXEC 0
|
|
|
|
|
#endif
|
|
|
|
|
#ifndef F_DUPFD_CLOEXEC
|
|
|
|
|
# define F_DUPFD_CLOEXEC F_DUPFD
|
|
|
|
|
#endif
|
|
|
|
@ -556,11 +559,27 @@ static const char *const assignment_flag[] = {
|
|
|
|
|
};
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* We almost can use standard FILE api, but we need an ability to move
|
|
|
|
|
* its fd when redirects coincide with it. No api exists for that
|
|
|
|
|
* (RFE for it at https://sourceware.org/bugzilla/show_bug.cgi?id=21902).
|
|
|
|
|
* HFILE is our internal alternative. Only supports reading.
|
|
|
|
|
* Since we now can, we incorporate linked list of all opened HFILEs
|
|
|
|
|
* into the struct (used to be a separate mini-list).
|
|
|
|
|
*/
|
|
|
|
|
typedef struct HFILE {
|
|
|
|
|
char *cur;
|
|
|
|
|
char *end;
|
|
|
|
|
struct HFILE *next_hfile;
|
|
|
|
|
int is_stdin;
|
|
|
|
|
int fd;
|
|
|
|
|
char buf[1024];
|
|
|
|
|
} HFILE;
|
|
|
|
|
|
|
|
|
|
typedef struct in_str {
|
|
|
|
|
const char *p;
|
|
|
|
|
int peek_buf[2];
|
|
|
|
|
int last_char;
|
|
|
|
|
FILE *file;
|
|
|
|
|
HFILE *file;
|
|
|
|
|
} in_str;
|
|
|
|
|
|
|
|
|
|
/* The descrip member of this structure is only used to make
|
|
|
|
@ -814,14 +833,6 @@ enum {
|
|
|
|
|
NUM_OPT_O
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct FILE_list {
|
|
|
|
|
struct FILE_list *next;
|
|
|
|
|
FILE *fp;
|
|
|
|
|
int fd;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* "Globals" within this file */
|
|
|
|
|
/* Sorted roughly by size (smaller offsets == smaller code) */
|
|
|
|
|
struct globals {
|
|
|
|
@ -954,7 +965,7 @@ struct globals {
|
|
|
|
|
unsigned lineno;
|
|
|
|
|
char *lineno_var;
|
|
|
|
|
#endif
|
|
|
|
|
struct FILE_list *FILE_list;
|
|
|
|
|
HFILE *HFILE_list;
|
|
|
|
|
/* Which signals have non-DFL handler (even with no traps set)?
|
|
|
|
|
* Set at the start to:
|
|
|
|
|
* (SIGQUIT + maybe SPECIAL_INTERACTIVE_SIGS + maybe SPECIAL_JOBSTOP_SIGS)
|
|
|
|
@ -1563,83 +1574,115 @@ static int xdup_CLOEXEC_and_close(int fd, int avoid_fd)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Manipulating the list of open FILEs */
|
|
|
|
|
static FILE *remember_FILE(FILE *fp)
|
|
|
|
|
/* Manipulating HFILEs */
|
|
|
|
|
static HFILE *hfopen(const char *name)
|
|
|
|
|
{
|
|
|
|
|
if (fp) {
|
|
|
|
|
struct FILE_list *n = xmalloc(sizeof(*n));
|
|
|
|
|
n->next = G.FILE_list;
|
|
|
|
|
G.FILE_list = n;
|
|
|
|
|
n->fp = fp;
|
|
|
|
|
n->fd = fileno(fp);
|
|
|
|
|
close_on_exec_on(n->fd);
|
|
|
|
|
HFILE *fp;
|
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
|
|
fd = STDIN_FILENO;
|
|
|
|
|
if (name) {
|
|
|
|
|
fd = open(name, O_RDONLY | O_CLOEXEC);
|
|
|
|
|
if (fd < 0)
|
|
|
|
|
return NULL;
|
|
|
|
|
if (O_CLOEXEC == 0) /* ancient libc */
|
|
|
|
|
close_on_exec_on(fd);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fp = xmalloc(sizeof(*fp));
|
|
|
|
|
fp->is_stdin = (name == NULL);
|
|
|
|
|
fp->fd = fd;
|
|
|
|
|
fp->cur = fp->end = fp->buf;
|
|
|
|
|
fp->next_hfile = G.HFILE_list;
|
|
|
|
|
G.HFILE_list = fp;
|
|
|
|
|
return fp;
|
|
|
|
|
}
|
|
|
|
|
static void fclose_and_forget(FILE *fp)
|
|
|
|
|
static void hfclose(HFILE *fp)
|
|
|
|
|
{
|
|
|
|
|
struct FILE_list **pp = &G.FILE_list;
|
|
|
|
|
HFILE **pp = &G.HFILE_list;
|
|
|
|
|
while (*pp) {
|
|
|
|
|
struct FILE_list *cur = *pp;
|
|
|
|
|
if (cur->fp == fp) {
|
|
|
|
|
*pp = cur->next;
|
|
|
|
|
free(cur);
|
|
|
|
|
HFILE *cur = *pp;
|
|
|
|
|
if (cur == fp) {
|
|
|
|
|
*pp = cur->next_hfile;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
pp = &cur->next;
|
|
|
|
|
pp = &cur->next_hfile;
|
|
|
|
|
}
|
|
|
|
|
fclose(fp);
|
|
|
|
|
if (fp->fd >= 0)
|
|
|
|
|
close(fp->fd);
|
|
|
|
|
free(fp);
|
|
|
|
|
}
|
|
|
|
|
static int save_FILEs_on_redirect(int fd, int avoid_fd)
|
|
|
|
|
static int refill_HFILE_and_getc(HFILE *fp)
|
|
|
|
|
{
|
|
|
|
|
struct FILE_list *fl = G.FILE_list;
|
|
|
|
|
int n;
|
|
|
|
|
|
|
|
|
|
if (fp->fd < 0) {
|
|
|
|
|
/* Already saw EOF */
|
|
|
|
|
return EOF;
|
|
|
|
|
}
|
|
|
|
|
/* Try to buffer more input */
|
|
|
|
|
fp->cur = fp->buf;
|
|
|
|
|
n = safe_read(fp->fd, fp->buf, sizeof(fp->buf));
|
|
|
|
|
if (n < 0) {
|
|
|
|
|
bb_perror_msg("read error");
|
|
|
|
|
n = 0;
|
|
|
|
|
}
|
|
|
|
|
fp->end = fp->buf + n;
|
|
|
|
|
if (n == 0) {
|
|
|
|
|
/* EOF/error */
|
|
|
|
|
close(fp->fd);
|
|
|
|
|
fp->fd = -1;
|
|
|
|
|
return EOF;
|
|
|
|
|
}
|
|
|
|
|
return (unsigned char)(*fp->cur++);
|
|
|
|
|
}
|
|
|
|
|
/* Inlined for common case of non-empty buffer.
|
|
|
|
|
*/
|
|
|
|
|
static ALWAYS_INLINE int hfgetc(HFILE *fp)
|
|
|
|
|
{
|
|
|
|
|
if (fp->cur < fp->end)
|
|
|
|
|
return (unsigned char)(*fp->cur++);
|
|
|
|
|
/* Buffer empty */
|
|
|
|
|
return refill_HFILE_and_getc(fp);
|
|
|
|
|
}
|
|
|
|
|
static int move_HFILEs_on_redirect(int fd, int avoid_fd)
|
|
|
|
|
{
|
|
|
|
|
HFILE *fl = G.HFILE_list;
|
|
|
|
|
while (fl) {
|
|
|
|
|
if (fd == fl->fd) {
|
|
|
|
|
/* We use it only on script files, they are all CLOEXEC */
|
|
|
|
|
fl->fd = xdup_CLOEXEC_and_close(fd, avoid_fd);
|
|
|
|
|
debug_printf_redir("redirect_fd %d: matches a script fd, moving it to %d\n", fd, fl->fd);
|
|
|
|
|
return 1;
|
|
|
|
|
return 1; /* "found and moved" */
|
|
|
|
|
}
|
|
|
|
|
fl = fl->next;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
static void restore_redirected_FILEs(void)
|
|
|
|
|
{
|
|
|
|
|
struct FILE_list *fl = G.FILE_list;
|
|
|
|
|
while (fl) {
|
|
|
|
|
int should_be = fileno(fl->fp);
|
|
|
|
|
if (fl->fd != should_be) {
|
|
|
|
|
debug_printf_redir("restoring script fd from %d to %d\n", fl->fd, should_be);
|
|
|
|
|
xmove_fd(fl->fd, should_be);
|
|
|
|
|
fl->fd = should_be;
|
|
|
|
|
}
|
|
|
|
|
fl = fl->next;
|
|
|
|
|
fl = fl->next_hfile;
|
|
|
|
|
}
|
|
|
|
|
return 0; /* "not in the list" */
|
|
|
|
|
}
|
|
|
|
|
#if ENABLE_FEATURE_SH_STANDALONE && BB_MMU
|
|
|
|
|
static void close_all_FILE_list(void)
|
|
|
|
|
static void close_all_HFILE_list(void)
|
|
|
|
|
{
|
|
|
|
|
struct FILE_list *fl = G.FILE_list;
|
|
|
|
|
HFILE *fl = G.HFILE_list;
|
|
|
|
|
while (fl) {
|
|
|
|
|
/* fclose would also free FILE object.
|
|
|
|
|
/* hfclose would also free HFILE object.
|
|
|
|
|
* It is disastrous if we share memory with a vforked parent.
|
|
|
|
|
* I'm not sure we never come here after vfork.
|
|
|
|
|
* Therefore just close fd, nothing more.
|
|
|
|
|
*/
|
|
|
|
|
/*fclose(fl->fp); - unsafe */
|
|
|
|
|
close(fl->fd);
|
|
|
|
|
fl = fl->next;
|
|
|
|
|
/*hfclose(fl); - unsafe */
|
|
|
|
|
if (fl->fd >= 0)
|
|
|
|
|
close(fl->fd);
|
|
|
|
|
fl = fl->next_hfile;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
static int fd_in_FILEs(int fd)
|
|
|
|
|
static int fd_in_HFILEs(int fd)
|
|
|
|
|
{
|
|
|
|
|
struct FILE_list *fl = G.FILE_list;
|
|
|
|
|
HFILE *fl = G.HFILE_list;
|
|
|
|
|
while (fl) {
|
|
|
|
|
if (fl->fd == fd)
|
|
|
|
|
return 1;
|
|
|
|
|
fl = fl->next;
|
|
|
|
|
fl = fl->next_hfile;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
@ -2580,7 +2623,7 @@ static int get_user_input(struct in_str *i)
|
|
|
|
|
}
|
|
|
|
|
fflush_all();
|
|
|
|
|
//FIXME: here ^C or SIGINT will have effect only after <Enter>
|
|
|
|
|
r = fgetc(i->file);
|
|
|
|
|
r = hfgetc(i->file);
|
|
|
|
|
/* In !ENABLE_FEATURE_EDITING we don't use read_line_input,
|
|
|
|
|
* no ^C masking happens during fgetc, no special code for ^C:
|
|
|
|
|
* it generates SIGINT as usual.
|
|
|
|
@ -2600,22 +2643,22 @@ static int fgetc_interactive(struct in_str *i)
|
|
|
|
|
{
|
|
|
|
|
int ch;
|
|
|
|
|
/* If it's interactive stdin, get new line. */
|
|
|
|
|
if (G_interactive_fd && i->file == stdin) {
|
|
|
|
|
if (G_interactive_fd && i->file->is_stdin) {
|
|
|
|
|
/* Returns first char (or EOF), the rest is in i->p[] */
|
|
|
|
|
ch = get_user_input(i);
|
|
|
|
|
G.promptmode = 1; /* PS2 */
|
|
|
|
|
debug_printf_prompt("%s promptmode=%d\n", __func__, G.promptmode);
|
|
|
|
|
} else {
|
|
|
|
|
/* Not stdin: script file, sourced file, etc */
|
|
|
|
|
do ch = fgetc(i->file); while (ch == '\0');
|
|
|
|
|
do ch = hfgetc(i->file); while (ch == '\0');
|
|
|
|
|
}
|
|
|
|
|
return ch;
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
static inline int fgetc_interactive(struct in_str *i)
|
|
|
|
|
static ALWAYS_INLINE int fgetc_interactive(struct in_str *i)
|
|
|
|
|
{
|
|
|
|
|
int ch;
|
|
|
|
|
do ch = fgetc(i->file); while (ch == '\0');
|
|
|
|
|
do ch = hfgetc(i->file); while (ch == '\0');
|
|
|
|
|
return ch;
|
|
|
|
|
}
|
|
|
|
|
#endif /* INTERACTIVE */
|
|
|
|
@ -2730,7 +2773,7 @@ static int i_peek2(struct in_str *i)
|
|
|
|
|
ch = i->peek_buf[1];
|
|
|
|
|
if (ch == 0) {
|
|
|
|
|
/* We did not read it yet, get it now */
|
|
|
|
|
do ch = fgetc(i->file); while (ch == '\0');
|
|
|
|
|
do ch = hfgetc(i->file); while (ch == '\0');
|
|
|
|
|
i->peek_buf[1] = ch;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -2774,10 +2817,10 @@ static int i_peek_and_eat_bkslash_nl(struct in_str *input)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void setup_file_in_str(struct in_str *i, FILE *f)
|
|
|
|
|
static void setup_file_in_str(struct in_str *i, HFILE *fp)
|
|
|
|
|
{
|
|
|
|
|
memset(i, 0, sizeof(*i));
|
|
|
|
|
i->file = f;
|
|
|
|
|
i->file = fp;
|
|
|
|
|
/* i->p = NULL; */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -7106,19 +7149,19 @@ static void parse_and_run_string(const char *s)
|
|
|
|
|
//IF_HUSH_LINENO_VAR(G.lineno = sv;)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void parse_and_run_file(FILE *f)
|
|
|
|
|
static void parse_and_run_file(HFILE *fp)
|
|
|
|
|
{
|
|
|
|
|
struct in_str input;
|
|
|
|
|
IF_HUSH_LINENO_VAR(unsigned sv = G.lineno;)
|
|
|
|
|
|
|
|
|
|
IF_HUSH_LINENO_VAR(G.lineno = 1;)
|
|
|
|
|
setup_file_in_str(&input, f);
|
|
|
|
|
setup_file_in_str(&input, fp);
|
|
|
|
|
parse_and_run_stream(&input, ';');
|
|
|
|
|
IF_HUSH_LINENO_VAR(G.lineno = sv;)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if ENABLE_HUSH_TICK
|
|
|
|
|
static FILE *generate_stream_from_string(const char *s, pid_t *pid_p)
|
|
|
|
|
static int generate_stream_from_string(const char *s, pid_t *pid_p)
|
|
|
|
|
{
|
|
|
|
|
pid_t pid;
|
|
|
|
|
int channel[2];
|
|
|
|
@ -7220,7 +7263,7 @@ static FILE *generate_stream_from_string(const char *s, pid_t *pid_p)
|
|
|
|
|
free(to_free);
|
|
|
|
|
# endif
|
|
|
|
|
close(channel[1]);
|
|
|
|
|
return remember_FILE(xfdopen_for_read(channel[0]));
|
|
|
|
|
return channel[0];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Return code is exit status of the process that is run. */
|
|
|
|
@ -7230,7 +7273,7 @@ static int process_command_subs(o_string *dest, const char *s)
|
|
|
|
|
pid_t pid;
|
|
|
|
|
int status, ch, eol_cnt;
|
|
|
|
|
|
|
|
|
|
fp = generate_stream_from_string(s, &pid);
|
|
|
|
|
fp = xfdopen_for_read(generate_stream_from_string(s, &pid));
|
|
|
|
|
|
|
|
|
|
/* Now send results of command back into original context */
|
|
|
|
|
eol_cnt = 0;
|
|
|
|
@ -7249,7 +7292,7 @@ static int process_command_subs(o_string *dest, const char *s)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
debug_printf("done reading from `cmd` pipe, closing it\n");
|
|
|
|
|
fclose_and_forget(fp);
|
|
|
|
|
fclose(fp);
|
|
|
|
|
/* We need to extract exitcode. Test case
|
|
|
|
|
* "true; echo `sleep 1; false` $?"
|
|
|
|
|
* should print 1 */
|
|
|
|
@ -7427,20 +7470,17 @@ static int save_fd_on_redirect(int fd, int avoid_fd, struct squirrel **sqp)
|
|
|
|
|
return 1; /* "we closed fd" */
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
/* If this one of script's fds? */
|
|
|
|
|
if (move_HFILEs_on_redirect(fd, avoid_fd))
|
|
|
|
|
return 1; /* yes. "we closed fd" (actually moved it) */
|
|
|
|
|
|
|
|
|
|
/* Are we called from setup_redirects(squirrel==NULL)? Two cases:
|
|
|
|
|
* (1) Redirect in a forked child. No need to save FILEs' fds,
|
|
|
|
|
* we aren't going to use them anymore, ok to trash.
|
|
|
|
|
* (2) "exec 3>FILE". Bummer. We can save script FILEs' fds,
|
|
|
|
|
* but how are we doing to restore them?
|
|
|
|
|
* "fileno(fd) = new_fd" can't be done.
|
|
|
|
|
* (1) Redirect in a forked child.
|
|
|
|
|
* (2) "exec 3>FILE".
|
|
|
|
|
*/
|
|
|
|
|
if (!sqp)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
/* If this one of script's fds? */
|
|
|
|
|
if (save_FILEs_on_redirect(fd, avoid_fd))
|
|
|
|
|
return 1; /* yes. "we closed fd" */
|
|
|
|
|
|
|
|
|
|
/* Check whether it collides with any open fds (e.g. stdio), save fds as needed */
|
|
|
|
|
*sqp = add_squirrel(*sqp, fd, avoid_fd);
|
|
|
|
|
return 0; /* "we did not close fd" */
|
|
|
|
@ -7465,8 +7505,6 @@ static void restore_redirects(struct squirrel *sq)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If moved, G.interactive_fd stays on new fd, not restoring it */
|
|
|
|
|
|
|
|
|
|
restore_redirected_FILEs();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if ENABLE_FEATURE_SH_STANDALONE && BB_MMU
|
|
|
|
@ -7474,7 +7512,7 @@ static void close_saved_fds_and_FILE_fds(void)
|
|
|
|
|
{
|
|
|
|
|
if (G_interactive_fd)
|
|
|
|
|
close(G_interactive_fd);
|
|
|
|
|
close_all_FILE_list();
|
|
|
|
|
close_all_HFILE_list();
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
@ -7487,7 +7525,7 @@ static int internally_opened_fd(int fd, struct squirrel *sq)
|
|
|
|
|
return 1;
|
|
|
|
|
#endif
|
|
|
|
|
/* If this one of script's fds? */
|
|
|
|
|
if (fd_in_FILEs(fd))
|
|
|
|
|
if (fd_in_HFILEs(fd))
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
if (sq) for (i = 0; sq[i].orig_fd >= 0; i++) {
|
|
|
|
@ -7512,7 +7550,7 @@ static int setup_redirects(struct command *prog, struct squirrel **sqp)
|
|
|
|
|
save_fd_on_redirect(redir->rd_fd, /*avoid:*/ 0, sqp);
|
|
|
|
|
/* for REDIRECT_HEREDOC2, rd_filename holds _contents_
|
|
|
|
|
* of the heredoc */
|
|
|
|
|
debug_printf_parse("set heredoc '%s'\n",
|
|
|
|
|
debug_printf_redir("set heredoc '%s'\n",
|
|
|
|
|
redir->rd_filename);
|
|
|
|
|
setup_heredoc(redir);
|
|
|
|
|
continue;
|
|
|
|
@ -7524,8 +7562,7 @@ static int setup_redirects(struct command *prog, struct squirrel **sqp)
|
|
|
|
|
int mode;
|
|
|
|
|
|
|
|
|
|
if (redir->rd_filename == NULL) {
|
|
|
|
|
/*
|
|
|
|
|
* Examples:
|
|
|
|
|
/* Examples:
|
|
|
|
|
* "cmd >" (no filename)
|
|
|
|
|
* "cmd > <file" (2nd redirect starts too early)
|
|
|
|
|
*/
|
|
|
|
@ -8706,7 +8743,7 @@ static NOINLINE int run_pipe(struct pipe *pi)
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
/* { list } */
|
|
|
|
|
debug_printf("non-subshell group\n");
|
|
|
|
|
debug_printf_exec("non-subshell group\n");
|
|
|
|
|
rcode = 1; /* exitcode if redir failed */
|
|
|
|
|
if (setup_redirects(command, &squirrel) == 0) {
|
|
|
|
|
debug_printf_exec(": run_list\n");
|
|
|
|
@ -9871,14 +9908,13 @@ int hush_main(int argc, char **argv)
|
|
|
|
|
|
|
|
|
|
/* If we are login shell... */
|
|
|
|
|
if (flags & OPT_login) {
|
|
|
|
|
FILE *input;
|
|
|
|
|
HFILE *input;
|
|
|
|
|
debug_printf("sourcing /etc/profile\n");
|
|
|
|
|
input = fopen_for_read("/etc/profile");
|
|
|
|
|
input = hfopen("/etc/profile");
|
|
|
|
|
if (input != NULL) {
|
|
|
|
|
remember_FILE(input);
|
|
|
|
|
install_special_sighandlers();
|
|
|
|
|
parse_and_run_file(input);
|
|
|
|
|
fclose_and_forget(input);
|
|
|
|
|
hfclose(input);
|
|
|
|
|
}
|
|
|
|
|
/* bash: after sourcing /etc/profile,
|
|
|
|
|
* tries to source (in the given order):
|
|
|
|
@ -9891,7 +9927,7 @@ int hush_main(int argc, char **argv)
|
|
|
|
|
|
|
|
|
|
/* -s is: hush -s ARGV1 ARGV2 (no SCRIPT) */
|
|
|
|
|
if (!(flags & OPT_s) && G.global_argv[1]) {
|
|
|
|
|
FILE *input;
|
|
|
|
|
HFILE *input;
|
|
|
|
|
/*
|
|
|
|
|
* "bash <script>" (which is never interactive (unless -i?))
|
|
|
|
|
* sources $BASH_ENV here (without scanning $PATH).
|
|
|
|
@ -9902,13 +9938,15 @@ int hush_main(int argc, char **argv)
|
|
|
|
|
G.global_argv++;
|
|
|
|
|
debug_printf("running script '%s'\n", G.global_argv[0]);
|
|
|
|
|
xfunc_error_retval = 127; /* for "hush /does/not/exist" case */
|
|
|
|
|
input = xfopen_for_read(G.global_argv[0]);
|
|
|
|
|
input = hfopen(G.global_argv[0]);
|
|
|
|
|
if (!input) {
|
|
|
|
|
bb_simple_perror_msg_and_die(G.global_argv[0]);
|
|
|
|
|
}
|
|
|
|
|
xfunc_error_retval = 1;
|
|
|
|
|
remember_FILE(input);
|
|
|
|
|
install_special_sighandlers();
|
|
|
|
|
parse_and_run_file(input);
|
|
|
|
|
#if ENABLE_FEATURE_CLEAN_UP
|
|
|
|
|
fclose_and_forget(input);
|
|
|
|
|
hfclose(input);
|
|
|
|
|
#endif
|
|
|
|
|
goto final_return;
|
|
|
|
|
}
|
|
|
|
@ -10038,7 +10076,7 @@ int hush_main(int argc, char **argv)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
parse_and_run_file(stdin);
|
|
|
|
|
parse_and_run_file(hfopen(NULL)); /* stdin */
|
|
|
|
|
|
|
|
|
|
final_return:
|
|
|
|
|
hush_exit(G.last_exitcode);
|
|
|
|
@ -10849,7 +10887,7 @@ Test that VAR is a valid variable name?
|
|
|
|
|
static int FAST_FUNC builtin_source(char **argv)
|
|
|
|
|
{
|
|
|
|
|
char *arg_path, *filename;
|
|
|
|
|
FILE *input;
|
|
|
|
|
HFILE *input;
|
|
|
|
|
save_arg_t sv;
|
|
|
|
|
char *args_need_save;
|
|
|
|
|
#if ENABLE_HUSH_FUNCTIONS
|
|
|
|
@ -10873,10 +10911,10 @@ static int FAST_FUNC builtin_source(char **argv)
|
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
input = remember_FILE(fopen_or_warn(filename, "r"));
|
|
|
|
|
input = hfopen(filename);
|
|
|
|
|
free(arg_path);
|
|
|
|
|
if (!input) {
|
|
|
|
|
/* bb_perror_msg("%s", *argv); - done by fopen_or_warn */
|
|
|
|
|
bb_perror_msg("%s", filename);
|
|
|
|
|
/* POSIX: non-interactive shell should abort here,
|
|
|
|
|
* not merely fail. So far no one complained :)
|
|
|
|
|
*/
|
|
|
|
@ -10895,7 +10933,7 @@ static int FAST_FUNC builtin_source(char **argv)
|
|
|
|
|
/* "false; . ./empty_line; echo Zero:$?" should print 0 */
|
|
|
|
|
G.last_exitcode = 0;
|
|
|
|
|
parse_and_run_file(input);
|
|
|
|
|
fclose_and_forget(input);
|
|
|
|
|
hfclose(input);
|
|
|
|
|
|
|
|
|
|
if (args_need_save) /* can't use argv[1] instead: "shift" can mangle it */
|
|
|
|
|
restore_G_args(&sv, argv);
|
|
|
|
|