source: MondoRescue/branches/stable/mindi-busybox/shell/hush.c @ 1770

Last change on this file since 1770 was 1770, checked in by Bruno Cornec, 12 years ago
  • Better output for mindi-busybox revision
  • Remove dummy file created on NFS - report from Arnaud Tiger <arnaud.tiger_at_hp.com>
  • strace useful for debug
  • fix new versions for pb (2.0.0 for mindi and 1.7.2 for mindi-busybox)
  • fix build process for mindi-busybox + options used in that version (dd for label-partitions-as-necessary)
  • fix typo in label-partitions-as-necessary which doesn't seem to work
  • Update to busybox 1.7.2
  • perl is now required at restore time to support uuid swap partitions (and will be used for many other thigs

in the future for sure)

  • next mindi version will be 2.0.0 due to all the changes made in it (udev may break working distros)
  • small optimization in mindi on keyboard handling (one single find instead of multiple)
  • better interaction for USB device when launching mindi manually
  • attempt to automatically guess block disk size for ramdisk
  • fix typos in bkphw
  • Fix the remaining problem with UUID support for swap partitions
  • Updates mondoarchive man page for USB support
  • Adds preliminary Hardware support to mindi (Proliant SSSTK)
  • Tries to add udev support also for rhel4
  • Fix UUID support which was still broken.
  • Be conservative in test for the start-nfs script
  • Update config file for mindi-busybox for 1.7.2 migration
  • Try to run around a busybox bug (1.2.2 pb on inexistant links)
  • Add build content for mindi-busybox in pb
  • Remove distributions content for mindi-busybox
  • Fix a warning on inexistant raidtab
  • Solve problem on tmpfs in restore init (Problem of inexistant symlink and busybox)
  • Create MONDO_CACHE and use it everywhere + creation at start
  • Really never try to eject a USB device
  • Fix a issue with &> usage (replaced with 1> and 2>)
  • Adds magic file to depllist in order to have file working + ldd which helps for debugging issues
  • tty modes correct to avoid sh error messages
  • Use ext3 normally and not ext2 instead
  • USB device should be corrected after reading (take 1st part)
  • Adds a mount_USB_here function derived from mount_CDROM_here
  • usb detection place before /dev detection in device name at restore time
  • Fix when restoring from USB: media is asked in interactive mode
  • Adds USB support for mondorestore
  • mount_cdrom => mount_media
  • elilo.efi is now searched throughout /boot/efi and not in a fixed place as there is no standard
  • untar-and-softlink => untar (+ interface change)
  • suppress useless softlinks creation/removal in boot process
  • avoids udevd messages on groups
  • Increase # of disks to 99 as in mindi at restore time (should be a conf file parameter)
  • skip existing big file creation
  • seems to work correctly for USB mindi boot
  • Adds group and tty link to udev conf
  • Always load usb-torage (even 2.6) to initiate USB bus discovery
  • Better printing of messages
  • Attempt to fix a bug in supporting OpenSusE 10.3 kernel for initramfs (mindi may now use multiple regex for kernel initrd detection)
  • Links were not correctly done as non relative for modules in mindi
  • exclusion of modules denied now works
  • Also create modules in their ordinary place, so that classical modprobe works + copy modules.dep
  • Fix bugs for DENY_MODS handling
  • Add device /dev/console for udev
  • ide-generic should now really be excluded
  • Fix a bug in major number for tty
  • If udev then adds modprobe/insmod to rootfs
  • tty0 is also cretaed with udev
  • ide-generic put rather in DENY_MODS
  • udevd remove from deplist s handled in mindi directly
  • better default for mindi when using --usb
  • Handles dynamically linked busybox (in case we want to use it soon ;-)
  • Adds fixed devices to create for udev
  • ide-generic should not be part of the initrd when using libata v2
  • support a dynamically linked udev (case on Ubuntu 7.10 and Mandriva 2008.0 so should be quite generic) This will give incitation to move to dyn. linked binaries in the initrd which will help for other tasks (ia6 4)
  • Improvement in udev support (do not use cl options not available in busybox)
  • Udev in mindi
    • auto creation of the right links at boot time with udev-links.conf(from Mandriva 2008.0)
    • rework startup of udev as current makes kernel crash (from Mandriva 2008.0)
    • add support for 64 bits udev
  • Try to render MyInsmod? silent at boot time
  • Adds udev support (mandatory for newest distributions to avoid remapping of devices in a different way as on the original system)
  • We also need vaft format support for USB boot
  • Adds libusual support (Ubuntu 7.10 needs it for USB)
  • Improve Ubuntu/Debian? keyboard detection and support
  • pbinit adapted to new pb (0.8.10). Filtering of docs done in it
  • Suppress some mondo warnings and errors on USB again
  • Tries to fix lack of files in deb mindi package
  • Verify should now work for USB devices
  • More log/mesages improvement for USB support
  • - Supress g_erase_tmpdir_and_scratchdir
  • Improve some log messages for USB support
  • Try to improve install in mindi to avoid issues with isolinux.cfg not installed vene if in the pkg :-(
  • Improve mindi-busybox build
  • In conformity with pb 0.8.9
  • Add support for Ubuntu 7.10 in build process
  • Add USB Key button to Menu UI (CD streamer removed)
  • Attempt to fix error messages on tmp/scratch files at the end by removing those dir at the latest possible.
  • Fix a bug linked to the size of the -E param which could be used (Arnaud Tiger/René? Ribaud).
  • Integrate ~/.pbrc content into mondorescue.pb (required project-builder >= 0.8.7)
  • Put mondorescue in conformity with new pb filtering rules
  • Add USB support at restore time (no test done yet). New start-usb script PB varibale added where useful
  • Unmounting USB device before removal of temporary scratchdir
  • Stil refining USB copy back to mondo (one command was not executed)
  • No need to have the image subdor in the csratchdir when USB.
  • umount the USB partition before attempting to use it
  • Remove useless copy from mindi to mondo at end of USB handling

(risky merge, we are raising the limits of 2 diverging branches. The status of stable is not completely sure as such. Will need lots of tests, but it's not yet done :-()
(merge -r1692:1769 $SVN_M/branches/2.2.5)

File size: 106.1 KB
Line 
1/* vi: set sw=4 ts=4: */
2/*
3 * sh.c -- a prototype Bourne shell grammar parser
4 *      Intended to follow the original Thompson and Ritchie
5 *      "small and simple is beautiful" philosophy, which
6 *      incidentally is a good match to today's BusyBox.
7 *
8 * Copyright (C) 2000,2001  Larry Doolittle  <larry@doolittle.boa.org>
9 *
10 * Credits:
11 *      The parser routines proper are all original material, first
12 *      written Dec 2000 and Jan 2001 by Larry Doolittle.  The
13 *      execution engine, the builtins, and much of the underlying
14 *      support has been adapted from busybox-0.49pre's lash, which is
15 *      Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
16 *      written by Erik Andersen <andersen@codepoet.org>.  That, in turn,
17 *      is based in part on ladsh.c, by Michael K. Johnson and Erik W.
18 *      Troan, which they placed in the public domain.  I don't know
19 *      how much of the Johnson/Troan code has survived the repeated
20 *      rewrites.
21 *
22 * Other credits:
23 *      b_addchr() derived from similar w_addchar function in glibc-2.2
24 *      setup_redirect(), redirect_opt_num(), and big chunks of main()
25 *      and many builtins derived from contributions by Erik Andersen
26 *      miscellaneous bugfixes from Matt Kraai
27 *
28 * There are two big (and related) architecture differences between
29 * this parser and the lash parser.  One is that this version is
30 * actually designed from the ground up to understand nearly all
31 * of the Bourne grammar.  The second, consequential change is that
32 * the parser and input reader have been turned inside out.  Now,
33 * the parser is in control, and asks for input as needed.  The old
34 * way had the input reader in control, and it asked for parsing to
35 * take place as needed.  The new way makes it much easier to properly
36 * handle the recursion implicit in the various substitutions, especially
37 * across continuation lines.
38 *
39 * Bash grammar not implemented: (how many of these were in original sh?)
40 *      $_
41 *      ! negation operator for pipes
42 *      &> and >& redirection of stdout+stderr
43 *      Brace Expansion
44 *      Tilde Expansion
45 *      fancy forms of Parameter Expansion
46 *      aliases
47 *      Arithmetic Expansion
48 *      <(list) and >(list) Process Substitution
49 *      reserved words: case, esac, select, function
50 *      Here Documents ( << word )
51 *      Functions
52 * Major bugs:
53 *      job handling woefully incomplete and buggy (improved --vda)
54 *      reserved word execution woefully incomplete and buggy
55 * to-do:
56 *      port selected bugfixes from post-0.49 busybox lash - done?
57 *      finish implementing reserved words: for, while, until, do, done
58 *      change { and } from special chars to reserved words
59 *      builtins: break, continue, eval, return, set, trap, ulimit
60 *      test magic exec
61 *      handle children going into background
62 *      clean up recognition of null pipes
63 *      check setting of global_argc and global_argv
64 *      control-C handling, probably with longjmp
65 *      follow IFS rules more precisely, including update semantics
66 *      figure out what to do with backslash-newline
67 *      explain why we use signal instead of sigaction
68 *      propagate syntax errors, die on resource errors?
69 *      continuation lines, both explicit and implicit - done?
70 *      memory leak finding and plugging - done?
71 *      more testing, especially quoting rules and redirection
72 *      document how quoting rules not precisely followed for variable assignments
73 *      maybe change charmap[] to use 2-bit entries
74 *      (eventually) remove all the printf's
75 *
76 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
77 */
78
79
80#include <glob.h>      /* glob, of course */
81#include <getopt.h>    /* should be pretty obvious */
82/* #include <dmalloc.h> */
83
84extern char **environ; /* This is in <unistd.h>, but protected with __USE_GNU */
85
86#include "busybox.h" /* for struct bb_applet */
87
88
89/* If you comment out one of these below, it will be #defined later
90 * to perform debug printfs to stderr: */
91#define debug_printf(...)        do {} while (0)
92/* Finer-grained debug switches */
93#define debug_printf_parse(...)  do {} while (0)
94#define debug_print_tree(a, b)   do {} while (0)
95#define debug_printf_exec(...)   do {} while (0)
96#define debug_printf_jobs(...)   do {} while (0)
97#define debug_printf_expand(...) do {} while (0)
98#define debug_printf_clean(...)  do {} while (0)
99
100#ifndef debug_printf
101#define debug_printf(...) fprintf(stderr, __VA_ARGS__)
102#endif
103
104#ifndef debug_printf_parse
105#define debug_printf_parse(...) fprintf(stderr, __VA_ARGS__)
106#endif
107
108#ifndef debug_printf_exec
109#define debug_printf_exec(...) fprintf(stderr, __VA_ARGS__)
110#endif
111
112#ifndef debug_printf_jobs
113#define debug_printf_jobs(...) fprintf(stderr, __VA_ARGS__)
114#define DEBUG_SHELL_JOBS 1
115#endif
116
117#ifndef debug_printf_expand
118#define debug_printf_expand(...) fprintf(stderr, __VA_ARGS__)
119#define DEBUG_EXPAND 1
120#endif
121
122/* Keep unconditionally on for now */
123#define ENABLE_HUSH_DEBUG 1
124
125#ifndef debug_printf_clean
126/* broken, of course, but OK for testing */
127static const char *indenter(int i)
128{
129    static const char blanks[] ALIGN1 =
130        "                                    ";
131    return &blanks[sizeof(blanks) - i - 1];
132}
133#define debug_printf_clean(...) fprintf(stderr, __VA_ARGS__)
134#define DEBUG_CLEAN 1
135#endif
136
137
138#if !ENABLE_HUSH_INTERACTIVE
139#undef ENABLE_FEATURE_EDITING
140#define ENABLE_FEATURE_EDITING 0
141#undef ENABLE_FEATURE_EDITING_FANCY_PROMPT
142#define ENABLE_FEATURE_EDITING_FANCY_PROMPT 0
143#endif
144
145#define SPECIAL_VAR_SYMBOL   3
146
147#define PARSEFLAG_EXIT_FROM_LOOP 1
148#define PARSEFLAG_SEMICOLON      (1 << 1)  /* symbol ';' is special for parser */
149#define PARSEFLAG_REPARSING      (1 << 2)  /* >= 2nd pass */
150
151typedef enum {
152    REDIRECT_INPUT     = 1,
153    REDIRECT_OVERWRITE = 2,
154    REDIRECT_APPEND    = 3,
155    REDIRECT_HEREIS    = 4,
156    REDIRECT_IO        = 5
157} redir_type;
158
159/* The descrip member of this structure is only used to make debugging
160 * output pretty */
161static const struct {
162    int mode;
163    signed char default_fd;
164    char descrip[3];
165} redir_table[] = {
166    { 0,                         0, "()" },
167    { O_RDONLY,                  0, "<"  },
168    { O_CREAT|O_TRUNC|O_WRONLY,  1, ">"  },
169    { O_CREAT|O_APPEND|O_WRONLY, 1, ">>" },
170    { O_RDONLY,                 -1, "<<" },
171    { O_RDWR,                    1, "<>" }
172};
173
174typedef enum {
175    PIPE_SEQ = 1,
176    PIPE_AND = 2,
177    PIPE_OR  = 3,
178    PIPE_BG  = 4,
179} pipe_style;
180
181/* might eventually control execution */
182typedef enum {
183    RES_NONE  = 0,
184#if ENABLE_HUSH_IF
185    RES_IF    = 1,
186    RES_THEN  = 2,
187    RES_ELIF  = 3,
188    RES_ELSE  = 4,
189    RES_FI    = 5,
190#endif
191#if ENABLE_HUSH_LOOPS
192    RES_FOR   = 6,
193    RES_WHILE = 7,
194    RES_UNTIL = 8,
195    RES_DO    = 9,
196    RES_DONE  = 10,
197    RES_IN    = 11,
198#endif
199    RES_XXXX  = 12,
200    RES_SNTX  = 13
201} reserved_style;
202enum {
203    FLAG_END   = (1 << RES_NONE ),
204#if ENABLE_HUSH_IF
205    FLAG_IF    = (1 << RES_IF   ),
206    FLAG_THEN  = (1 << RES_THEN ),
207    FLAG_ELIF  = (1 << RES_ELIF ),
208    FLAG_ELSE  = (1 << RES_ELSE ),
209    FLAG_FI    = (1 << RES_FI   ),
210#endif
211#if ENABLE_HUSH_LOOPS
212    FLAG_FOR   = (1 << RES_FOR  ),
213    FLAG_WHILE = (1 << RES_WHILE),
214    FLAG_UNTIL = (1 << RES_UNTIL),
215    FLAG_DO    = (1 << RES_DO   ),
216    FLAG_DONE  = (1 << RES_DONE ),
217    FLAG_IN    = (1 << RES_IN   ),
218#endif
219    FLAG_START = (1 << RES_XXXX ),
220};
221
222/* This holds pointers to the various results of parsing */
223struct p_context {
224    struct child_prog *child;
225    struct pipe *list_head;
226    struct pipe *pipe;
227    struct redir_struct *pending_redirect;
228    smallint res_w;
229    smallint parse_type;        /* bitmask of PARSEFLAG_xxx, defines type of parser : ";$" common or special symbol */
230    int old_flag;               /* bitmask of FLAG_xxx, for figuring out valid reserved words */
231    struct p_context *stack;
232    /* How about quoting status? */
233};
234
235struct redir_struct {
236    struct redir_struct *next;  /* pointer to the next redirect in the list */
237    redir_type type;            /* type of redirection */
238    int fd;                     /* file descriptor being redirected */
239    int dup;                    /* -1, or file descriptor being duplicated */
240    glob_t word;                /* *word.gl_pathv is the filename */
241};
242
243struct child_prog {
244    pid_t pid;                  /* 0 if exited */
245    char **argv;                /* program name and arguments */
246    struct pipe *group;         /* if non-NULL, first in group or subshell */
247    smallint subshell;          /* flag, non-zero if group must be forked */
248    smallint is_stopped;        /* is the program currently running? */
249    struct redir_struct *redirects; /* I/O redirections */
250    glob_t glob_result;         /* result of parameter globbing */
251    struct pipe *family;        /* pointer back to the child's parent pipe */
252    //sp counting seems to be broken... so commented out, grep for '//sp:'
253    //sp: int sp;               /* number of SPECIAL_VAR_SYMBOL */
254    //seems to be unused, grep for '//pt:'
255    //pt: int parse_type;
256};
257/* argv vector may contain variable references (^Cvar^C, ^C0^C etc)
258 * and on execution these are substituted with their values.
259 * Substitution can make _several_ words out of one argv[n]!
260 * Example: argv[0]=='.^C*^C.' here: echo .$*.
261 */
262
263struct pipe {
264    struct pipe *next;
265    int num_progs;              /* total number of programs in job */
266    int running_progs;          /* number of programs running (not exited) */
267    int stopped_progs;          /* number of programs alive, but stopped */
268#if ENABLE_HUSH_JOB
269    int jobid;                  /* job number */
270    pid_t pgrp;                 /* process group ID for the job */
271    char *cmdtext;              /* name of job */
272#endif
273    char *cmdbuf;               /* buffer various argv's point into */
274    struct child_prog *progs;   /* array of commands in pipe */
275    int job_context;            /* bitmask defining current context */
276    smallint followup;          /* PIPE_BG, PIPE_SEQ, PIPE_OR, PIPE_AND */
277    smallint res_word;          /* needed for if, for, while, until... */
278};
279
280struct close_me {
281    struct close_me *next;
282    int fd;
283};
284
285/* On program start, environ points to initial environment.
286 * putenv adds new pointers into it, unsetenv removes them.
287 * Neither of these (de)allocates the strings.
288 * setenv allocates new strings in malloc space and does putenv,
289 * and thus setenv is unusable (leaky) for shell's purposes */
290#define setenv(...) setenv_is_leaky_dont_use()
291struct variable {
292    struct variable *next;
293    char *varstr;        /* points to "name=" portion */
294    int max_len;         /* if > 0, name is part of initial env; else name is malloced */
295    smallint flg_export; /* putenv should be done on this var */
296    smallint flg_read_only;
297};
298
299typedef struct {
300    char *data;
301    int length;
302    int maxlen;
303    int quote;
304    int nonnull;
305} o_string;
306#define NULL_O_STRING {NULL,0,0,0,0}
307/* used for initialization: o_string foo = NULL_O_STRING; */
308
309/* I can almost use ordinary FILE *.  Is open_memstream() universally
310 * available?  Where is it documented? */
311struct in_str {
312    const char *p;
313    /* eof_flag=1: last char in ->p is really an EOF */
314    char eof_flag; /* meaningless if ->p == NULL */
315    char peek_buf[2];
316#if ENABLE_HUSH_INTERACTIVE
317    smallint promptme;
318    smallint promptmode; /* 0: PS1, 1: PS2 */
319#endif
320    FILE *file;
321    int (*get) (struct in_str *);
322    int (*peek) (struct in_str *);
323};
324#define b_getch(input) ((input)->get(input))
325#define b_peek(input) ((input)->peek(input))
326
327enum {
328    CHAR_ORDINARY           = 0,
329    CHAR_ORDINARY_IF_QUOTED = 1, /* example: *, # */
330    CHAR_IFS                = 2, /* treated as ordinary if quoted */
331    CHAR_SPECIAL            = 3, /* example: $ */
332};
333
334#define HUSH_VER_STR "0.02"
335
336/* "Globals" within this file */
337
338/* Sorted roughly by size (smaller offsets == smaller code) */
339struct globals {
340#if ENABLE_HUSH_INTERACTIVE
341    /* 'interactive_fd' is a fd# open to ctty, if we have one
342     * _AND_ if we decided to act interactively */
343    int interactive_fd;
344    const char *PS1;
345    const char *PS2;
346#endif
347#if ENABLE_FEATURE_EDITING
348    line_input_t *line_input_state;
349#endif
350#if ENABLE_HUSH_JOB
351    int run_list_level;
352    pid_t saved_task_pgrp;
353    pid_t saved_tty_pgrp;
354    int last_jobid;
355    struct pipe *job_list;
356    struct pipe *toplevel_list;
357    smallint ctrl_z_flag;
358#endif
359    smallint fake_mode;
360    /* these three support $?, $#, and $1 */
361    char **global_argv;
362    int global_argc;
363    int last_return_code;
364    const char *ifs;
365    struct close_me *close_me_head;
366    const char *cwd;
367    unsigned last_bg_pid;
368    struct variable *top_var; /* = &shell_ver (set in main()) */
369    struct variable shell_ver;
370#if ENABLE_FEATURE_SH_STANDALONE
371    struct nofork_save_area nofork_save;
372#endif
373#if ENABLE_HUSH_JOB
374    sigjmp_buf toplevel_jb;
375#endif
376    unsigned char charmap[256];
377    char user_input_buf[ENABLE_FEATURE_EDITING ? BUFSIZ : 2];
378};
379
380#define G (*ptr_to_globals)
381
382#if !ENABLE_HUSH_INTERACTIVE
383enum { interactive_fd = 0 };
384#endif
385#if !ENABLE_HUSH_JOB
386enum { run_list_level = 0 };
387#endif
388
389#if ENABLE_HUSH_INTERACTIVE
390#define interactive_fd   (G.interactive_fd  )
391#define PS1              (G.PS1             )
392#define PS2              (G.PS2             )
393#endif
394#if ENABLE_FEATURE_EDITING
395#define line_input_state (G.line_input_state)
396#endif
397#if ENABLE_HUSH_JOB
398#define run_list_level   (G.run_list_level  )
399#define saved_task_pgrp  (G.saved_task_pgrp )
400#define saved_tty_pgrp   (G.saved_tty_pgrp  )
401#define last_jobid       (G.last_jobid      )
402#define job_list         (G.job_list        )
403#define toplevel_list    (G.toplevel_list   )
404#define toplevel_jb      (G.toplevel_jb     )
405#define ctrl_z_flag      (G.ctrl_z_flag     )
406#endif /* JOB */
407#define global_argv      (G.global_argv     )
408#define global_argc      (G.global_argc     )
409#define last_return_code (G.last_return_code)
410#define ifs              (G.ifs             )
411#define fake_mode        (G.fake_mode       )
412#define close_me_head    (G.close_me_head   )
413#define cwd              (G.cwd             )
414#define last_bg_pid      (G.last_bg_pid     )
415#define top_var          (G.top_var         )
416#define shell_ver        (G.shell_ver       )
417#if ENABLE_FEATURE_SH_STANDALONE
418#define nofork_save      (G.nofork_save     )
419#endif
420#if ENABLE_HUSH_JOB
421#define toplevel_jb      (G.toplevel_jb     )
422#endif
423#define charmap          (G.charmap         )
424#define user_input_buf   (G.user_input_buf  )
425
426
427#define B_CHUNK  100
428#define B_NOSPAC 1
429#define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n"
430
431#if 1
432/* Normal */
433static void syntax(const char *msg)
434{
435    /* Was using fancy stuff:
436     * (interactive_fd ? bb_error_msg : bb_error_msg_and_die)(...params...)
437     * but it SEGVs. ?! Oh well... explicit temp ptr works around that */
438    void (*fp)(const char *s, ...);
439
440    fp = (interactive_fd ? bb_error_msg : bb_error_msg_and_die);
441    fp(msg ? "%s: %s" : "syntax error", "syntax error", msg);
442}
443
444#else
445/* Debug */
446static void syntax_lineno(int line)
447{
448    void (*fp)(const char *s, ...);
449
450    fp = (interactive_fd ? bb_error_msg : bb_error_msg_and_die);
451    fp("syntax error hush.c:%d", line);
452}
453#define syntax(str) syntax_lineno(__LINE__)
454#endif
455
456/* Index of subroutines: */
457/*   function prototypes for builtins */
458static int builtin_cd(char **argv);
459static int builtin_eval(char **argv);
460static int builtin_exec(char **argv);
461static int builtin_exit(char **argv);
462static int builtin_export(char **argv);
463#if ENABLE_HUSH_JOB
464static int builtin_fg_bg(char **argv);
465static int builtin_jobs(char **argv);
466#endif
467#if ENABLE_HUSH_HELP
468static int builtin_help(char **argv);
469#endif
470static int builtin_pwd(char **argv);
471static int builtin_read(char **argv);
472static int builtin_set(char **argv);
473static int builtin_shift(char **argv);
474static int builtin_source(char **argv);
475static int builtin_umask(char **argv);
476static int builtin_unset(char **argv);
477//static int builtin_not_written(char **argv);
478/*   o_string manipulation: */
479static int b_check_space(o_string *o, int len);
480static int b_addchr(o_string *o, int ch);
481static void b_reset(o_string *o);
482static int b_addqchr(o_string *o, int ch, int quote);
483/*  in_str manipulations: */
484static int static_get(struct in_str *i);
485static int static_peek(struct in_str *i);
486static int file_get(struct in_str *i);
487static int file_peek(struct in_str *i);
488static void setup_file_in_str(struct in_str *i, FILE *f);
489static void setup_string_in_str(struct in_str *i, const char *s);
490/*  close_me manipulations: */
491static void mark_open(int fd);
492static void mark_closed(int fd);
493static void close_all(void);
494/*  "run" the final data structures: */
495#if !defined(DEBUG_CLEAN)
496#define free_pipe_list(head, indent) free_pipe_list(head)
497#define free_pipe(pi, indent)        free_pipe(pi)
498#endif
499static int free_pipe_list(struct pipe *head, int indent);
500static int free_pipe(struct pipe *pi, int indent);
501/*  really run the final data structures: */
502static int setup_redirects(struct child_prog *prog, int squirrel[]);
503static int run_list_real(struct pipe *pi);
504static void pseudo_exec_argv(char **argv) ATTRIBUTE_NORETURN;
505static void pseudo_exec(struct child_prog *child) ATTRIBUTE_NORETURN;
506static int run_pipe_real(struct pipe *pi);
507/*   extended glob support: */
508static int globhack(const char *src, int flags, glob_t *pglob);
509static int glob_needed(const char *s);
510static int xglob(o_string *dest, int flags, glob_t *pglob);
511/*   variable assignment: */
512static int is_assignment(const char *s);
513/*   data structure manipulation: */
514static int setup_redirect(struct p_context *ctx, int fd, redir_type style, struct in_str *input);
515static void initialize_context(struct p_context *ctx);
516static int done_word(o_string *dest, struct p_context *ctx);
517static int done_command(struct p_context *ctx);
518static int done_pipe(struct p_context *ctx, pipe_style type);
519/*   primary string parsing: */
520static int redirect_dup_num(struct in_str *input);
521static int redirect_opt_num(o_string *o);
522#if ENABLE_HUSH_TICK
523static int process_command_subs(o_string *dest, struct p_context *ctx, struct in_str *input, const char *subst_end);
524#endif
525static int parse_group(o_string *dest, struct p_context *ctx, struct in_str *input, int ch);
526static const char *lookup_param(const char *src);
527static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input);
528static int parse_stream(o_string *dest, struct p_context *ctx, struct in_str *input0, const char *end_trigger);
529/*   setup: */
530static int parse_and_run_stream(struct in_str *inp, int parse_flag);
531static int parse_and_run_string(const char *s, int parse_flag);
532static int parse_and_run_file(FILE *f);
533/*   job management: */
534static int checkjobs(struct pipe* fg_pipe);
535#if ENABLE_HUSH_JOB
536static int checkjobs_and_fg_shell(struct pipe* fg_pipe);
537static void insert_bg_job(struct pipe *pi);
538static void remove_bg_job(struct pipe *pi);
539static void delete_finished_bg_job(struct pipe *pi);
540#else
541int checkjobs_and_fg_shell(struct pipe* fg_pipe); /* never called */
542#endif
543/*     local variable support */
544static char **expand_strvec_to_strvec(char **argv);
545/* used for eval */
546static char *expand_strvec_to_string(char **argv);
547/* used for expansion of right hand of assignments */
548static char *expand_string_to_string(const char *str);
549static struct variable *get_local_var(const char *name);
550static int set_local_var(char *str, int flg_export);
551static void unset_local_var(const char *name);
552
553/* Table of built-in functions.  They can be forked or not, depending on
554 * context: within pipes, they fork.  As simple commands, they do not.
555 * When used in non-forking context, they can change global variables
556 * in the parent shell process.  If forked, of course they cannot.
557 * For example, 'unset foo | whatever' will parse and run, but foo will
558 * still be set at the end. */
559struct built_in_command {
560    const char *cmd;                /* name */
561    int (*function) (char **argv);  /* function ptr */
562#if ENABLE_HUSH_HELP
563    const char *descr;              /* description */
564#define BLTIN(cmd, func, help) { cmd, func, help }
565#else
566#define BLTIN(cmd, func, help) { cmd, func }
567#endif
568};
569
570static const struct built_in_command bltins[] = {
571#if ENABLE_HUSH_JOB
572    BLTIN("bg"    , builtin_fg_bg, "Resume a job in the background"),
573#endif
574//  BLTIN("break" , builtin_not_written, "Exit for, while or until loop"),
575    BLTIN("cd"    , builtin_cd, "Change working directory"),
576//  BLTIN("continue", builtin_not_written, "Continue for, while or until loop"),
577    BLTIN("eval"  , builtin_eval, "Construct and run shell command"),
578    BLTIN("exec"  , builtin_exec, "Exec command, replacing this shell with the exec'd process"),
579    BLTIN("exit"  , builtin_exit, "Exit from shell"),
580    BLTIN("export", builtin_export, "Set environment variable"),
581#if ENABLE_HUSH_JOB
582    BLTIN("fg"    , builtin_fg_bg, "Bring job into the foreground"),
583    BLTIN("jobs"  , builtin_jobs, "Lists the active jobs"),
584#endif
585// TODO: remove pwd? we have it as an applet...
586    BLTIN("pwd"   , builtin_pwd, "Print current directory"),
587    BLTIN("read"  , builtin_read, "Input environment variable"),
588//  BLTIN("return", builtin_not_written, "Return from a function"),
589    BLTIN("set"   , builtin_set, "Set/unset shell local variables"),
590    BLTIN("shift" , builtin_shift, "Shift positional parameters"),
591//  BLTIN("trap"  , builtin_not_written, "Trap signals"),
592//  BLTIN("ulimit", builtin_not_written, "Controls resource limits"),
593    BLTIN("umask" , builtin_umask, "Sets file creation mask"),
594    BLTIN("unset" , builtin_unset, "Unset environment variable"),
595    BLTIN("."     , builtin_source, "Source-in and run commands in a file"),
596#if ENABLE_HUSH_HELP
597    BLTIN("help"  , builtin_help, "List shell built-in commands"),
598#endif
599    BLTIN(NULL, NULL, NULL)
600};
601
602#if ENABLE_HUSH_JOB
603
604/* move to libbb? */
605static void signal_SA_RESTART(int sig, void (*handler)(int))
606{
607    struct sigaction sa;
608    sa.sa_handler = handler;
609    sa.sa_flags = SA_RESTART;
610    sigemptyset(&sa.sa_mask);
611    sigaction(sig, &sa, NULL);
612}
613
614/* Signals are grouped, we handle them in batches */
615static void set_fatal_sighandler(void (*handler)(int))
616{
617    signal(SIGILL , handler);
618    signal(SIGTRAP, handler);
619    signal(SIGABRT, handler);
620    signal(SIGFPE , handler);
621    signal(SIGBUS , handler);
622    signal(SIGSEGV, handler);
623    /* bash 3.2 seems to handle these just like 'fatal' ones */
624    signal(SIGHUP , handler);
625    signal(SIGPIPE, handler);
626    signal(SIGALRM, handler);
627}
628static void set_jobctrl_sighandler(void (*handler)(int))
629{
630    signal(SIGTSTP, handler);
631    signal(SIGTTIN, handler);
632    signal(SIGTTOU, handler);
633}
634static void set_misc_sighandler(void (*handler)(int))
635{
636    signal(SIGINT , handler);
637    signal(SIGQUIT, handler);
638    signal(SIGTERM, handler);
639}
640/* SIGCHLD is special and handled separately */
641
642static void set_every_sighandler(void (*handler)(int))
643{
644    set_fatal_sighandler(handler);
645    set_jobctrl_sighandler(handler);
646    set_misc_sighandler(handler);
647    signal(SIGCHLD, handler);
648}
649
650static void handler_ctrl_c(int sig)
651{
652    debug_printf_jobs("got sig %d\n", sig);
653// as usual we can have all kinds of nasty problems with leaked malloc data here
654    siglongjmp(toplevel_jb, 1);
655}
656
657static void handler_ctrl_z(int sig)
658{
659    pid_t pid;
660
661    debug_printf_jobs("got tty sig %d in pid %d\n", sig, getpid());
662    pid = fork();
663    if (pid < 0) /* can't fork. Pretend there was no ctrl-Z */
664        return;
665    ctrl_z_flag = 1;
666    if (!pid) { /* child */
667        setpgrp();
668        debug_printf_jobs("set pgrp for child %d ok\n", getpid());
669        set_every_sighandler(SIG_DFL);
670        raise(SIGTSTP); /* resend TSTP so that child will be stopped */
671        debug_printf_jobs("returning in child\n");
672        /* return to nofork, it will eventually exit now,
673         * not return back to shell */
674        return;
675    }
676    /* parent */
677    /* finish filling up pipe info */
678    toplevel_list->pgrp = pid; /* child is in its own pgrp */
679    toplevel_list->progs[0].pid = pid;
680    /* parent needs to longjmp out of running nofork.
681     * we will "return" exitcode 0, with child put in background */
682// as usual we can have all kinds of nasty problems with leaked malloc data here
683    debug_printf_jobs("siglongjmp in parent\n");
684    siglongjmp(toplevel_jb, 1);
685}
686
687/* Restores tty foreground process group, and exits.
688 * May be called as signal handler for fatal signal
689 * (will faithfully resend signal to itself, producing correct exit state)
690 * or called directly with -EXITCODE.
691 * We also call it if xfunc is exiting. */
692static void sigexit(int sig) ATTRIBUTE_NORETURN;
693static void sigexit(int sig)
694{
695    sigset_t block_all;
696
697    /* Disable all signals: job control, SIGPIPE, etc. */
698    sigfillset(&block_all);
699    sigprocmask(SIG_SETMASK, &block_all, NULL);
700
701    if (interactive_fd)
702        tcsetpgrp(interactive_fd, saved_tty_pgrp);
703
704    /* Not a signal, just exit */
705    if (sig <= 0)
706        _exit(- sig);
707
708    /* Enable only this sig and kill ourself with it */
709    signal(sig, SIG_DFL);
710    sigdelset(&block_all, sig);
711    sigprocmask(SIG_SETMASK, &block_all, NULL);
712    raise(sig);
713    _exit(1); /* Should not reach it */
714}
715
716/* Restores tty foreground process group, and exits. */
717static void hush_exit(int exitcode) ATTRIBUTE_NORETURN;
718static void hush_exit(int exitcode)
719{
720    fflush(NULL); /* flush all streams */
721    sigexit(- (exitcode & 0xff));
722}
723
724#else /* !JOB */
725
726#define set_fatal_sighandler(handler)   ((void)0)
727#define set_jobctrl_sighandler(handler) ((void)0)
728#define set_misc_sighandler(handler)    ((void)0)
729#define hush_exit(e)                    exit(e)
730
731#endif /* JOB */
732
733
734static const char *set_cwd(void)
735{
736    if (cwd == bb_msg_unknown)
737        cwd = NULL;     /* xrealloc_getcwd_or_warn(arg) calls free(arg)! */
738    cwd = xrealloc_getcwd_or_warn((char *)cwd);
739    if (!cwd)
740        cwd = bb_msg_unknown;
741    return cwd;
742}
743
744/* built-in 'eval' handler */
745static int builtin_eval(char **argv)
746{
747    int rcode = EXIT_SUCCESS;
748
749    if (argv[1]) {
750        char *str = expand_strvec_to_string(argv + 1);
751        parse_and_run_string(str, PARSEFLAG_EXIT_FROM_LOOP |
752                    PARSEFLAG_SEMICOLON);
753        free(str);
754        rcode = last_return_code;
755    }
756    return rcode;
757}
758
759/* built-in 'cd <path>' handler */
760static int builtin_cd(char **argv)
761{
762    const char *newdir;
763    if (argv[1] == NULL)
764        newdir = getenv("HOME") ? : "/";
765    else
766        newdir = argv[1];
767    if (chdir(newdir)) {
768        printf("cd: %s: %s\n", newdir, strerror(errno));
769        return EXIT_FAILURE;
770    }
771    set_cwd();
772    return EXIT_SUCCESS;
773}
774
775/* built-in 'exec' handler */
776static int builtin_exec(char **argv)
777{
778    if (argv[1] == NULL)
779        return EXIT_SUCCESS;   /* Really? */
780    pseudo_exec_argv(argv + 1);
781    /* never returns */
782}
783
784/* built-in 'exit' handler */
785static int builtin_exit(char **argv)
786{
787// TODO: bash does it ONLY on top-level sh exit (+interacive only?)
788    //puts("exit"); /* bash does it */
789// TODO: warn if we have background jobs: "There are stopped jobs"
790// On second consecutive 'exit', exit anyway.
791
792    if (argv[1] == NULL)
793        hush_exit(last_return_code);
794    /* mimic bash: exit 123abc == exit 255 + error msg */
795    xfunc_error_retval = 255;
796    /* bash: exit -2 == exit 254, no error msg */
797    hush_exit(xatoi(argv[1]) & 0xff);
798}
799
800/* built-in 'export VAR=value' handler */
801static int builtin_export(char **argv)
802{
803    const char *value;
804    char *name = argv[1];
805
806    if (name == NULL) {
807        // TODO:
808        // ash emits: export VAR='VAL'
809        // bash: declare -x VAR="VAL"
810        // (both also escape as needed (quotes, $, etc))
811        char **e = environ;
812        if (e)
813            while (*e)
814                puts(*e++);
815        return EXIT_SUCCESS;
816    }
817
818    value = strchr(name, '=');
819    if (!value) {
820        /* They are exporting something without a =VALUE */
821        struct variable *var;
822
823        var = get_local_var(name);
824        if (var) {
825            var->flg_export = 1;
826            putenv(var->varstr);
827        }
828        /* bash does not return an error when trying to export
829         * an undefined variable.  Do likewise. */
830        return EXIT_SUCCESS;
831    }
832
833    set_local_var(xstrdup(name), 1);
834    return EXIT_SUCCESS;
835}
836
837#if ENABLE_HUSH_JOB
838/* built-in 'fg' and 'bg' handler */
839static int builtin_fg_bg(char **argv)
840{
841    int i, jobnum;
842    struct pipe *pi;
843
844    if (!interactive_fd)
845        return EXIT_FAILURE;
846    /* If they gave us no args, assume they want the last backgrounded task */
847    if (!argv[1]) {
848        for (pi = job_list; pi; pi = pi->next) {
849            if (pi->jobid == last_jobid) {
850                goto found;
851            }
852        }
853        bb_error_msg("%s: no current job", argv[0]);
854        return EXIT_FAILURE;
855    }
856    if (sscanf(argv[1], "%%%d", &jobnum) != 1) {
857        bb_error_msg("%s: bad argument '%s'", argv[0], argv[1]);
858        return EXIT_FAILURE;
859    }
860    for (pi = job_list; pi; pi = pi->next) {
861        if (pi->jobid == jobnum) {
862            goto found;
863        }
864    }
865    bb_error_msg("%s: %d: no such job", argv[0], jobnum);
866    return EXIT_FAILURE;
867 found:
868    // TODO: bash prints a string representation
869    // of job being foregrounded (like "sleep 1 | cat")
870    if (*argv[0] == 'f') {
871        /* Put the job into the foreground.  */
872        tcsetpgrp(interactive_fd, pi->pgrp);
873    }
874
875    /* Restart the processes in the job */
876    debug_printf_jobs("reviving %d procs, pgrp %d\n", pi->num_progs, pi->pgrp);
877    for (i = 0; i < pi->num_progs; i++) {
878        debug_printf_jobs("reviving pid %d\n", pi->progs[i].pid);
879        pi->progs[i].is_stopped = 0;
880    }
881    pi->stopped_progs = 0;
882
883    i = kill(- pi->pgrp, SIGCONT);
884    if (i < 0) {
885        if (errno == ESRCH) {
886            delete_finished_bg_job(pi);
887            return EXIT_SUCCESS;
888        } else {
889            bb_perror_msg("kill (SIGCONT)");
890        }
891    }
892
893    if (*argv[0] == 'f') {
894        remove_bg_job(pi);
895        return checkjobs_and_fg_shell(pi);
896    }
897    return EXIT_SUCCESS;
898}
899#endif
900
901/* built-in 'help' handler */
902#if ENABLE_HUSH_HELP
903static int builtin_help(char **argv ATTRIBUTE_UNUSED)
904{
905    const struct built_in_command *x;
906
907    printf("\nBuilt-in commands:\n");
908    printf("-------------------\n");
909    for (x = bltins; x->cmd; x++) {
910        printf("%s\t%s\n", x->cmd, x->descr);
911    }
912    printf("\n\n");
913    return EXIT_SUCCESS;
914}
915#endif
916
917#if ENABLE_HUSH_JOB
918/* built-in 'jobs' handler */
919static int builtin_jobs(char **argv ATTRIBUTE_UNUSED)
920{
921    struct pipe *job;
922    const char *status_string;
923
924    for (job = job_list; job; job = job->next) {
925        if (job->running_progs == job->stopped_progs)
926            status_string = "Stopped";
927        else
928            status_string = "Running";
929
930        printf(JOB_STATUS_FORMAT, job->jobid, status_string, job->cmdtext);
931    }
932    return EXIT_SUCCESS;
933}
934#endif
935
936/* built-in 'pwd' handler */
937static int builtin_pwd(char **argv ATTRIBUTE_UNUSED)
938{
939    puts(set_cwd());
940    return EXIT_SUCCESS;
941}
942
943/* built-in 'read VAR' handler */
944static int builtin_read(char **argv)
945{
946    char *string;
947    const char *name = argv[1] ? argv[1] : "REPLY";
948
949    string = xmalloc_reads(STDIN_FILENO, xasprintf("%s=", name));
950    return set_local_var(string, 0);
951}
952
953/* built-in 'set [VAR=value]' handler */
954static int builtin_set(char **argv)
955{
956    char *temp = argv[1];
957    struct variable *e;
958
959    if (temp == NULL)
960        for (e = top_var; e; e = e->next)
961            puts(e->varstr);
962    else
963        set_local_var(xstrdup(temp), 0);
964
965    return EXIT_SUCCESS;
966}
967
968
969/* Built-in 'shift' handler */
970static int builtin_shift(char **argv)
971{
972    int n = 1;
973    if (argv[1]) {
974        n = atoi(argv[1]);
975    }
976    if (n >= 0 && n < global_argc) {
977        global_argv[n] = global_argv[0];
978        global_argc -= n;
979        global_argv += n;
980        return EXIT_SUCCESS;
981    }
982    return EXIT_FAILURE;
983}
984
985/* Built-in '.' handler (read-in and execute commands from file) */
986static int builtin_source(char **argv)
987{
988    FILE *input;
989    int status;
990
991    if (argv[1] == NULL)
992        return EXIT_FAILURE;
993
994    /* XXX search through $PATH is missing */
995    input = fopen(argv[1], "r");
996    if (!input) {
997        bb_error_msg("cannot open '%s'", argv[1]);
998        return EXIT_FAILURE;
999    }
1000
1001    /* Now run the file */
1002    /* XXX argv and argc are broken; need to save old global_argv
1003     * (pointer only is OK!) on this stack frame,
1004     * set global_argv=argv+1, recurse, and restore. */
1005    mark_open(fileno(input));
1006    status = parse_and_run_file(input);
1007    mark_closed(fileno(input));
1008    fclose(input);
1009    return status;
1010}
1011
1012static int builtin_umask(char **argv)
1013{
1014    mode_t new_umask;
1015    const char *arg = argv[1];
1016    char *end;
1017    if (arg) {
1018        new_umask = strtoul(arg, &end, 8);
1019        if (*end != '\0' || end == arg) {
1020            return EXIT_FAILURE;
1021        }
1022    } else {
1023        new_umask = umask(0);
1024        printf("%.3o\n", (unsigned) new_umask);
1025    }
1026    umask(new_umask);
1027    return EXIT_SUCCESS;
1028}
1029
1030/* built-in 'unset VAR' handler */
1031static int builtin_unset(char **argv)
1032{
1033    /* bash always returns true */
1034    unset_local_var(argv[1]);
1035    return EXIT_SUCCESS;
1036}
1037
1038//static int builtin_not_written(char **argv)
1039//{
1040//  printf("builtin_%s not written\n", argv[0]);
1041//  return EXIT_FAILURE;
1042//}
1043
1044static int b_check_space(o_string *o, int len)
1045{
1046    /* It would be easy to drop a more restrictive policy
1047     * in here, such as setting a maximum string length */
1048    if (o->length + len > o->maxlen) {
1049        /* assert(data == NULL || o->maxlen != 0); */
1050        o->maxlen += (2*len > B_CHUNK ? 2*len : B_CHUNK);
1051        o->data = xrealloc(o->data, 1 + o->maxlen);
1052    }
1053    return o->data == NULL;
1054}
1055
1056static int b_addchr(o_string *o, int ch)
1057{
1058    debug_printf("b_addchr: '%c' o->length=%d o=%p\n", ch, o->length, o);
1059    if (b_check_space(o, 1))
1060        return B_NOSPAC;
1061    o->data[o->length] = ch;
1062    o->length++;
1063    o->data[o->length] = '\0';
1064    return 0;
1065}
1066
1067static void b_reset(o_string *o)
1068{
1069    o->length = 0;
1070    o->nonnull = 0;
1071    if (o->data != NULL)
1072        *o->data = '\0';
1073}
1074
1075static void b_free(o_string *o)
1076{
1077    b_reset(o);
1078    free(o->data);
1079    o->data = NULL;
1080    o->maxlen = 0;
1081}
1082
1083/* My analysis of quoting semantics tells me that state information
1084 * is associated with a destination, not a source.
1085 */
1086static int b_addqchr(o_string *o, int ch, int quote)
1087{
1088    if (quote && strchr("*?[\\", ch)) {
1089        int rc;
1090        rc = b_addchr(o, '\\');
1091        if (rc)
1092            return rc;
1093    }
1094    return b_addchr(o, ch);
1095}
1096
1097static int static_get(struct in_str *i)
1098{
1099    int ch = *i->p++;
1100    if (ch == '\0') return EOF;
1101    return ch;
1102}
1103
1104static int static_peek(struct in_str *i)
1105{
1106    return *i->p;
1107}
1108
1109#if ENABLE_HUSH_INTERACTIVE
1110#if ENABLE_FEATURE_EDITING
1111static void cmdedit_set_initial_prompt(void)
1112{
1113#if !ENABLE_FEATURE_EDITING_FANCY_PROMPT
1114    PS1 = NULL;
1115#else
1116    PS1 = getenv("PS1");
1117    if (PS1 == NULL)
1118        PS1 = "\\w \\$ ";
1119#endif
1120}
1121#endif /* EDITING */
1122
1123static const char* setup_prompt_string(int promptmode)
1124{
1125    const char *prompt_str;
1126    debug_printf("setup_prompt_string %d ", promptmode);
1127#if !ENABLE_FEATURE_EDITING_FANCY_PROMPT
1128    /* Set up the prompt */
1129    if (promptmode == 0) { /* PS1 */
1130        free((char*)PS1);
1131        PS1 = xasprintf("%s %c ", cwd, (geteuid() != 0) ? '$' : '#');
1132        prompt_str = PS1;
1133    } else {
1134        prompt_str = PS2;
1135    }
1136#else
1137    prompt_str = (promptmode == 0) ? PS1 : PS2;
1138#endif
1139    debug_printf("result '%s'\n", prompt_str);
1140    return prompt_str;
1141}
1142
1143static void get_user_input(struct in_str *i)
1144{
1145    int r;
1146    const char *prompt_str;
1147
1148    prompt_str = setup_prompt_string(i->promptmode);
1149#if ENABLE_FEATURE_EDITING
1150    /* Enable command line editing only while a command line
1151     * is actually being read; otherwise, we'll end up bequeathing
1152     * atexit() handlers and other unwanted stuff to our
1153     * child processes (rob@sysgo.de) */
1154    r = read_line_input(prompt_str, user_input_buf, BUFSIZ-1, line_input_state);
1155    i->eof_flag = (r < 0);
1156    if (i->eof_flag) { /* EOF/error detected */
1157        user_input_buf[0] = EOF; /* yes, it will be truncated, it's ok */
1158        user_input_buf[1] = '\0';
1159    }
1160#else
1161    fputs(prompt_str, stdout);
1162    fflush(stdout);
1163    user_input_buf[0] = r = fgetc(i->file);
1164    /*user_input_buf[1] = '\0'; - already is and never changed */
1165    i->eof_flag = (r == EOF);
1166#endif
1167    i->p = user_input_buf;
1168}
1169#endif  /* INTERACTIVE */
1170
1171/* This is the magic location that prints prompts
1172 * and gets data back from the user */
1173static int file_get(struct in_str *i)
1174{
1175    int ch;
1176
1177    /* If there is data waiting, eat it up */
1178    if (i->p && *i->p) {
1179#if ENABLE_HUSH_INTERACTIVE
1180 take_cached:
1181#endif
1182        ch = *i->p++;
1183        if (i->eof_flag && !*i->p)
1184            ch = EOF;
1185    } else {
1186        /* need to double check i->file because we might be doing something
1187         * more complicated by now, like sourcing or substituting. */
1188#if ENABLE_HUSH_INTERACTIVE
1189        if (interactive_fd && i->promptme && i->file == stdin) {
1190            do {
1191                get_user_input(i);
1192            } while (!*i->p); /* need non-empty line */
1193            i->promptmode = 1; /* PS2 */
1194            i->promptme = 0;
1195            goto take_cached;
1196        }
1197#endif
1198        ch = fgetc(i->file);
1199    }
1200    debug_printf("file_get: got a '%c' %d\n", ch, ch);
1201#if ENABLE_HUSH_INTERACTIVE
1202    if (ch == '\n')
1203        i->promptme = 1;
1204#endif
1205    return ch;
1206}
1207
1208/* All the callers guarantee this routine will never be
1209 * used right after a newline, so prompting is not needed.
1210 */
1211static int file_peek(struct in_str *i)
1212{
1213    int ch;
1214    if (i->p && *i->p) {
1215        if (i->eof_flag && !i->p[1])
1216            return EOF;
1217        return *i->p;
1218    }
1219    ch = fgetc(i->file);
1220    i->eof_flag = (ch == EOF);
1221    i->peek_buf[0] = ch;
1222    i->peek_buf[1] = '\0';
1223    i->p = i->peek_buf;
1224    debug_printf("file_peek: got a '%c' %d\n", *i->p, *i->p);
1225    return ch;
1226}
1227
1228static void setup_file_in_str(struct in_str *i, FILE *f)
1229{
1230    i->peek = file_peek;
1231    i->get = file_get;
1232#if ENABLE_HUSH_INTERACTIVE
1233    i->promptme = 1;
1234    i->promptmode = 0; /* PS1 */
1235#endif
1236    i->file = f;
1237    i->p = NULL;
1238}
1239
1240static void setup_string_in_str(struct in_str *i, const char *s)
1241{
1242    i->peek = static_peek;
1243    i->get = static_get;
1244#if ENABLE_HUSH_INTERACTIVE
1245    i->promptme = 1;
1246    i->promptmode = 0; /* PS1 */
1247#endif
1248    i->p = s;
1249    i->eof_flag = 0;
1250}
1251
1252static void mark_open(int fd)
1253{
1254    struct close_me *new = xmalloc(sizeof(struct close_me));
1255    new->fd = fd;
1256    new->next = close_me_head;
1257    close_me_head = new;
1258}
1259
1260static void mark_closed(int fd)
1261{
1262    struct close_me *tmp;
1263    if (close_me_head == NULL || close_me_head->fd != fd)
1264        bb_error_msg_and_die("corrupt close_me");
1265    tmp = close_me_head;
1266    close_me_head = close_me_head->next;
1267    free(tmp);
1268}
1269
1270static void close_all(void)
1271{
1272    struct close_me *c;
1273    for (c = close_me_head; c; c = c->next) {
1274        close(c->fd);
1275    }
1276    close_me_head = NULL;
1277}
1278
1279/* squirrel != NULL means we squirrel away copies of stdin, stdout,
1280 * and stderr if they are redirected. */
1281static int setup_redirects(struct child_prog *prog, int squirrel[])
1282{
1283    int openfd, mode;
1284    struct redir_struct *redir;
1285
1286    for (redir = prog->redirects; redir; redir = redir->next) {
1287        if (redir->dup == -1 && redir->word.gl_pathv == NULL) {
1288            /* something went wrong in the parse.  Pretend it didn't happen */
1289            continue;
1290        }
1291        if (redir->dup == -1) {
1292            mode = redir_table[redir->type].mode;
1293            openfd = open_or_warn(redir->word.gl_pathv[0], mode);
1294            if (openfd < 0) {
1295            /* this could get lost if stderr has been redirected, but
1296               bash and ash both lose it as well (though zsh doesn't!) */
1297                return 1;
1298            }
1299        } else {
1300            openfd = redir->dup;
1301        }
1302
1303        if (openfd != redir->fd) {
1304            if (squirrel && redir->fd < 3) {
1305                squirrel[redir->fd] = dup(redir->fd);
1306            }
1307            if (openfd == -3) {
1308                close(openfd);
1309            } else {
1310                dup2(openfd, redir->fd);
1311                if (redir->dup == -1)
1312                    close(openfd);
1313            }
1314        }
1315    }
1316    return 0;
1317}
1318
1319static void restore_redirects(int squirrel[])
1320{
1321    int i, fd;
1322    for (i = 0; i < 3; i++) {
1323        fd = squirrel[i];
1324        if (fd != -1) {
1325            /* We simply die on error */
1326            xmove_fd(fd, i);
1327        }
1328    }
1329}
1330
1331/* never returns */
1332/* XXX no exit() here.  If you don't exec, use _exit instead.
1333 * The at_exit handlers apparently confuse the calling process,
1334 * in particular stdin handling.  Not sure why? -- because of vfork! (vda) */
1335static void pseudo_exec_argv(char **argv)
1336{
1337    int i, rcode;
1338    char *p;
1339    const struct built_in_command *x;
1340
1341    for (i = 0; is_assignment(argv[i]); i++) {
1342        debug_printf_exec("pid %d environment modification: %s\n",
1343                getpid(), argv[i]);
1344// FIXME: vfork case??
1345        p = expand_string_to_string(argv[i]);
1346        putenv(p);
1347    }
1348    argv += i;
1349    /* If a variable is assigned in a forest, and nobody listens,
1350     * was it ever really set?
1351     */
1352    if (argv[0] == NULL) {
1353        _exit(EXIT_SUCCESS);
1354    }
1355
1356    argv = expand_strvec_to_strvec(argv);
1357
1358    /*
1359     * Check if the command matches any of the builtins.
1360     * Depending on context, this might be redundant.  But it's
1361     * easier to waste a few CPU cycles than it is to figure out
1362     * if this is one of those cases.
1363     */
1364    for (x = bltins; x->cmd; x++) {
1365        if (strcmp(argv[0], x->cmd) == 0) {
1366            debug_printf_exec("running builtin '%s'\n", argv[0]);
1367            rcode = x->function(argv);
1368            fflush(stdout);
1369            _exit(rcode);
1370        }
1371    }
1372
1373    /* Check if the command matches any busybox applets */
1374#if ENABLE_FEATURE_SH_STANDALONE
1375    if (strchr(argv[0], '/') == NULL) {
1376        const struct bb_applet *a = find_applet_by_name(argv[0]);
1377        if (a) {
1378            if (a->noexec) {
1379                current_applet = a;
1380                debug_printf_exec("running applet '%s'\n", argv[0]);
1381// is it ok that run_current_applet_and_exit() does exit(), not _exit()?
1382                run_current_applet_and_exit(argv);
1383            }
1384            /* re-exec ourselves with the new arguments */
1385            debug_printf_exec("re-execing applet '%s'\n", argv[0]);
1386            execvp(bb_busybox_exec_path, argv);
1387            /* If they called chroot or otherwise made the binary no longer
1388             * executable, fall through */
1389        }
1390    }
1391#endif
1392
1393    debug_printf_exec("execing '%s'\n", argv[0]);
1394    execvp(argv[0], argv);
1395    bb_perror_msg("cannot exec '%s'", argv[0]);
1396    _exit(1);
1397}
1398
1399static void pseudo_exec(struct child_prog *child)
1400{
1401// FIXME: buggy wrt NOMMU! Must not modify any global data
1402// until it does exec/_exit, but currently it does.
1403    int rcode;
1404
1405    if (child->argv) {
1406        pseudo_exec_argv(child->argv);
1407    }
1408
1409    if (child->group) {
1410    // FIXME: do not modify globals! Think vfork!
1411#if ENABLE_HUSH_INTERACTIVE
1412        debug_printf_exec("pseudo_exec: setting interactive_fd=0\n");
1413        interactive_fd = 0;    /* crucial!!!! */
1414#endif
1415        debug_printf_exec("pseudo_exec: run_list_real\n");
1416        rcode = run_list_real(child->group);
1417        /* OK to leak memory by not calling free_pipe_list,
1418         * since this process is about to exit */
1419        _exit(rcode);
1420    }
1421
1422    /* Can happen.  See what bash does with ">foo" by itself. */
1423    debug_printf("trying to pseudo_exec null command\n");
1424    _exit(EXIT_SUCCESS);
1425}
1426
1427#if ENABLE_HUSH_JOB
1428static const char *get_cmdtext(struct pipe *pi)
1429{
1430    char **argv;
1431    char *p;
1432    int len;
1433
1434    /* This is subtle. ->cmdtext is created only on first backgrounding.
1435     * (Think "cat, <ctrl-z>, fg, <ctrl-z>, fg, <ctrl-z>...." here...)
1436     * On subsequent bg argv is trashed, but we won't use it */
1437    if (pi->cmdtext)
1438        return pi->cmdtext;
1439    argv = pi->progs[0].argv;
1440    if (!argv || !argv[0])
1441        return (pi->cmdtext = xzalloc(1));
1442
1443    len = 0;
1444    do len += strlen(*argv) + 1; while (*++argv);
1445    pi->cmdtext = p = xmalloc(len);
1446    argv = pi->progs[0].argv;
1447    do {
1448        len = strlen(*argv);
1449        memcpy(p, *argv, len);
1450        p += len;
1451        *p++ = ' ';
1452    } while (*++argv);
1453    p[-1] = '\0';
1454    return pi->cmdtext;
1455}
1456
1457static void insert_bg_job(struct pipe *pi)
1458{
1459    struct pipe *thejob;
1460    int i;
1461
1462    /* Linear search for the ID of the job to use */
1463    pi->jobid = 1;
1464    for (thejob = job_list; thejob; thejob = thejob->next)
1465        if (thejob->jobid >= pi->jobid)
1466            pi->jobid = thejob->jobid + 1;
1467
1468    /* Add thejob to the list of running jobs */
1469    if (!job_list) {
1470        thejob = job_list = xmalloc(sizeof(*thejob));
1471    } else {
1472        for (thejob = job_list; thejob->next; thejob = thejob->next)
1473            continue;
1474        thejob->next = xmalloc(sizeof(*thejob));
1475        thejob = thejob->next;
1476    }
1477
1478    /* Physically copy the struct job */
1479    memcpy(thejob, pi, sizeof(struct pipe));
1480    thejob->progs = xzalloc(sizeof(pi->progs[0]) * pi->num_progs);
1481    /* We cannot copy entire pi->progs[] vector! Double free()s will happen */
1482    for (i = 0; i < pi->num_progs; i++) {
1483// TODO: do we really need to have so many fields which are just dead weight
1484// at execution stage?
1485        thejob->progs[i].pid = pi->progs[i].pid;
1486        /* all other fields are not used and stay zero */
1487    }
1488    thejob->next = NULL;
1489    thejob->cmdtext = xstrdup(get_cmdtext(pi));
1490
1491    /* We don't wait for background thejobs to return -- append it
1492       to the list of backgrounded thejobs and leave it alone */
1493    printf("[%d] %d %s\n", thejob->jobid, thejob->progs[0].pid, thejob->cmdtext);
1494    last_bg_pid = thejob->progs[0].pid;
1495    last_jobid = thejob->jobid;
1496}
1497
1498static void remove_bg_job(struct pipe *pi)
1499{
1500    struct pipe *prev_pipe;
1501
1502    if (pi == job_list) {
1503        job_list = pi->next;
1504    } else {
1505        prev_pipe = job_list;
1506        while (prev_pipe->next != pi)
1507            prev_pipe = prev_pipe->next;
1508        prev_pipe->next = pi->next;
1509    }
1510    if (job_list)
1511        last_jobid = job_list->jobid;
1512    else
1513        last_jobid = 0;
1514}
1515
1516/* remove a backgrounded job */
1517static void delete_finished_bg_job(struct pipe *pi)
1518{
1519    remove_bg_job(pi);
1520    pi->stopped_progs = 0;
1521    free_pipe(pi, 0);
1522    free(pi);
1523}
1524#endif /* JOB */
1525
1526/* Checks to see if any processes have exited -- if they
1527   have, figure out why and see if a job has completed */
1528static int checkjobs(struct pipe* fg_pipe)
1529{
1530    int attributes;
1531    int status;
1532#if ENABLE_HUSH_JOB
1533    int prognum = 0;
1534    struct pipe *pi;
1535#endif
1536    pid_t childpid;
1537    int rcode = 0;
1538
1539    attributes = WUNTRACED;
1540    if (fg_pipe == NULL) {
1541        attributes |= WNOHANG;
1542    }
1543
1544/* Do we do this right?
1545 * bash-3.00# sleep 20 | false
1546 * <ctrl-Z pressed>
1547 * [3]+  Stopped          sleep 20 | false
1548 * bash-3.00# echo $?
1549 * 1   <========== bg pipe is not fully done, but exitcode is already known!
1550 */
1551
1552//FIXME: non-interactive bash does not continue even if all processes in fg pipe
1553//are stopped. Testcase: "cat | cat" in a script (not on command line)
1554// + killall -STOP cat
1555
1556 wait_more:
1557    while ((childpid = waitpid(-1, &status, attributes)) > 0) {
1558        const int dead = WIFEXITED(status) || WIFSIGNALED(status);
1559
1560#ifdef DEBUG_SHELL_JOBS
1561        if (WIFSTOPPED(status))
1562            debug_printf_jobs("pid %d stopped by sig %d (exitcode %d)\n",
1563                    childpid, WSTOPSIG(status), WEXITSTATUS(status));
1564        if (WIFSIGNALED(status))
1565            debug_printf_jobs("pid %d killed by sig %d (exitcode %d)\n",
1566                    childpid, WTERMSIG(status), WEXITSTATUS(status));
1567        if (WIFEXITED(status))
1568            debug_printf_jobs("pid %d exited, exitcode %d\n",
1569                    childpid, WEXITSTATUS(status));
1570#endif
1571        /* Were we asked to wait for fg pipe? */
1572        if (fg_pipe) {
1573            int i;
1574            for (i = 0; i < fg_pipe->num_progs; i++) {
1575                debug_printf_jobs("check pid %d\n", fg_pipe->progs[i].pid);
1576                if (fg_pipe->progs[i].pid == childpid) {
1577                    /* printf("process %d exit %d\n", i, WEXITSTATUS(status)); */
1578                    if (dead) {
1579                        fg_pipe->progs[i].pid = 0;
1580                        fg_pipe->running_progs--;
1581                        if (i == fg_pipe->num_progs-1)
1582                            /* last process gives overall exitstatus */
1583                            rcode = WEXITSTATUS(status);
1584                    } else {
1585                        fg_pipe->progs[i].is_stopped = 1;
1586                        fg_pipe->stopped_progs++;
1587                    }
1588                    debug_printf_jobs("fg_pipe: running_progs %d stopped_progs %d\n",
1589                            fg_pipe->running_progs, fg_pipe->stopped_progs);
1590                    if (fg_pipe->running_progs - fg_pipe->stopped_progs <= 0) {
1591                        /* All processes in fg pipe have exited/stopped */
1592#if ENABLE_HUSH_JOB
1593                        if (fg_pipe->running_progs)
1594                            insert_bg_job(fg_pipe);
1595#endif
1596                        return rcode;
1597                    }
1598                    /* There are still running processes in the fg pipe */
1599                    goto wait_more;
1600                }
1601            }
1602            /* fall through to searching process in bg pipes */
1603        }
1604
1605#if ENABLE_HUSH_JOB
1606        /* We asked to wait for bg or orphaned children */
1607        /* No need to remember exitcode in this case */
1608        for (pi = job_list; pi; pi = pi->next) {
1609            prognum = 0;
1610            while (prognum < pi->num_progs) {
1611                if (pi->progs[prognum].pid == childpid)
1612                    goto found_pi_and_prognum;
1613                prognum++;
1614            }
1615        }
1616#endif
1617
1618        /* Happens when shell is used as init process (init=/bin/sh) */
1619        debug_printf("checkjobs: pid %d was not in our list!\n", childpid);
1620        goto wait_more;
1621
1622#if ENABLE_HUSH_JOB
1623 found_pi_and_prognum:
1624        if (dead) {
1625            /* child exited */
1626            pi->progs[prognum].pid = 0;
1627            pi->running_progs--;
1628            if (!pi->running_progs) {
1629                printf(JOB_STATUS_FORMAT, pi->jobid,
1630                            "Done", pi->cmdtext);
1631                delete_finished_bg_job(pi);
1632            }
1633        } else {
1634            /* child stopped */
1635            pi->stopped_progs++;
1636            pi->progs[prognum].is_stopped = 1;
1637        }
1638#endif
1639    }
1640
1641    /* wait found no children or failed */
1642
1643    if (childpid && errno != ECHILD)
1644        bb_perror_msg("waitpid");
1645    return rcode;
1646}
1647
1648#if ENABLE_HUSH_JOB
1649static int checkjobs_and_fg_shell(struct pipe* fg_pipe)
1650{
1651    pid_t p;
1652    int rcode = checkjobs(fg_pipe);
1653    /* Job finished, move the shell to the foreground */
1654    p = getpgid(0); /* pgid of our process */
1655    debug_printf_jobs("fg'ing ourself: getpgid(0)=%d\n", (int)p);
1656    if (tcsetpgrp(interactive_fd, p) && errno != ENOTTY)
1657        bb_perror_msg("tcsetpgrp-4a");
1658    return rcode;
1659}
1660#endif
1661
1662/* run_pipe_real() starts all the jobs, but doesn't wait for anything
1663 * to finish.  See checkjobs().
1664 *
1665 * return code is normally -1, when the caller has to wait for children
1666 * to finish to determine the exit status of the pipe.  If the pipe
1667 * is a simple builtin command, however, the action is done by the
1668 * time run_pipe_real returns, and the exit code is provided as the
1669 * return value.
1670 *
1671 * The input of the pipe is always stdin, the output is always
1672 * stdout.  The outpipe[] mechanism in BusyBox-0.48 lash is bogus,
1673 * because it tries to avoid running the command substitution in
1674 * subshell, when that is in fact necessary.  The subshell process
1675 * now has its stdout directed to the input of the appropriate pipe,
1676 * so this routine is noticeably simpler.
1677 *
1678 * Returns -1 only if started some children. IOW: we have to
1679 * mask out retvals of builtins etc with 0xff!
1680 */
1681static int run_pipe_real(struct pipe *pi)
1682{
1683    int i;
1684    int nextin, nextout;
1685    int pipefds[2];             /* pipefds[0] is for reading */
1686    struct child_prog *child;
1687    const struct built_in_command *x;
1688    char *p;
1689    /* it is not always needed, but we aim to smaller code */
1690    int squirrel[] = { -1, -1, -1 };
1691    int rcode;
1692    const int single_fg = (pi->num_progs == 1 && pi->followup != PIPE_BG);
1693
1694    debug_printf_exec("run_pipe_real start: single_fg=%d\n", single_fg);
1695
1696    nextin = 0;
1697#if ENABLE_HUSH_JOB
1698    pi->pgrp = -1;
1699#endif
1700    pi->running_progs = 1;
1701    pi->stopped_progs = 0;
1702
1703    /* Check if this is a simple builtin (not part of a pipe).
1704     * Builtins within pipes have to fork anyway, and are handled in
1705     * pseudo_exec.  "echo foo | read bar" doesn't work on bash, either.
1706     */
1707    child = &(pi->progs[0]);
1708    if (single_fg && child->group && child->subshell == 0) {
1709        debug_printf("non-subshell grouping\n");
1710        setup_redirects(child, squirrel);
1711        debug_printf_exec(": run_list_real\n");
1712        rcode = run_list_real(child->group);
1713        restore_redirects(squirrel);
1714        debug_printf_exec("run_pipe_real return %d\n", rcode);
1715        return rcode; // do we need to add '... & 0xff' ?
1716    }
1717
1718    if (single_fg && child->argv != NULL) {
1719        char **argv_expanded;
1720        char **argv = child->argv;
1721
1722        for (i = 0; is_assignment(argv[i]); i++)
1723            continue;
1724        if (i != 0 && argv[i] == NULL) {
1725            /* assignments, but no command: set the local environment */
1726            for (i = 0; argv[i] != NULL; i++) {
1727                debug_printf("local environment set: %s\n", argv[i]);
1728                p = expand_string_to_string(argv[i]);
1729                set_local_var(p, 0);
1730            }
1731            return EXIT_SUCCESS;   /* don't worry about errors in set_local_var() yet */
1732        }
1733        for (i = 0; is_assignment(argv[i]); i++) {
1734            p = expand_string_to_string(argv[i]);
1735            //sp: child->sp--;
1736            putenv(p);
1737        }
1738        for (x = bltins; x->cmd; x++) {
1739            if (strcmp(argv[i], x->cmd) == 0) {
1740                if (x->function == builtin_exec && argv[i+1] == NULL) {
1741                    debug_printf("magic exec\n");
1742                    setup_redirects(child, NULL);
1743                    return EXIT_SUCCESS;
1744                }
1745                debug_printf("builtin inline %s\n", argv[0]);
1746                /* XXX setup_redirects acts on file descriptors, not FILEs.
1747                 * This is perfect for work that comes after exec().
1748                 * Is it really safe for inline use?  Experimentally,
1749                 * things seem to work with glibc. */
1750                setup_redirects(child, squirrel);
1751                debug_printf_exec(": builtin '%s' '%s'...\n", x->cmd, argv[i+1]);
1752                //sp: if (child->sp) /* btw we can do it unconditionally... */
1753                argv_expanded = expand_strvec_to_strvec(argv + i);
1754                rcode = x->function(argv_expanded) & 0xff;
1755                free(argv_expanded);
1756                restore_redirects(squirrel);
1757                debug_printf_exec("run_pipe_real return %d\n", rcode);
1758                return rcode;
1759            }
1760        }
1761#if ENABLE_FEATURE_SH_STANDALONE
1762        {
1763            const struct bb_applet *a = find_applet_by_name(argv[i]);
1764            if (a && a->nofork) {
1765                setup_redirects(child, squirrel);
1766                save_nofork_data(&nofork_save);
1767                argv_expanded = argv + i;
1768                //sp: if (child->sp)
1769                argv_expanded = expand_strvec_to_strvec(argv + i);
1770                debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", argv_expanded[0], argv_expanded[1]);
1771                rcode = run_nofork_applet_prime(&nofork_save, a, argv_expanded) & 0xff;
1772                free(argv_expanded);
1773                restore_redirects(squirrel);
1774                debug_printf_exec("run_pipe_real return %d\n", rcode);
1775                return rcode;
1776            }
1777        }
1778#endif
1779    }
1780
1781    /* Going to fork a child per each pipe member */
1782    pi->running_progs = 0;
1783
1784    /* Disable job control signals for shell (parent) and
1785     * for initial child code after fork */
1786    set_jobctrl_sighandler(SIG_IGN);
1787
1788    for (i = 0; i < pi->num_progs; i++) {
1789        child = &(pi->progs[i]);
1790        if (child->argv)
1791            debug_printf_exec(": pipe member '%s' '%s'...\n", child->argv[0], child->argv[1]);
1792        else
1793            debug_printf_exec(": pipe member with no argv\n");
1794
1795        /* pipes are inserted between pairs of commands */
1796        if ((i + 1) < pi->num_progs) {
1797            pipe(pipefds);
1798            nextout = pipefds[1];
1799        } else {
1800            nextout = 1;
1801            pipefds[0] = -1;
1802        }
1803
1804        /* XXX test for failed fork()? */
1805#if BB_MMU
1806        child->pid = fork();
1807#else
1808        child->pid = vfork();
1809#endif
1810        if (!child->pid) { /* child */
1811            /* Every child adds itself to new process group
1812             * with pgid == pid of first child in pipe */
1813#if ENABLE_HUSH_JOB
1814            if (run_list_level == 1 && interactive_fd) {
1815                /* Don't do pgrp restore anymore on fatal signals */
1816                set_fatal_sighandler(SIG_DFL);
1817                if (pi->pgrp < 0) /* true for 1st process only */
1818                    pi->pgrp = getpid();
1819                if (setpgid(0, pi->pgrp) == 0 && pi->followup != PIPE_BG) {
1820                    /* We do it in *every* child, not just first,
1821                     * to avoid races */
1822                    tcsetpgrp(interactive_fd, pi->pgrp);
1823                }
1824            }
1825#endif
1826            /* in non-interactive case fatal sigs are already SIG_DFL */
1827            close_all();
1828            if (nextin != 0) {
1829                dup2(nextin, 0);
1830                close(nextin);
1831            }
1832            if (nextout != 1) {
1833                dup2(nextout, 1);
1834                close(nextout);
1835            }
1836            if (pipefds[0] != -1) {
1837                close(pipefds[0]);  /* opposite end of our output pipe */
1838            }
1839            /* Like bash, explicit redirects override pipes,
1840             * and the pipe fd is available for dup'ing. */
1841            setup_redirects(child, NULL);
1842
1843            /* Restore default handlers just prior to exec */
1844            set_jobctrl_sighandler(SIG_DFL);
1845            set_misc_sighandler(SIG_DFL);
1846            signal(SIGCHLD, SIG_DFL);
1847            pseudo_exec(child);
1848        }
1849
1850        pi->running_progs++;
1851
1852#if ENABLE_HUSH_JOB
1853        /* Second and next children need to know pid of first one */
1854        if (pi->pgrp < 0)
1855            pi->pgrp = child->pid;
1856#endif
1857        if (nextin != 0)
1858            close(nextin);
1859        if (nextout != 1)
1860            close(nextout);
1861
1862        /* If there isn't another process, nextin is garbage
1863           but it doesn't matter */
1864        nextin = pipefds[0];
1865    }
1866    debug_printf_exec("run_pipe_real return -1\n");
1867    return -1;
1868}
1869
1870#ifndef debug_print_tree
1871static void debug_print_tree(struct pipe *pi, int lvl)
1872{
1873    static const char *PIPE[] = {
1874        [PIPE_SEQ] = "SEQ",
1875        [PIPE_AND] = "AND",
1876        [PIPE_OR ] = "OR" ,
1877        [PIPE_BG ] = "BG" ,
1878    };
1879    static const char *RES[] = {
1880        [RES_NONE ] = "NONE" ,
1881#if ENABLE_HUSH_IF
1882        [RES_IF   ] = "IF"   ,
1883        [RES_THEN ] = "THEN" ,
1884        [RES_ELIF ] = "ELIF" ,
1885        [RES_ELSE ] = "ELSE" ,
1886        [RES_FI   ] = "FI"   ,
1887#endif
1888#if ENABLE_HUSH_LOOPS
1889        [RES_FOR  ] = "FOR"  ,
1890        [RES_WHILE] = "WHILE",
1891        [RES_UNTIL] = "UNTIL",
1892        [RES_DO   ] = "DO"   ,
1893        [RES_DONE ] = "DONE" ,
1894        [RES_IN   ] = "IN"   ,
1895#endif
1896        [RES_XXXX ] = "XXXX" ,
1897        [RES_SNTX ] = "SNTX" ,
1898    };
1899
1900    int pin, prn;
1901
1902    pin = 0;
1903    while (pi) {
1904        fprintf(stderr, "%*spipe %d res_word=%s followup=%d %s\n", lvl*2, "",
1905                pin, RES[pi->res_word], pi->followup, PIPE[pi->followup]);
1906        prn = 0;
1907        while (prn < pi->num_progs) {
1908            struct child_prog *child = &pi->progs[prn];
1909            char **argv = child->argv;
1910
1911            fprintf(stderr, "%*s prog %d", lvl*2, "", prn);
1912            if (child->group) {
1913                fprintf(stderr, " group %s: (argv=%p)\n",
1914                        (child->subshell ? "()" : "{}"),
1915                        argv);
1916                debug_print_tree(child->group, lvl+1);
1917                prn++;
1918                continue;
1919            }
1920            if (argv) while (*argv) {
1921                fprintf(stderr, " '%s'", *argv);
1922                argv++;
1923            }
1924            fprintf(stderr, "\n");
1925            prn++;
1926        }
1927        pi = pi->next;
1928        pin++;
1929    }
1930}
1931#endif
1932
1933/* NB: called by pseudo_exec, and therefore must not modify any
1934 * global data until exec/_exit (we can be a child after vfork!) */
1935static int run_list_real(struct pipe *pi)
1936{
1937    struct pipe *rpipe;
1938#if ENABLE_HUSH_LOOPS
1939    char *for_varname = NULL;
1940    char **for_lcur = NULL;
1941    char **for_list = NULL;
1942    int flag_rep = 0;
1943#endif
1944    int save_num_progs;
1945    int flag_skip = 1;
1946    int rcode = 0; /* probably for gcc only */
1947    int flag_restore = 0;
1948#if ENABLE_HUSH_IF
1949    int if_code = 0, next_if_code = 0;  /* need double-buffer to handle elif */
1950#else
1951    enum { if_code = 0, next_if_code = 0 };
1952#endif
1953    reserved_style rword;
1954    reserved_style skip_more_for_this_rword = RES_XXXX;
1955
1956    debug_printf_exec("run_list_real start lvl %d\n", run_list_level + 1);
1957
1958#if ENABLE_HUSH_LOOPS
1959    /* check syntax for "for" */
1960    for (rpipe = pi; rpipe; rpipe = rpipe->next) {
1961        if ((rpipe->res_word == RES_IN || rpipe->res_word == RES_FOR)
1962         && (rpipe->next == NULL)
1963        ) {
1964            syntax("malformed for"); /* no IN or no commands after IN */
1965            debug_printf_exec("run_list_real lvl %d return 1\n", run_list_level);
1966            return 1;
1967        }
1968        if ((rpipe->res_word == RES_IN && rpipe->next->res_word == RES_IN && rpipe->next->progs[0].argv != NULL)
1969         || (rpipe->res_word == RES_FOR && rpipe->next->res_word != RES_IN)
1970        ) {
1971            /* TODO: what is tested in the first condition? */
1972            syntax("malformed for"); /* 2nd condition: not followed by IN */
1973            debug_printf_exec("run_list_real lvl %d return 1\n", run_list_level);
1974            return 1;
1975        }
1976    }
1977#else
1978    rpipe = NULL;
1979#endif
1980
1981#if ENABLE_HUSH_JOB
1982    /* Example of nested list: "while true; do { sleep 1 | exit 2; } done".
1983     * We are saving state before entering outermost list ("while...done")
1984     * so that ctrl-Z will correctly background _entire_ outermost list,
1985     * not just a part of it (like "sleep 1 | exit 2") */
1986    if (++run_list_level == 1 && interactive_fd) {
1987        if (sigsetjmp(toplevel_jb, 1)) {
1988            /* ctrl-Z forked and we are parent; or ctrl-C.
1989             * Sighandler has longjmped us here */
1990            signal(SIGINT, SIG_IGN);
1991            signal(SIGTSTP, SIG_IGN);
1992            /* Restore level (we can be coming from deep inside
1993             * nested levels) */
1994            run_list_level = 1;
1995#if ENABLE_FEATURE_SH_STANDALONE
1996            if (nofork_save.saved) { /* if save area is valid */
1997                debug_printf_jobs("exiting nofork early\n");
1998                restore_nofork_data(&nofork_save);
1999            }
2000#endif
2001            if (ctrl_z_flag) {
2002                /* ctrl-Z has forked and stored pid of the child in pi->pid.
2003                 * Remember this child as background job */
2004                insert_bg_job(pi);
2005            } else {
2006                /* ctrl-C. We just stop doing whatever we were doing */
2007                putchar('\n');
2008            }
2009            rcode = 0;
2010            goto ret;
2011        }
2012        /* ctrl-Z handler will store pid etc in pi */
2013        toplevel_list = pi;
2014        ctrl_z_flag = 0;
2015#if ENABLE_FEATURE_SH_STANDALONE
2016        nofork_save.saved = 0; /* in case we will run a nofork later */
2017#endif
2018        signal_SA_RESTART(SIGTSTP, handler_ctrl_z);
2019        signal(SIGINT, handler_ctrl_c);
2020    }
2021#endif
2022
2023    for (; pi; pi = flag_restore ? rpipe : pi->next) {
2024        rword = pi->res_word;
2025#if ENABLE_HUSH_LOOPS
2026        if (rword == RES_WHILE || rword == RES_UNTIL || rword == RES_FOR) {
2027            flag_restore = 0;
2028            if (!rpipe) {
2029                flag_rep = 0;
2030                rpipe = pi;
2031            }
2032        }
2033#endif
2034        debug_printf_exec(": rword=%d if_code=%d next_if_code=%d skip_more=%d\n",
2035                rword, if_code, next_if_code, skip_more_for_this_rword);
2036        if (rword == skip_more_for_this_rword && flag_skip) {
2037            if (pi->followup == PIPE_SEQ)
2038                flag_skip = 0;
2039            continue;
2040        }
2041        flag_skip = 1;
2042        skip_more_for_this_rword = RES_XXXX;
2043#if ENABLE_HUSH_IF
2044        if (rword == RES_THEN || rword == RES_ELSE)
2045            if_code = next_if_code;
2046        if (rword == RES_THEN && if_code)
2047            continue;
2048        if (rword == RES_ELSE && !if_code)
2049            continue;
2050        if (rword == RES_ELIF && !if_code)
2051            break;
2052#endif
2053#if ENABLE_HUSH_LOOPS
2054        if (rword == RES_FOR && pi->num_progs) {
2055            if (!for_lcur) {
2056                /* if no variable values after "in" we skip "for" */
2057                if (!pi->next->progs->argv)
2058                    continue;
2059                /* create list of variable values */
2060                for_list = expand_strvec_to_strvec(pi->next->progs->argv);
2061                for_lcur = for_list;
2062                for_varname = pi->progs->argv[0];
2063                pi->progs->argv[0] = NULL;
2064                flag_rep = 1;
2065            }
2066            free(pi->progs->argv[0]);
2067            if (!*for_lcur) {
2068                free(for_list);
2069                for_lcur = NULL;
2070                flag_rep = 0;
2071                pi->progs->argv[0] = for_varname;
2072                pi->progs->glob_result.gl_pathv[0] = pi->progs->argv[0];
2073                continue;
2074            }
2075            /* insert next value from for_lcur */
2076            /* vda: does it need escaping? */
2077            pi->progs->argv[0] = xasprintf("%s=%s", for_varname, *for_lcur++);
2078            pi->progs->glob_result.gl_pathv[0] = pi->progs->argv[0];
2079        }
2080        if (rword == RES_IN)
2081            continue;
2082        if (rword == RES_DO) {
2083            if (!flag_rep)
2084                continue;
2085        }
2086        if (rword == RES_DONE) {
2087            if (flag_rep) {
2088                flag_restore = 1;
2089            } else {
2090                rpipe = NULL;
2091            }
2092        }
2093#endif
2094        if (pi->num_progs == 0)
2095            continue;
2096        save_num_progs = pi->num_progs; /* save number of programs */
2097        debug_printf_exec(": run_pipe_real with %d members\n", pi->num_progs);
2098        rcode = run_pipe_real(pi);
2099        if (rcode != -1) {
2100            /* We only ran a builtin: rcode was set by the return value
2101             * of run_pipe_real(), and we don't need to wait for anything. */
2102        } else if (pi->followup == PIPE_BG) {
2103            /* What does bash do with attempts to background builtins? */
2104            /* Even bash 3.2 doesn't do that well with nested bg:
2105             * try "{ { sleep 10; echo DEEP; } & echo HERE; } &".
2106             * I'm NOT treating inner &'s as jobs */
2107#if ENABLE_HUSH_JOB
2108            if (run_list_level == 1)
2109                insert_bg_job(pi);
2110#endif
2111            rcode = EXIT_SUCCESS;
2112        } else {
2113#if ENABLE_HUSH_JOB
2114            /* Paranoia, just "interactive_fd" should be enough? */
2115            if (run_list_level == 1 && interactive_fd) {
2116                /* waits for completion, then fg's main shell */
2117                rcode = checkjobs_and_fg_shell(pi);
2118            } else
2119#endif
2120            {
2121                /* this one just waits for completion */
2122                rcode = checkjobs(pi);
2123            }
2124            debug_printf_exec(": checkjobs returned %d\n", rcode);
2125        }
2126        debug_printf_exec(": setting last_return_code=%d\n", rcode);
2127        last_return_code = rcode;
2128        pi->num_progs = save_num_progs; /* restore number of programs */
2129#if ENABLE_HUSH_IF
2130        if (rword == RES_IF || rword == RES_ELIF)
2131            next_if_code = rcode;  /* can be overwritten a number of times */
2132#endif
2133#if ENABLE_HUSH_LOOPS
2134        if (rword == RES_WHILE)
2135            flag_rep = !last_return_code;
2136        if (rword == RES_UNTIL)
2137            flag_rep = last_return_code;
2138#endif
2139        if ((rcode == EXIT_SUCCESS && pi->followup == PIPE_OR)
2140         || (rcode != EXIT_SUCCESS && pi->followup == PIPE_AND)
2141        ) {
2142            skip_more_for_this_rword = rword;
2143        }
2144        checkjobs(NULL);
2145    }
2146
2147#if ENABLE_HUSH_JOB
2148    if (ctrl_z_flag) {
2149        /* ctrl-Z forked somewhere in the past, we are the child,
2150         * and now we completed running the list. Exit. */
2151        exit(rcode);
2152    }
2153 ret:
2154    if (!--run_list_level && interactive_fd) {
2155        signal(SIGTSTP, SIG_IGN);
2156        signal(SIGINT, SIG_IGN);
2157    }
2158#endif
2159    debug_printf_exec("run_list_real lvl %d return %d\n", run_list_level + 1, rcode);
2160    return rcode;
2161}
2162
2163/* return code is the exit status of the pipe */
2164static int free_pipe(struct pipe *pi, int indent)
2165{
2166    char **p;
2167    struct child_prog *child;
2168    struct redir_struct *r, *rnext;
2169    int a, i, ret_code = 0;
2170
2171    if (pi->stopped_progs > 0)
2172        return ret_code;
2173    debug_printf_clean("%s run pipe: (pid %d)\n", indenter(indent), getpid());
2174    for (i = 0; i < pi->num_progs; i++) {
2175        child = &pi->progs[i];
2176        debug_printf_clean("%s  command %d:\n", indenter(indent), i);
2177        if (child->argv) {
2178            for (a = 0, p = child->argv; *p; a++, p++) {
2179                debug_printf_clean("%s   argv[%d] = %s\n", indenter(indent), a, *p);
2180            }
2181            globfree(&child->glob_result);
2182            child->argv = NULL;
2183        } else if (child->group) {
2184            debug_printf_clean("%s   begin group (subshell:%d)\n", indenter(indent), child->subshell);
2185            ret_code = free_pipe_list(child->group, indent+3);
2186            debug_printf_clean("%s   end group\n", indenter(indent));
2187        } else {
2188            debug_printf_clean("%s   (nil)\n", indenter(indent));
2189        }
2190        for (r = child->redirects; r; r = rnext) {
2191            debug_printf_clean("%s   redirect %d%s", indenter(indent), r->fd, redir_table[r->type].descrip);
2192            if (r->dup == -1) {
2193                /* guard against the case >$FOO, where foo is unset or blank */
2194                if (r->word.gl_pathv) {
2195                    debug_printf_clean(" %s\n", *r->word.gl_pathv);
2196                    globfree(&r->word);
2197                }
2198            } else {
2199                debug_printf_clean("&%d\n", r->dup);
2200            }
2201            rnext = r->next;
2202            free(r);
2203        }
2204        child->redirects = NULL;
2205    }
2206    free(pi->progs);   /* children are an array, they get freed all at once */
2207    pi->progs = NULL;
2208#if ENABLE_HUSH_JOB
2209    free(pi->cmdtext);
2210    pi->cmdtext = NULL;
2211#endif
2212    return ret_code;
2213}
2214
2215static int free_pipe_list(struct pipe *head, int indent)
2216{
2217    int rcode = 0;   /* if list has no members */
2218    struct pipe *pi, *next;
2219
2220    for (pi = head; pi; pi = next) {
2221        debug_printf_clean("%s pipe reserved mode %d\n", indenter(indent), pi->res_word);
2222        rcode = free_pipe(pi, indent);
2223        debug_printf_clean("%s pipe followup code %d\n", indenter(indent), pi->followup);
2224        next = pi->next;
2225        /*pi->next = NULL;*/
2226        free(pi);
2227    }
2228    return rcode;
2229}
2230
2231/* Select which version we will use */
2232static int run_list(struct pipe *pi)
2233{
2234    int rcode = 0;
2235    debug_printf_exec("run_list entered\n");
2236    if (fake_mode == 0) {
2237        debug_printf_exec(": run_list_real with %d members\n", pi->num_progs);
2238        rcode = run_list_real(pi);
2239    }
2240    /* free_pipe_list has the side effect of clearing memory.
2241     * In the long run that function can be merged with run_list_real,
2242     * but doing that now would hobble the debugging effort. */
2243    free_pipe_list(pi, 0);
2244    debug_printf_exec("run_list return %d\n", rcode);
2245    return rcode;
2246}
2247
2248/* The API for glob is arguably broken.  This routine pushes a non-matching
2249 * string into the output structure, removing non-backslashed backslashes.
2250 * If someone can prove me wrong, by performing this function within the
2251 * original glob(3) api, feel free to rewrite this routine into oblivion.
2252 * Return code (0 vs. GLOB_NOSPACE) matches glob(3).
2253 * XXX broken if the last character is '\\', check that before calling.
2254 */
2255static int globhack(const char *src, int flags, glob_t *pglob)
2256{
2257    int cnt = 0, pathc;
2258    const char *s;
2259    char *dest;
2260    for (cnt = 1, s = src; s && *s; s++) {
2261        if (*s == '\\') s++;
2262        cnt++;
2263    }
2264    dest = xmalloc(cnt);
2265    if (!(flags & GLOB_APPEND)) {
2266        pglob->gl_pathv = NULL;
2267        pglob->gl_pathc = 0;
2268        pglob->gl_offs = 0;
2269        pglob->gl_offs = 0;
2270    }
2271    pathc = ++pglob->gl_pathc;
2272    pglob->gl_pathv = xrealloc(pglob->gl_pathv, (pathc+1) * sizeof(*pglob->gl_pathv));
2273    pglob->gl_pathv[pathc-1] = dest;
2274    pglob->gl_pathv[pathc] = NULL;
2275    for (s = src; s && *s; s++, dest++) {
2276        if (*s == '\\') s++;
2277        *dest = *s;
2278    }
2279    *dest = '\0';
2280    return 0;
2281}
2282
2283/* XXX broken if the last character is '\\', check that before calling */
2284static int glob_needed(const char *s)
2285{
2286    for (; *s; s++) {
2287        if (*s == '\\') s++;
2288        if (strchr("*[?", *s)) return 1;
2289    }
2290    return 0;
2291}
2292
2293static int xglob(o_string *dest, int flags, glob_t *pglob)
2294{
2295    int gr;
2296
2297    /* short-circuit for null word */
2298    /* we can code this better when the debug_printf's are gone */
2299    if (dest->length == 0) {
2300        if (dest->nonnull) {
2301            /* bash man page calls this an "explicit" null */
2302            gr = globhack(dest->data, flags, pglob);
2303            debug_printf("globhack returned %d\n", gr);
2304        } else {
2305            return 0;
2306        }
2307    } else if (glob_needed(dest->data)) {
2308        gr = glob(dest->data, flags, NULL, pglob);
2309        debug_printf("glob returned %d\n", gr);
2310        if (gr == GLOB_NOMATCH) {
2311            /* quote removal, or more accurately, backslash removal */
2312            gr = globhack(dest->data, flags, pglob);
2313            debug_printf("globhack returned %d\n", gr);
2314        }
2315    } else {
2316        gr = globhack(dest->data, flags, pglob);
2317        debug_printf("globhack returned %d\n", gr);
2318    }
2319    if (gr == GLOB_NOSPACE)
2320        bb_error_msg_and_die("out of memory during glob");
2321    if (gr != 0) { /* GLOB_ABORTED ? */
2322        bb_error_msg("glob(3) error %d", gr);
2323    }
2324    /* globprint(glob_target); */
2325    return gr;
2326}
2327
2328/* expand_strvec_to_strvec() takes a list of strings, expands
2329 * all variable references within and returns a pointer to
2330 * a list of expanded strings, possibly with larger number
2331 * of strings. (Think VAR="a b"; echo $VAR).
2332 * This new list is allocated as a single malloc block.
2333 * NULL-terminated list of char* pointers is at the beginning of it,
2334 * followed by strings themself.
2335 * Caller can deallocate entire list by single free(list). */
2336
2337/* Helpers first:
2338 * count_XXX estimates size of the block we need. It's okay
2339 * to over-estimate sizes a bit, if it makes code simpler */
2340static int count_ifs(const char *str)
2341{
2342    int cnt = 0;
2343    debug_printf_expand("count_ifs('%s') ifs='%s'", str, ifs);
2344    while (1) {
2345        str += strcspn(str, ifs);
2346        if (!*str) break;
2347        str++; /* str += strspn(str, ifs); */
2348        cnt++; /* cnt += strspn(str, ifs); - but this code is larger */
2349    }
2350    debug_printf_expand(" return %d\n", cnt);
2351    return cnt;
2352}
2353
2354static void count_var_expansion_space(int *countp, int *lenp, char *arg)
2355{
2356    char first_ch;
2357    int i;
2358    int len = *lenp;
2359    int count = *countp;
2360    const char *val;
2361    char *p;
2362
2363    while ((p = strchr(arg, SPECIAL_VAR_SYMBOL))) {
2364        len += p - arg;
2365        arg = ++p;
2366        p = strchr(p, SPECIAL_VAR_SYMBOL);
2367        first_ch = arg[0];
2368
2369        switch (first_ch & 0x7f) {
2370        /* high bit in 1st_ch indicates that var is double-quoted */
2371        case '$': /* pid */
2372        case '!': /* bg pid */
2373        case '?': /* exitcode */
2374        case '#': /* argc */
2375            len += sizeof(int)*3 + 1; /* enough for int */
2376            break;
2377        case '*':
2378        case '@':
2379            for (i = 1; i < global_argc; i++) {
2380                len += strlen(global_argv[i]) + 1;
2381                count++;
2382                if (!(first_ch & 0x80))
2383                    count += count_ifs(global_argv[i]);
2384            }
2385            break;
2386        default:
2387            *p = '\0';
2388            arg[0] = first_ch & 0x7f;
2389            if (isdigit(arg[0])) {
2390                i = xatoi_u(arg);
2391                val = NULL;
2392                if (i < global_argc)
2393                    val = global_argv[i];
2394            } else
2395                val = lookup_param(arg);
2396            arg[0] = first_ch;
2397            *p = SPECIAL_VAR_SYMBOL;
2398
2399            if (val) {
2400                len += strlen(val) + 1;
2401                if (!(first_ch & 0x80))
2402                    count += count_ifs(val);
2403            }
2404        }
2405        arg = ++p;
2406    }
2407
2408    len += strlen(arg) + 1;
2409    count++;
2410    *lenp = len;
2411    *countp = count;
2412}
2413
2414/* Store given string, finalizing the word and starting new one whenever
2415 * we encounter ifs char(s). This is used for expanding variable values.
2416 * End-of-string does NOT finalize word: think about 'echo -$VAR-' */
2417static int expand_on_ifs(char **list, int n, char **posp, const char *str)
2418{
2419    char *pos = *posp;
2420    while (1) {
2421        int word_len = strcspn(str, ifs);
2422        if (word_len) {
2423            memcpy(pos, str, word_len); /* store non-ifs chars */
2424            pos += word_len;
2425            str += word_len;
2426        }
2427        if (!*str)  /* EOL - do not finalize word */
2428            break;
2429        *pos++ = '\0';
2430        if (n) debug_printf_expand("expand_on_ifs finalized list[%d]=%p '%s' "
2431            "strlen=%d next=%p pos=%p\n", n-1, list[n-1], list[n-1],
2432            strlen(list[n-1]), list[n-1] + strlen(list[n-1]) + 1, pos);
2433        list[n++] = pos;
2434        str += strspn(str, ifs); /* skip ifs chars */
2435    }
2436    *posp = pos;
2437    return n;
2438}
2439
2440/* Expand all variable references in given string, adding words to list[]
2441 * at n, n+1,... positions. Return updated n (so that list[n] is next one
2442 * to be filled). This routine is extremely tricky: has to deal with
2443 * variables/parameters with whitespace, $* and $@, and constructs like
2444 * 'echo -$*-'. If you play here, you must run testsuite afterwards! */
2445/* NB: another bug is that we cannot detect empty strings yet:
2446 * "" or $empty"" expands to zero words, has to expand to empty word */
2447static int expand_vars_to_list(char **list, int n, char **posp, char *arg, char or_mask)
2448{
2449    /* or_mask is either 0 (normal case) or 0x80
2450     * (expansion of right-hand side of assignment == 1-element expand) */
2451
2452    char first_ch, ored_ch;
2453    int i;
2454    const char *val;
2455    char *p;
2456    char *pos = *posp;
2457
2458    ored_ch = 0;
2459
2460    if (n) debug_printf_expand("expand_vars_to_list finalized list[%d]=%p '%s' "
2461        "strlen=%d next=%p pos=%p\n", n-1, list[n-1], list[n-1],
2462        strlen(list[n-1]), list[n-1] + strlen(list[n-1]) + 1, pos);
2463    list[n++] = pos;
2464
2465    while ((p = strchr(arg, SPECIAL_VAR_SYMBOL))) {
2466        memcpy(pos, arg, p - arg);
2467        pos += (p - arg);
2468        arg = ++p;
2469        p = strchr(p, SPECIAL_VAR_SYMBOL);
2470
2471        first_ch = arg[0] | or_mask; /* forced to "quoted" if or_mask = 0x80 */
2472        ored_ch |= first_ch;
2473        val = NULL;
2474        switch (first_ch & 0x7f) {
2475        /* Highest bit in first_ch indicates that var is double-quoted */
2476        case '$': /* pid */
2477            /* FIXME: (echo $$) should still print pid of main shell */
2478            val = utoa(getpid());
2479            break;
2480        case '!': /* bg pid */
2481            val = last_bg_pid ? utoa(last_bg_pid) : (char*)"";
2482            break;
2483        case '?': /* exitcode */
2484            val = utoa(last_return_code);
2485            break;
2486        case '#': /* argc */
2487            val = utoa(global_argc ? global_argc-1 : 0);
2488            break;
2489        case '*':
2490        case '@':
2491            i = 1;
2492            if (!(first_ch & 0x80)) { /* unquoted $* or $@ */
2493                while (i < global_argc) {
2494                    n = expand_on_ifs(list, n, &pos, global_argv[i]);
2495                    debug_printf_expand("expand_vars_to_list: argv %d (last %d)\n", i, global_argc-1);
2496                    if (global_argv[i++][0] && i < global_argc) {
2497                        /* this argv[] is not empty and not last:
2498                         * put terminating NUL, start new word */
2499                        *pos++ = '\0';
2500                        if (n) debug_printf_expand("expand_vars_to_list 2 finalized list[%d]=%p '%s' "
2501                            "strlen=%d next=%p pos=%p\n", n-1, list[n-1], list[n-1],
2502                            strlen(list[n-1]), list[n-1] + strlen(list[n-1]) + 1, pos);
2503                        list[n++] = pos;
2504                    }
2505                }
2506            } else
2507            /* If or_mask is nonzero, we handle assignment 'a=....$@.....'
2508             * and in this case should theat it like '$*' */
2509            if (first_ch == ('@'|0x80) && !or_mask) { /* quoted $@ */
2510                while (1) {
2511                    strcpy(pos, global_argv[i]);
2512                    pos += strlen(global_argv[i]);
2513                    if (++i >= global_argc)
2514                        break;
2515                    *pos++ = '\0';
2516                    if (n) debug_printf_expand("expand_vars_to_list 3 finalized list[%d]=%p '%s' "
2517                        "strlen=%d next=%p pos=%p\n", n-1, list[n-1], list[n-1],
2518                            strlen(list[n-1]), list[n-1] + strlen(list[n-1]) + 1, pos);
2519                    list[n++] = pos;
2520                }
2521            } else { /* quoted $*: add as one word */
2522                while (1) {
2523                    strcpy(pos, global_argv[i]);
2524                    pos += strlen(global_argv[i]);
2525                    if (++i >= global_argc)
2526                        break;
2527                    if (ifs[0])
2528                        *pos++ = ifs[0];
2529                }
2530            }
2531            break;
2532        default:
2533            *p = '\0';
2534            arg[0] = first_ch & 0x7f;
2535            if (isdigit(arg[0])) {
2536                i = xatoi_u(arg);
2537                val = NULL;
2538                if (i < global_argc)
2539                    val = global_argv[i];
2540            } else
2541                val = lookup_param(arg);
2542            arg[0] = first_ch;
2543            *p = SPECIAL_VAR_SYMBOL;
2544            if (!(first_ch & 0x80)) { /* unquoted $VAR */
2545                if (val) {
2546                    n = expand_on_ifs(list, n, &pos, val);
2547                    val = NULL;
2548                }
2549            } /* else: quoted $VAR, val will be appended at pos */
2550        }
2551        if (val) {
2552            strcpy(pos, val);
2553            pos += strlen(val);
2554        }
2555        arg = ++p;
2556    }
2557    debug_printf_expand("expand_vars_to_list adding tail '%s' at %p\n", arg, pos);
2558    strcpy(pos, arg);
2559    pos += strlen(arg) + 1;
2560    if (pos == list[n-1] + 1) { /* expansion is empty */
2561        if (!(ored_ch & 0x80)) { /* all vars were not quoted... */
2562            debug_printf_expand("expand_vars_to_list list[%d] empty, going back\n", n);
2563            pos--;
2564            n--;
2565        }
2566    }
2567
2568    *posp = pos;
2569    return n;
2570}
2571
2572static char **expand_variables(char **argv, char or_mask)
2573{
2574    int n;
2575    int count = 1;
2576    int len = 0;
2577    char *pos, **v, **list;
2578
2579    v = argv;
2580    if (!*v) debug_printf_expand("count_var_expansion_space: "
2581            "argv[0]=NULL count=%d len=%d alloc_space=%d\n",
2582            count, len, sizeof(char*) * count + len);
2583    while (*v) {
2584        count_var_expansion_space(&count, &len, *v);
2585        debug_printf_expand("count_var_expansion_space: "
2586            "'%s' count=%d len=%d alloc_space=%d\n",
2587            *v, count, len, sizeof(char*) * count + len);
2588        v++;
2589    }
2590    len += sizeof(char*) * count; /* total to alloc */
2591    list = xmalloc(len);
2592    pos = (char*)(list + count);
2593    debug_printf_expand("list=%p, list[0] should be %p\n", list, pos);
2594    n = 0;
2595    v = argv;
2596    while (*v)
2597        n = expand_vars_to_list(list, n, &pos, *v++, or_mask);
2598
2599    if (n) debug_printf_expand("finalized list[%d]=%p '%s' "
2600        "strlen=%d next=%p pos=%p\n", n-1, list[n-1], list[n-1],
2601        strlen(list[n-1]), list[n-1] + strlen(list[n-1]) + 1, pos);
2602    list[n] = NULL;
2603
2604#ifdef DEBUG_EXPAND
2605    {
2606        int m = 0;
2607        while (m <= n) {
2608            debug_printf_expand("list[%d]=%p '%s'\n", m, list[m], list[m]);
2609            m++;
2610        }
2611        debug_printf_expand("used_space=%d\n", pos - (char*)list);
2612    }
2613#endif
2614    if (ENABLE_HUSH_DEBUG)
2615        if (pos - (char*)list > len)
2616            bb_error_msg_and_die("BUG in varexp");
2617    return list;
2618}
2619
2620static char **expand_strvec_to_strvec(char **argv)
2621{
2622    return expand_variables(argv, 0);
2623}
2624
2625static char *expand_string_to_string(const char *str)
2626{
2627    char *argv[2], **list;
2628
2629    argv[0] = (char*)str;
2630    argv[1] = NULL;
2631    list = expand_variables(argv, 0x80); /* 0x80: make one-element expansion */
2632    if (ENABLE_HUSH_DEBUG)
2633        if (!list[0] || list[1])
2634            bb_error_msg_and_die("BUG in varexp2");
2635    /* actually, just move string 2*sizeof(char*) bytes back */
2636    strcpy((char*)list, list[0]);
2637    debug_printf_expand("string_to_string='%s'\n", (char*)list);
2638    return (char*)list;
2639}
2640
2641static char* expand_strvec_to_string(char **argv)
2642{
2643    char **list;
2644
2645    list = expand_variables(argv, 0x80);
2646    /* Convert all NULs to spaces */
2647    if (list[0]) {
2648        int n = 1;
2649        while (list[n]) {
2650            if (ENABLE_HUSH_DEBUG)
2651                if (list[n-1] + strlen(list[n-1]) + 1 != list[n])
2652                    bb_error_msg_and_die("BUG in varexp3");
2653            list[n][-1] = ' '; /* TODO: or to ifs[0]? */
2654            n++;
2655        }
2656    }
2657    strcpy((char*)list, list[0]);
2658    debug_printf_expand("strvec_to_string='%s'\n", (char*)list);
2659    return (char*)list;
2660}
2661
2662/* This is used to get/check local shell variables */
2663static struct variable *get_local_var(const char *name)
2664{
2665    struct variable *cur;
2666    int len;
2667
2668    if (!name)
2669        return NULL;
2670    len = strlen(name);
2671    for (cur = top_var; cur; cur = cur->next) {
2672        if (strncmp(cur->varstr, name, len) == 0 && cur->varstr[len] == '=')
2673            return cur;
2674    }
2675    return NULL;
2676}
2677
2678/* str holds "NAME=VAL" and is expected to be malloced.
2679 * We take ownership of it. */
2680static int set_local_var(char *str, int flg_export)
2681{
2682    struct variable *cur;
2683    char *value;
2684    int name_len;
2685
2686    value = strchr(str, '=');
2687    if (!value) { /* not expected to ever happen? */
2688        free(str);
2689        return -1;
2690    }
2691
2692    name_len = value - str + 1; /* including '=' */
2693    cur = top_var; /* cannot be NULL (we have HUSH_VERSION and it's RO) */
2694    while (1) {
2695        if (strncmp(cur->varstr, str, name_len) != 0) {
2696            if (!cur->next) {
2697                /* Bail out. Note that now cur points
2698                 * to last var in linked list */
2699                break;
2700            }
2701            cur = cur->next;
2702            continue;
2703        }
2704        /* We found an existing var with this name */
2705        *value = '\0';
2706        if (cur->flg_read_only) {
2707            bb_error_msg("%s: readonly variable", str);
2708            free(str);
2709            return -1;
2710        }
2711        unsetenv(str); /* just in case */
2712        *value = '=';
2713        if (strcmp(cur->varstr, str) == 0) {
2714 free_and_exp:
2715            free(str);
2716            goto exp;
2717        }
2718        if (cur->max_len >= strlen(str)) {
2719            /* This one is from startup env, reuse space */
2720            strcpy(cur->varstr, str);
2721            goto free_and_exp;
2722        }
2723        /* max_len == 0 signifies "malloced" var, which we can
2724         * (and has to) free */
2725        if (!cur->max_len)
2726            free(cur->varstr);
2727        cur->max_len = 0;
2728        goto set_str_and_exp;
2729    }
2730
2731    /* Not found - create next variable struct */
2732    cur->next = xzalloc(sizeof(*cur));
2733    cur = cur->next;
2734
2735 set_str_and_exp:
2736    cur->varstr = str;
2737 exp:
2738    if (flg_export)
2739        cur->flg_export = 1;
2740    if (cur->flg_export)
2741        return putenv(cur->varstr);
2742    return 0;
2743}
2744
2745static void unset_local_var(const char *name)
2746{
2747    struct variable *cur;
2748    struct variable *prev = prev; /* for gcc */
2749    int name_len;
2750
2751    if (!name)
2752        return;
2753    name_len = strlen(name);
2754    cur = top_var;
2755    while (cur) {
2756        if (strncmp(cur->varstr, name, name_len) == 0 && cur->varstr[name_len] == '=') {
2757            if (cur->flg_read_only) {
2758                bb_error_msg("%s: readonly variable", name);
2759                return;
2760            }
2761        /* prev is ok to use here because 1st variable, HUSH_VERSION,
2762         * is ro, and we cannot reach this code on the 1st pass */
2763            prev->next = cur->next;
2764            unsetenv(cur->varstr);
2765            if (!cur->max_len)
2766                free(cur->varstr);
2767            free(cur);
2768            return;
2769        }
2770        prev = cur;
2771        cur = cur->next;
2772    }
2773}
2774
2775static int is_assignment(const char *s)
2776{
2777    if (!s || !isalpha(*s))
2778        return 0;
2779    s++;
2780    while (isalnum(*s) || *s == '_')
2781        s++;
2782    return *s == '=';
2783}
2784
2785/* the src parameter allows us to peek forward to a possible &n syntax
2786 * for file descriptor duplication, e.g., "2>&1".
2787 * Return code is 0 normally, 1 if a syntax error is detected in src.
2788 * Resource errors (in xmalloc) cause the process to exit */
2789static int setup_redirect(struct p_context *ctx, int fd, redir_type style,
2790    struct in_str *input)
2791{
2792    struct child_prog *child = ctx->child;
2793    struct redir_struct *redir = child->redirects;
2794    struct redir_struct *last_redir = NULL;
2795
2796    /* Create a new redir_struct and drop it onto the end of the linked list */
2797    while (redir) {
2798        last_redir = redir;
2799        redir = redir->next;
2800    }
2801    redir = xmalloc(sizeof(struct redir_struct));
2802    redir->next = NULL;
2803    redir->word.gl_pathv = NULL;
2804    if (last_redir) {
2805        last_redir->next = redir;
2806    } else {
2807        child->redirects = redir;
2808    }
2809
2810    redir->type = style;
2811    redir->fd = (fd == -1) ? redir_table[style].default_fd : fd;
2812
2813    debug_printf("Redirect type %d%s\n", redir->fd, redir_table[style].descrip);
2814
2815    /* Check for a '2>&1' type redirect */
2816    redir->dup = redirect_dup_num(input);
2817    if (redir->dup == -2) return 1;  /* syntax error */
2818    if (redir->dup != -1) {
2819        /* Erik had a check here that the file descriptor in question
2820         * is legit; I postpone that to "run time"
2821         * A "-" representation of "close me" shows up as a -3 here */
2822        debug_printf("Duplicating redirect '%d>&%d'\n", redir->fd, redir->dup);
2823    } else {
2824        /* We do _not_ try to open the file that src points to,
2825         * since we need to return and let src be expanded first.
2826         * Set ctx->pending_redirect, so we know what to do at the
2827         * end of the next parsed word. */
2828        ctx->pending_redirect = redir;
2829    }
2830    return 0;
2831}
2832
2833static struct pipe *new_pipe(void)
2834{
2835    struct pipe *pi;
2836    pi = xzalloc(sizeof(struct pipe));
2837    /*pi->num_progs = 0;*/
2838    /*pi->progs = NULL;*/
2839    /*pi->next = NULL;*/
2840    /*pi->followup = 0;  invalid */
2841    if (RES_NONE)
2842        pi->res_word = RES_NONE;
2843    return pi;
2844}
2845
2846static void initialize_context(struct p_context *ctx)
2847{
2848    ctx->child = NULL;
2849    ctx->pipe = ctx->list_head = new_pipe();
2850    ctx->pending_redirect = NULL;
2851    ctx->res_w = RES_NONE;
2852    //only ctx->parse_type is not touched... is this intentional?
2853    ctx->old_flag = 0;
2854    ctx->stack = NULL;
2855    done_command(ctx);   /* creates the memory for working child */
2856}
2857
2858/* normal return is 0
2859 * if a reserved word is found, and processed, return 1
2860 * should handle if, then, elif, else, fi, for, while, until, do, done.
2861 * case, function, and select are obnoxious, save those for later.
2862 */
2863#if ENABLE_HUSH_IF || ENABLE_HUSH_LOOPS
2864static int reserved_word(o_string *dest, struct p_context *ctx)
2865{
2866    struct reserved_combo {
2867        char literal[7];
2868        unsigned char code;
2869        int flag;
2870    };
2871    /* Mostly a list of accepted follow-up reserved words.
2872     * FLAG_END means we are done with the sequence, and are ready
2873     * to turn the compound list into a command.
2874     * FLAG_START means the word must start a new compound list.
2875     */
2876    static const struct reserved_combo reserved_list[] = {
2877#if ENABLE_HUSH_IF
2878        { "if",    RES_IF,    FLAG_THEN | FLAG_START },
2879        { "then",  RES_THEN,  FLAG_ELIF | FLAG_ELSE | FLAG_FI },
2880        { "elif",  RES_ELIF,  FLAG_THEN },
2881        { "else",  RES_ELSE,  FLAG_FI   },
2882        { "fi",    RES_FI,    FLAG_END  },
2883#endif
2884#if ENABLE_HUSH_LOOPS
2885        { "for",   RES_FOR,   FLAG_IN   | FLAG_START },
2886        { "while", RES_WHILE, FLAG_DO   | FLAG_START },
2887        { "until", RES_UNTIL, FLAG_DO   | FLAG_START },
2888        { "in",    RES_IN,    FLAG_DO   },
2889        { "do",    RES_DO,    FLAG_DONE },
2890        { "done",  RES_DONE,  FLAG_END  }
2891#endif
2892    };
2893
2894    const struct reserved_combo *r;
2895
2896    for (r = reserved_list; r < reserved_list + ARRAY_SIZE(reserved_list); r++) {
2897        if (strcmp(dest->data, r->literal) != 0)
2898            continue;
2899        debug_printf("found reserved word %s, code %d\n", r->literal, r->code);
2900        if (r->flag & FLAG_START) {
2901            struct p_context *new;
2902            debug_printf("push stack\n");
2903#if ENABLE_HUSH_LOOPS
2904            if (ctx->res_w == RES_IN || ctx->res_w == RES_FOR) {
2905                syntax("malformed for"); /* example: 'for if' */
2906                ctx->res_w = RES_SNTX;
2907                b_reset(dest);
2908                return 1;
2909            }
2910#endif
2911            new = xmalloc(sizeof(*new));
2912            *new = *ctx;   /* physical copy */
2913            initialize_context(ctx);
2914            ctx->stack = new;
2915        } else if (ctx->res_w == RES_NONE || !(ctx->old_flag & (1 << r->code))) {
2916            syntax(NULL);
2917            ctx->res_w = RES_SNTX;
2918            b_reset(dest);
2919            return 1;
2920        }
2921        ctx->res_w = r->code;
2922        ctx->old_flag = r->flag;
2923        if (ctx->old_flag & FLAG_END) {
2924            struct p_context *old;
2925            debug_printf("pop stack\n");
2926            done_pipe(ctx, PIPE_SEQ);
2927            old = ctx->stack;
2928            old->child->group = ctx->list_head;
2929            old->child->subshell = 0;
2930            *ctx = *old;   /* physical copy */
2931            free(old);
2932        }
2933        b_reset(dest);
2934        return 1;
2935    }
2936    return 0;
2937}
2938#else
2939#define reserved_word(dest, ctx) ((int)0)
2940#endif
2941
2942/* Normal return is 0.
2943 * Syntax or xglob errors return 1. */
2944static int done_word(o_string *dest, struct p_context *ctx)
2945{
2946    struct child_prog *child = ctx->child;
2947    glob_t *glob_target;
2948    int gr, flags = 0;
2949
2950    debug_printf_parse("done_word entered: '%s' %p\n", dest->data, child);
2951    if (dest->length == 0 && !dest->nonnull) {
2952        debug_printf_parse("done_word return 0: true null, ignored\n");
2953        return 0;
2954    }
2955    if (ctx->pending_redirect) {
2956        glob_target = &ctx->pending_redirect->word;
2957    } else {
2958        if (child->group) {
2959            syntax(NULL);
2960            debug_printf_parse("done_word return 1: syntax error, groups and arglists don't mix\n");
2961            return 1;
2962        }
2963        if (!child->argv && (ctx->parse_type & PARSEFLAG_SEMICOLON)) {
2964            debug_printf_parse(": checking '%s' for reserved-ness\n", dest->data);
2965            if (reserved_word(dest, ctx)) {
2966                debug_printf_parse("done_word return %d\n", (ctx->res_w == RES_SNTX));
2967                return (ctx->res_w == RES_SNTX);
2968            }
2969        }
2970        glob_target = &child->glob_result;
2971        if (child->argv)
2972            flags |= GLOB_APPEND;
2973    }
2974    gr = xglob(dest, flags, glob_target);
2975    if (gr != 0) {
2976        debug_printf_parse("done_word return 1: xglob returned %d\n", gr);
2977        return 1;
2978    }
2979
2980    b_reset(dest);
2981    if (ctx->pending_redirect) {
2982        ctx->pending_redirect = NULL;
2983        if (glob_target->gl_pathc != 1) {
2984            bb_error_msg("ambiguous redirect");
2985            debug_printf_parse("done_word return 1: ambiguous redirect\n");
2986            return 1;
2987        }
2988    } else {
2989        child->argv = glob_target->gl_pathv;
2990    }
2991#if ENABLE_HUSH_LOOPS
2992    if (ctx->res_w == RES_FOR) {
2993        done_word(dest, ctx);
2994        done_pipe(ctx, PIPE_SEQ);
2995    }
2996#endif
2997    debug_printf_parse("done_word return 0\n");
2998    return 0;
2999}
3000
3001/* The only possible error here is out of memory, in which case
3002 * xmalloc exits. */
3003static int done_command(struct p_context *ctx)
3004{
3005    /* The child is really already in the pipe structure, so
3006     * advance the pipe counter and make a new, null child. */
3007    struct pipe *pi = ctx->pipe;
3008    struct child_prog *child = ctx->child;
3009
3010    if (child) {
3011        if (child->group == NULL
3012         && child->argv == NULL
3013         && child->redirects == NULL
3014        ) {
3015            debug_printf_parse("done_command: skipping null cmd, num_progs=%d\n", pi->num_progs);
3016            return pi->num_progs;
3017        }
3018        pi->num_progs++;
3019        debug_printf_parse("done_command: ++num_progs=%d\n", pi->num_progs);
3020    } else {
3021        debug_printf_parse("done_command: initializing, num_progs=%d\n", pi->num_progs);
3022    }
3023
3024    /* Only real trickiness here is that the uncommitted
3025     * child structure is not counted in pi->num_progs. */
3026    pi->progs = xrealloc(pi->progs, sizeof(*pi->progs) * (pi->num_progs+1));
3027    child = &pi->progs[pi->num_progs];
3028
3029    memset(child, 0, sizeof(*child));
3030    /*child->redirects = NULL;*/
3031    /*child->argv = NULL;*/
3032    /*child->is_stopped = 0;*/
3033    /*child->group = NULL;*/
3034    /*child->glob_result.gl_pathv = NULL;*/
3035    child->family = pi;
3036    //sp: /*child->sp = 0;*/
3037    //pt: child->parse_type = ctx->parse_type;
3038
3039    ctx->child = child;
3040    /* but ctx->pipe and ctx->list_head remain unchanged */
3041
3042    return pi->num_progs; /* used only for 0/nonzero check */
3043}
3044
3045static int done_pipe(struct p_context *ctx, pipe_style type)
3046{
3047    struct pipe *new_p;
3048    int not_null;
3049
3050    debug_printf_parse("done_pipe entered, followup %d\n", type);
3051    not_null = done_command(ctx);  /* implicit closure of previous command */
3052    ctx->pipe->followup = type;
3053    ctx->pipe->res_word = ctx->res_w;
3054    /* Without this check, even just <enter> on command line generates
3055     * tree of three NOPs (!). Which is harmless but annoying.
3056     * IOW: it is safe to do it unconditionally. */
3057    if (not_null) {
3058        new_p = new_pipe();
3059        ctx->pipe->next = new_p;
3060        ctx->pipe = new_p;
3061        ctx->child = NULL;
3062        done_command(ctx);  /* set up new pipe to accept commands */
3063    }
3064    debug_printf_parse("done_pipe return 0\n");
3065    return 0;
3066}
3067
3068/* peek ahead in the in_str to find out if we have a "&n" construct,
3069 * as in "2>&1", that represents duplicating a file descriptor.
3070 * returns either -2 (syntax error), -1 (no &), or the number found.
3071 */
3072static int redirect_dup_num(struct in_str *input)
3073{
3074    int ch, d = 0, ok = 0;
3075    ch = b_peek(input);
3076    if (ch != '&') return -1;
3077
3078    b_getch(input);  /* get the & */
3079    ch = b_peek(input);
3080    if (ch == '-') {
3081        b_getch(input);
3082        return -3;  /* "-" represents "close me" */
3083    }
3084    while (isdigit(ch)) {
3085        d = d*10 + (ch-'0');
3086        ok = 1;
3087        b_getch(input);
3088        ch = b_peek(input);
3089    }
3090    if (ok) return d;
3091
3092    bb_error_msg("ambiguous redirect");
3093    return -2;
3094}
3095
3096/* If a redirect is immediately preceded by a number, that number is
3097 * supposed to tell which file descriptor to redirect.  This routine
3098 * looks for such preceding numbers.  In an ideal world this routine
3099 * needs to handle all the following classes of redirects...
3100 *     echo 2>foo     # redirects fd  2 to file "foo", nothing passed to echo
3101 *     echo 49>foo    # redirects fd 49 to file "foo", nothing passed to echo
3102 *     echo -2>foo    # redirects fd  1 to file "foo",    "-2" passed to echo
3103 *     echo 49x>foo   # redirects fd  1 to file "foo",   "49x" passed to echo
3104 * A -1 output from this program means no valid number was found, so the
3105 * caller should use the appropriate default for this redirection.
3106 */
3107static int redirect_opt_num(o_string *o)
3108{
3109    int num;
3110
3111    if (o->length == 0)
3112        return -1;
3113    for (num = 0; num < o->length; num++) {
3114        if (!isdigit(*(o->data + num))) {
3115            return -1;
3116        }
3117    }
3118    /* reuse num (and save an int) */
3119    num = atoi(o->data);
3120    b_reset(o);
3121    return num;
3122}
3123
3124#if ENABLE_HUSH_TICK
3125static FILE *generate_stream_from_list(struct pipe *head)
3126{
3127    FILE *pf;
3128    int pid, channel[2];
3129
3130    xpipe(channel);
3131#if BB_MMU
3132    pid = fork();
3133#else
3134    pid = vfork();
3135#endif
3136    if (pid < 0) {
3137        bb_perror_msg_and_die("fork");
3138    } else if (pid == 0) {
3139        close(channel[0]);
3140        if (channel[1] != 1) {
3141            dup2(channel[1], 1);
3142            close(channel[1]);
3143        }
3144        /* Prevent it from trying to handle ctrl-z etc */
3145#if ENABLE_HUSH_JOB
3146        run_list_level = 1;
3147#endif
3148        /* Process substitution is not considered to be usual
3149         * 'command execution'.
3150         * SUSv3 says ctrl-Z should be ignored, ctrl-C should not. */
3151        /* Not needed, we are relying on it being disabled
3152         * everywhere outside actual command execution. */
3153        /*set_jobctrl_sighandler(SIG_IGN);*/
3154        set_misc_sighandler(SIG_DFL);
3155        _exit(run_list_real(head));   /* leaks memory */
3156    }
3157    close(channel[1]);
3158    pf = fdopen(channel[0], "r");
3159    return pf;
3160}
3161
3162/* Return code is exit status of the process that is run. */
3163static int process_command_subs(o_string *dest, struct p_context *ctx,
3164    struct in_str *input, const char *subst_end)
3165{
3166    int retcode, ch, eol_cnt;
3167    o_string result = NULL_O_STRING;
3168    struct p_context inner;
3169    FILE *p;
3170    struct in_str pipe_str;
3171
3172    initialize_context(&inner);
3173
3174    /* recursion to generate command */
3175    retcode = parse_stream(&result, &inner, input, subst_end);
3176    if (retcode != 0)
3177        return retcode;  /* syntax error or EOF */
3178    done_word(&result, &inner);
3179    done_pipe(&inner, PIPE_SEQ);
3180    b_free(&result);
3181
3182    p = generate_stream_from_list(inner.list_head);
3183    if (p == NULL) return 1;
3184    mark_open(fileno(p));
3185    setup_file_in_str(&pipe_str, p);
3186
3187    /* now send results of command back into original context */
3188    eol_cnt = 0;
3189    while ((ch = b_getch(&pipe_str)) != EOF) {
3190        if (ch == '\n') {
3191            eol_cnt++;
3192            continue;
3193        }
3194        while (eol_cnt) {
3195            b_addqchr(dest, '\n', dest->quote);
3196            eol_cnt--;
3197        }
3198        b_addqchr(dest, ch, dest->quote);
3199    }
3200
3201    debug_printf("done reading from pipe, pclose()ing\n");
3202    /* This is the step that wait()s for the child.  Should be pretty
3203     * safe, since we just read an EOF from its stdout.  We could try
3204     * to do better, by using wait(), and keeping track of background jobs
3205     * at the same time.  That would be a lot of work, and contrary
3206     * to the KISS philosophy of this program. */
3207    mark_closed(fileno(p));
3208    retcode = fclose(p);
3209    free_pipe_list(inner.list_head, 0);
3210    debug_printf("closed FILE from child, retcode=%d\n", retcode);
3211    return retcode;
3212}
3213#endif
3214
3215static int parse_group(o_string *dest, struct p_context *ctx,
3216    struct in_str *input, int ch)
3217{
3218    int rcode;
3219    const char *endch = NULL;
3220    struct p_context sub;
3221    struct child_prog *child = ctx->child;
3222
3223    debug_printf_parse("parse_group entered\n");
3224    if (child->argv) {
3225        syntax(NULL);
3226        debug_printf_parse("parse_group return 1: syntax error, groups and arglists don't mix\n");
3227        return 1;
3228    }
3229    initialize_context(&sub);
3230    endch = "}";
3231    if (ch == '(') {
3232        endch = ")";
3233        child->subshell = 1;
3234    }
3235    rcode = parse_stream(dest, &sub, input, endch);
3236//vda: err chk?
3237    done_word(dest, &sub); /* finish off the final word in the subcontext */
3238    done_pipe(&sub, PIPE_SEQ);  /* and the final command there, too */
3239    child->group = sub.list_head;
3240
3241    debug_printf_parse("parse_group return %d\n", rcode);
3242    return rcode;
3243    /* child remains "open", available for possible redirects */
3244}
3245
3246/* Basically useful version until someone wants to get fancier,
3247 * see the bash man page under "Parameter Expansion" */
3248static const char *lookup_param(const char *src)
3249{
3250    struct variable *var = get_local_var(src);
3251    if (var)
3252        return strchr(var->varstr, '=') + 1;
3253    return NULL;
3254}
3255
3256/* return code: 0 for OK, 1 for syntax error */
3257static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input)
3258{
3259    int ch = b_peek(input);  /* first character after the $ */
3260    unsigned char quote_mask = dest->quote ? 0x80 : 0;
3261
3262    debug_printf_parse("handle_dollar entered: ch='%c'\n", ch);
3263    if (isalpha(ch)) {
3264        b_addchr(dest, SPECIAL_VAR_SYMBOL);
3265        //sp: ctx->child->sp++;
3266        while (1) {
3267            debug_printf_parse(": '%c'\n", ch);
3268            b_getch(input);
3269            b_addchr(dest, ch | quote_mask);
3270            quote_mask = 0;
3271            ch = b_peek(input);
3272            if (!isalnum(ch) && ch != '_')
3273                break;
3274        }
3275        b_addchr(dest, SPECIAL_VAR_SYMBOL);
3276    } else if (isdigit(ch)) {
3277 make_one_char_var:
3278        b_addchr(dest, SPECIAL_VAR_SYMBOL);
3279        //sp: ctx->child->sp++;
3280        debug_printf_parse(": '%c'\n", ch);
3281        b_getch(input);
3282        b_addchr(dest, ch | quote_mask);
3283        b_addchr(dest, SPECIAL_VAR_SYMBOL);
3284    } else switch (ch) {
3285        case '$': /* pid */
3286        case '!': /* last bg pid */
3287        case '?': /* last exit code */
3288        case '#': /* number of args */
3289        case '*': /* args */
3290        case '@': /* args */
3291            goto make_one_char_var;
3292        case '{':
3293            b_addchr(dest, SPECIAL_VAR_SYMBOL);
3294            //sp: ctx->child->sp++;
3295            b_getch(input);
3296            /* XXX maybe someone will try to escape the '}' */
3297            while (1) {
3298                ch = b_getch(input);
3299                if (ch == '}')
3300                    break;
3301                if (!isalnum(ch) && ch != '_') {
3302                    syntax("unterminated ${name}");
3303                    debug_printf_parse("handle_dollar return 1: unterminated ${name}\n");
3304                    return 1;
3305                }
3306                debug_printf_parse(": '%c'\n", ch);
3307                b_addchr(dest, ch | quote_mask);
3308                quote_mask = 0;
3309            }
3310            b_addchr(dest, SPECIAL_VAR_SYMBOL);
3311            break;
3312#if ENABLE_HUSH_TICK
3313        case '(':
3314            b_getch(input);
3315            process_command_subs(dest, ctx, input, ")");
3316            break;
3317#endif
3318        case '-':
3319        case '_':
3320            /* still unhandled, but should be eventually */
3321            bb_error_msg("unhandled syntax: $%c", ch);
3322            return 1;
3323            break;
3324        default:
3325            b_addqchr(dest, '$', dest->quote);
3326    }
3327    debug_printf_parse("handle_dollar return 0\n");
3328    return 0;
3329}
3330
3331/* return code is 0 for normal exit, 1 for syntax error */
3332static int parse_stream(o_string *dest, struct p_context *ctx,
3333    struct in_str *input, const char *end_trigger)
3334{
3335    int ch, m;
3336    int redir_fd;
3337    redir_type redir_style;
3338    int next;
3339
3340    /* Only double-quote state is handled in the state variable dest->quote.
3341     * A single-quote triggers a bypass of the main loop until its mate is
3342     * found.  When recursing, quote state is passed in via dest->quote. */
3343
3344    debug_printf_parse("parse_stream entered, end_trigger='%s'\n", end_trigger);
3345
3346    while (1) {
3347        m = CHAR_IFS;
3348        next = '\0';
3349        ch = b_getch(input);
3350        if (ch != EOF) {
3351            m = charmap[ch];
3352            if (ch != '\n')
3353                next = b_peek(input);
3354        }
3355        debug_printf_parse(": ch=%c (%d) m=%d quote=%d\n",
3356                        ch, ch, m, dest->quote);
3357        if (m == CHAR_ORDINARY
3358         || (m != CHAR_SPECIAL && dest->quote)
3359        ) {
3360            if (ch == EOF) {
3361                syntax("unterminated \"");
3362                debug_printf_parse("parse_stream return 1: unterminated \"\n");
3363                return 1;
3364            }
3365            b_addqchr(dest, ch, dest->quote);
3366            continue;
3367        }
3368        if (m == CHAR_IFS) {
3369            if (done_word(dest, ctx)) {
3370                debug_printf_parse("parse_stream return 1: done_word!=0\n");
3371                return 1;
3372            }
3373            if (ch == EOF)
3374                break;
3375            /* If we aren't performing a substitution, treat
3376             * a newline as a command separator.
3377             * [why we don't handle it exactly like ';'? --vda] */
3378            if (end_trigger && ch == '\n') {
3379                done_pipe(ctx, PIPE_SEQ);
3380            }
3381        }
3382        if ((end_trigger && strchr(end_trigger, ch))
3383         && !dest->quote && ctx->res_w == RES_NONE
3384        ) {
3385            debug_printf_parse("parse_stream return 0: end_trigger char found\n");
3386            return 0;
3387        }
3388        if (m == CHAR_IFS)
3389            continue;
3390        switch (ch) {
3391        case '#':
3392            if (dest->length == 0 && !dest->quote) {
3393                while (1) {
3394                    ch = b_peek(input);
3395                    if (ch == EOF || ch == '\n')
3396                        break;
3397                    b_getch(input);
3398                }
3399            } else {
3400                b_addqchr(dest, ch, dest->quote);
3401            }
3402            break;
3403        case '\\':
3404            if (next == EOF) {
3405                syntax("\\<eof>");
3406                debug_printf_parse("parse_stream return 1: \\<eof>\n");
3407                return 1;
3408            }
3409            b_addqchr(dest, '\\', dest->quote);
3410            b_addqchr(dest, b_getch(input), dest->quote);
3411            break;
3412        case '$':
3413            if (handle_dollar(dest, ctx, input) != 0) {
3414                debug_printf_parse("parse_stream return 1: handle_dollar returned non-0\n");
3415                return 1;
3416            }
3417            break;
3418        case '\'':
3419            dest->nonnull = 1;
3420            while (1) {
3421                ch = b_getch(input);
3422                if (ch == EOF || ch == '\'')
3423                    break;
3424                b_addchr(dest, ch);
3425            }
3426            if (ch == EOF) {
3427                syntax("unterminated '");
3428                debug_printf_parse("parse_stream return 1: unterminated '\n");
3429                return 1;
3430            }
3431            break;
3432        case '"':
3433            dest->nonnull = 1;
3434            dest->quote = !dest->quote;
3435            break;
3436#if ENABLE_HUSH_TICK
3437        case '`':
3438            process_command_subs(dest, ctx, input, "`");
3439            break;
3440#endif
3441        case '>':
3442            redir_fd = redirect_opt_num(dest);
3443            done_word(dest, ctx);
3444            redir_style = REDIRECT_OVERWRITE;
3445            if (next == '>') {
3446                redir_style = REDIRECT_APPEND;
3447                b_getch(input);
3448            }
3449#if 0
3450            else if (next == '(') {
3451                syntax(">(process) not supported");
3452                debug_printf_parse("parse_stream return 1: >(process) not supported\n");
3453                return 1;
3454            }
3455#endif
3456            setup_redirect(ctx, redir_fd, redir_style, input);
3457            break;
3458        case '<':
3459            redir_fd = redirect_opt_num(dest);
3460            done_word(dest, ctx);
3461            redir_style = REDIRECT_INPUT;
3462            if (next == '<') {
3463                redir_style = REDIRECT_HEREIS;
3464                b_getch(input);
3465            } else if (next == '>') {
3466                redir_style = REDIRECT_IO;
3467                b_getch(input);
3468            }
3469#if 0
3470            else if (next == '(') {
3471                syntax("<(process) not supported");
3472                debug_printf_parse("parse_stream return 1: <(process) not supported\n");
3473                return 1;
3474            }
3475#endif
3476            setup_redirect(ctx, redir_fd, redir_style, input);
3477            break;
3478        case ';':
3479            done_word(dest, ctx);
3480            done_pipe(ctx, PIPE_SEQ);
3481            break;
3482        case '&':
3483            done_word(dest, ctx);
3484            if (next == '&') {
3485                b_getch(input);
3486                done_pipe(ctx, PIPE_AND);
3487            } else {
3488                done_pipe(ctx, PIPE_BG);
3489            }
3490            break;
3491        case '|':
3492            done_word(dest, ctx);
3493            if (next == '|') {
3494                b_getch(input);
3495                done_pipe(ctx, PIPE_OR);
3496            } else {
3497                /* we could pick up a file descriptor choice here
3498                 * with redirect_opt_num(), but bash doesn't do it.
3499                 * "echo foo 2| cat" yields "foo 2". */
3500                done_command(ctx);
3501            }
3502            break;
3503        case '(':
3504        case '{':
3505            if (parse_group(dest, ctx, input, ch) != 0) {
3506                debug_printf_parse("parse_stream return 1: parse_group returned non-0\n");
3507                return 1;
3508            }
3509            break;
3510        case ')':
3511        case '}':
3512            syntax("unexpected }");   /* Proper use of this character is caught by end_trigger */
3513            debug_printf_parse("parse_stream return 1: unexpected '}'\n");
3514            return 1;
3515        default:
3516            if (ENABLE_HUSH_DEBUG)
3517                bb_error_msg_and_die("BUG: unexpected %c\n", ch);
3518        }
3519    }
3520    /* Complain if quote?  No, maybe we just finished a command substitution
3521     * that was quoted.  Example:
3522     * $ echo "`cat foo` plus more"
3523     * and we just got the EOF generated by the subshell that ran "cat foo"
3524     * The only real complaint is if we got an EOF when end_trigger != NULL,
3525     * that is, we were really supposed to get end_trigger, and never got
3526     * one before the EOF.  Can't use the standard "syntax error" return code,
3527     * so that parse_stream_outer can distinguish the EOF and exit smoothly. */
3528    debug_printf_parse("parse_stream return %d\n", -(end_trigger != NULL));
3529    if (end_trigger)
3530        return -1;
3531    return 0;
3532}
3533
3534static void set_in_charmap(const char *set, int code)
3535{
3536    while (*set)
3537        charmap[(unsigned char)*set++] = code;
3538}
3539
3540static void update_charmap(void)
3541{
3542    /* char *ifs and char charmap[256] are both globals. */
3543    ifs = getenv("IFS");
3544    if (ifs == NULL)
3545        ifs = " \t\n";
3546    /* Precompute a list of 'flow through' behavior so it can be treated
3547     * quickly up front.  Computation is necessary because of IFS.
3548     * Special case handling of IFS == " \t\n" is not implemented.
3549     * The charmap[] array only really needs two bits each,
3550     * and on most machines that would be faster (reduced L1 cache use).
3551     */
3552    memset(charmap, CHAR_ORDINARY, sizeof(charmap));
3553#if ENABLE_HUSH_TICK
3554    set_in_charmap("\\$\"`", CHAR_SPECIAL);
3555#else
3556    set_in_charmap("\\$\"", CHAR_SPECIAL);
3557#endif
3558    set_in_charmap("<>;&|(){}#'", CHAR_ORDINARY_IF_QUOTED);
3559    set_in_charmap(ifs, CHAR_IFS);  /* are ordinary if quoted */
3560}
3561
3562/* most recursion does not come through here, the exception is
3563 * from builtin_source() and builtin_eval() */
3564static int parse_and_run_stream(struct in_str *inp, int parse_flag)
3565{
3566    struct p_context ctx;
3567    o_string temp = NULL_O_STRING;
3568    int rcode;
3569    do {
3570        ctx.parse_type = parse_flag;
3571        initialize_context(&ctx);
3572        update_charmap();
3573        if (!(parse_flag & PARSEFLAG_SEMICOLON) || (parse_flag & PARSEFLAG_REPARSING))
3574            set_in_charmap(";$&|", CHAR_ORDINARY);
3575#if ENABLE_HUSH_INTERACTIVE
3576        inp->promptmode = 0; /* PS1 */
3577#endif
3578        /* We will stop & execute after each ';' or '\n'.
3579         * Example: "sleep 9999; echo TEST" + ctrl-C:
3580         * TEST should be printed */
3581        rcode = parse_stream(&temp, &ctx, inp, ";\n");
3582        if (rcode != 1 && ctx.old_flag != 0) {
3583            syntax(NULL);
3584        }
3585        if (rcode != 1 && ctx.old_flag == 0) {
3586            done_word(&temp, &ctx);
3587            done_pipe(&ctx, PIPE_SEQ);
3588            debug_print_tree(ctx.list_head, 0);
3589            debug_printf_exec("parse_stream_outer: run_list\n");
3590            run_list(ctx.list_head);
3591        } else {
3592            if (ctx.old_flag != 0) {
3593                free(ctx.stack);
3594                b_reset(&temp);
3595            }
3596            temp.nonnull = 0;
3597            temp.quote = 0;
3598            inp->p = NULL;
3599            free_pipe_list(ctx.list_head, 0);
3600        }
3601        b_free(&temp);
3602    } while (rcode != -1 && !(parse_flag & PARSEFLAG_EXIT_FROM_LOOP));   /* loop on syntax errors, return on EOF */
3603    return 0;
3604}
3605
3606static int parse_and_run_string(const char *s, int parse_flag)
3607{
3608    struct in_str input;
3609    setup_string_in_str(&input, s);
3610    return parse_and_run_stream(&input, parse_flag);
3611}
3612
3613static int parse_and_run_file(FILE *f)
3614{
3615    int rcode;
3616    struct in_str input;
3617    setup_file_in_str(&input, f);
3618    rcode = parse_and_run_stream(&input, PARSEFLAG_SEMICOLON);
3619    return rcode;
3620}
3621
3622#if ENABLE_HUSH_JOB
3623/* Make sure we have a controlling tty.  If we get started under a job
3624 * aware app (like bash for example), make sure we are now in charge so
3625 * we don't fight over who gets the foreground */
3626static void setup_job_control(void)
3627{
3628    pid_t shell_pgrp;
3629
3630    saved_task_pgrp = shell_pgrp = getpgrp();
3631    debug_printf_jobs("saved_task_pgrp=%d\n", saved_task_pgrp);
3632    fcntl(interactive_fd, F_SETFD, FD_CLOEXEC);
3633
3634    /* If we were ran as 'hush &',
3635     * sleep until we are in the foreground.  */
3636    while (tcgetpgrp(interactive_fd) != shell_pgrp) {
3637        /* Send TTIN to ourself (should stop us) */
3638        kill(- shell_pgrp, SIGTTIN);
3639        shell_pgrp = getpgrp();
3640    }
3641
3642    /* Ignore job-control and misc signals.  */
3643    set_jobctrl_sighandler(SIG_IGN);
3644    set_misc_sighandler(SIG_IGN);
3645//huh?  signal(SIGCHLD, SIG_IGN);
3646
3647    /* We _must_ restore tty pgrp on fatal signals */
3648    set_fatal_sighandler(sigexit);
3649
3650    /* Put ourselves in our own process group.  */
3651    setpgrp(); /* is the same as setpgid(our_pid, our_pid); */
3652    /* Grab control of the terminal.  */
3653    tcsetpgrp(interactive_fd, getpid());
3654}
3655#endif
3656
3657int hush_main(int argc, char **argv);
3658int hush_main(int argc, char **argv)
3659{
3660    static const char version_str[] ALIGN1 = "HUSH_VERSION="HUSH_VER_STR;
3661    static const struct variable const_shell_ver = {
3662        .next = NULL,
3663        .varstr = (char*)version_str,
3664        .max_len = 1, /* 0 can provoke free(name) */
3665        .flg_export = 1,
3666        .flg_read_only = 1,
3667    };
3668
3669    int opt;
3670    FILE *input;
3671    char **e;
3672    struct variable *cur_var;
3673
3674    PTR_TO_GLOBALS = xzalloc(sizeof(G));
3675
3676    /* Deal with HUSH_VERSION */
3677    shell_ver = const_shell_ver; /* copying struct here */
3678    top_var = &shell_ver;
3679    unsetenv("HUSH_VERSION"); /* in case it exists in initial env */
3680    /* Initialize our shell local variables with the values
3681     * currently living in the environment */
3682    cur_var = top_var;
3683    e = environ;
3684    if (e) while (*e) {
3685        char *value = strchr(*e, '=');
3686        if (value) { /* paranoia */
3687            cur_var->next = xzalloc(sizeof(*cur_var));
3688            cur_var = cur_var->next;
3689            cur_var->varstr = *e;
3690            cur_var->max_len = strlen(*e);
3691            cur_var->flg_export = 1;
3692        }
3693        e++;
3694    }
3695    putenv((char *)version_str); /* reinstate HUSH_VERSION */
3696
3697#if ENABLE_FEATURE_EDITING
3698    line_input_state = new_line_input_t(FOR_SHELL);
3699#endif
3700    /* XXX what should these be while sourcing /etc/profile? */
3701    global_argc = argc;
3702    global_argv = argv;
3703    /* Initialize some more globals to non-zero values */
3704    set_cwd();
3705#if ENABLE_HUSH_INTERACTIVE
3706#if ENABLE_FEATURE_EDITING
3707    cmdedit_set_initial_prompt();
3708#endif
3709    PS2 = "> ";
3710#endif
3711
3712    if (EXIT_SUCCESS) /* otherwise is already done */
3713        last_return_code = EXIT_SUCCESS;
3714
3715    if (argv[0] && argv[0][0] == '-') {
3716        debug_printf("sourcing /etc/profile\n");
3717        input = fopen("/etc/profile", "r");
3718        if (input != NULL) {
3719            mark_open(fileno(input));
3720            parse_and_run_file(input);
3721            mark_closed(fileno(input));
3722            fclose(input);
3723        }
3724    }
3725    input = stdin;
3726
3727    while ((opt = getopt(argc, argv, "c:xif")) > 0) {
3728        switch (opt) {
3729        case 'c':
3730            global_argv = argv + optind;
3731            global_argc = argc - optind;
3732            opt = parse_and_run_string(optarg, PARSEFLAG_SEMICOLON);
3733            goto final_return;
3734        case 'i':
3735            /* Well, we cannot just declare interactiveness,
3736             * we have to have some stuff (ctty, etc) */
3737            /* interactive_fd++; */
3738            break;
3739        case 'f':
3740            fake_mode = 1;
3741            break;
3742        default:
3743#ifndef BB_VER
3744            fprintf(stderr, "Usage: sh [FILE]...\n"
3745                    "   or: sh -c command [args]...\n\n");
3746            exit(EXIT_FAILURE);
3747#else
3748            bb_show_usage();
3749#endif
3750        }
3751    }
3752#if ENABLE_HUSH_JOB
3753    /* A shell is interactive if the '-i' flag was given, or if all of
3754     * the following conditions are met:
3755     *    no -c command
3756     *    no arguments remaining or the -s flag given
3757     *    standard input is a terminal
3758     *    standard output is a terminal
3759     *    Refer to Posix.2, the description of the 'sh' utility. */
3760    if (argv[optind] == NULL && input == stdin
3761     && isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)
3762    ) {
3763        saved_tty_pgrp = tcgetpgrp(STDIN_FILENO);
3764        debug_printf("saved_tty_pgrp=%d\n", saved_tty_pgrp);
3765        if (saved_tty_pgrp >= 0) {
3766            /* try to dup to high fd#, >= 255 */
3767            interactive_fd = fcntl(STDIN_FILENO, F_DUPFD, 255);
3768            if (interactive_fd < 0) {
3769                /* try to dup to any fd */
3770                interactive_fd = dup(STDIN_FILENO);
3771                if (interactive_fd < 0)
3772                    /* give up */
3773                    interactive_fd = 0;
3774            }
3775            // TODO: track & disallow any attempts of user
3776            // to (inadvertently) close/redirect it
3777        }
3778    }
3779    debug_printf("interactive_fd=%d\n", interactive_fd);
3780    if (interactive_fd) {
3781        /* Looks like they want an interactive shell */
3782        setup_job_control();
3783        /* Make xfuncs do cleanup on exit */
3784        die_sleep = -1; /* flag */
3785// FIXME: should we reset die_sleep = 0 whereever we fork?
3786        if (setjmp(die_jmp)) {
3787            /* xfunc has failed! die die die */
3788            hush_exit(xfunc_error_retval);
3789        }
3790#if !ENABLE_FEATURE_SH_EXTRA_QUIET
3791        printf("\n\n%s hush - the humble shell v"HUSH_VER_STR"\n", bb_banner);
3792        printf("Enter 'help' for a list of built-in commands.\n\n");
3793#endif
3794    }
3795#elif ENABLE_HUSH_INTERACTIVE
3796/* no job control compiled, only prompt/line editing */
3797    if (argv[optind] == NULL && input == stdin
3798     && isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)
3799    ) {
3800        interactive_fd = fcntl(STDIN_FILENO, F_DUPFD, 255);
3801        if (interactive_fd < 0) {
3802            /* try to dup to any fd */
3803            interactive_fd = dup(STDIN_FILENO);
3804            if (interactive_fd < 0)
3805                /* give up */
3806                interactive_fd = 0;
3807        }
3808    }
3809
3810#endif
3811
3812    if (argv[optind] == NULL) {
3813        opt = parse_and_run_file(stdin);
3814        goto final_return;
3815    }
3816
3817    debug_printf("\nrunning script '%s'\n", argv[optind]);
3818    global_argv = argv + optind;
3819    global_argc = argc - optind;
3820    input = xfopen(argv[optind], "r");
3821    opt = parse_and_run_file(input);
3822
3823 final_return:
3824
3825#if ENABLE_FEATURE_CLEAN_UP
3826    fclose(input);
3827    if (cwd != bb_msg_unknown)
3828        free((char*)cwd);
3829    cur_var = top_var->next;
3830    while (cur_var) {
3831        struct variable *tmp = cur_var;
3832        if (!cur_var->max_len)
3833            free(cur_var->varstr);
3834        cur_var = cur_var->next;
3835        free(tmp);
3836    }
3837#endif
3838    hush_exit(opt ? opt : last_return_code);
3839}
Note: See TracBrowser for help on using the repository browser.