Changeset 1770 in MondoRescue for branches/stable/mindi-busybox/shell/hush.c


Ignore:
Timestamp:
Nov 6, 2007, 11:01:53 AM (12 years ago)
Author:
Bruno Cornec
Message:
  • 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:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/stable/mindi-busybox/shell/hush.c

    r821 r1770  
    2121 *
    2222 * Other credits:
    23  *      simple_itoa() was lifted from boa-0.93.15
    2423 *      b_addchr() derived from similar w_addchar function in glibc-2.2
    2524 *      setup_redirect(), redirect_opt_num(), and big chunks of main()
    26  *        and many builtins derived from contributions by Erik Andersen
     25 *      and many builtins derived from contributions by Erik Andersen
    2726 *      miscellaneous bugfixes from Matt Kraai
    2827 *
     
    3938 *
    4039 * Bash grammar not implemented: (how many of these were in original sh?)
    41  *      $@ (those sure look like weird quoting rules)
    4240 *      $_
    4341 *      ! negation operator for pipes
     
    5351 *      Functions
    5452 * Major bugs:
    55  *      job handling woefully incomplete and buggy
     53 *      job handling woefully incomplete and buggy (improved --vda)
    5654 *      reserved word execution woefully incomplete and buggy
    5755 * to-do:
     
    7371 *      more testing, especially quoting rules and redirection
    7472 *      document how quoting rules not precisely followed for variable assignments
    75  *      maybe change map[] to use 2-bit entries
     73 *      maybe change charmap[] to use 2-bit entries
    7674 *      (eventually) remove all the printf's
    7775 *
     
    7977 */
    8078
    81 #include "busybox.h"
    82 #include <ctype.h>     /* isalpha, isdigit */
    83 #include <unistd.h>    /* getpid */
    84 #include <stdlib.h>    /* getenv, atoi */
    85 #include <string.h>    /* strchr */
    86 #include <stdio.h>     /* popen etc. */
     79
    8780#include <glob.h>      /* glob, of course */
    88 #include <stdarg.h>    /* va_list */
    89 #include <errno.h>
    90 #include <fcntl.h>
    9181#include <getopt.h>    /* should be pretty obvious */
    92 
    93 #include <sys/stat.h>  /* ulimit */
    94 #include <sys/types.h>
    95 #include <sys/wait.h>
    96 #include <signal.h>
    97 
    9882/* #include <dmalloc.h> */
    99 /* #define DEBUG_SHELL */
    100 
    101 #if 1
    102 #include "cmdedit.h"
    103 #else
    104 #define bb_applet_name "hush"
    105 //#include "standalone.h"
    106 #define hush_main main
    107 #undef CONFIG_FEATURE_SH_FANCY_PROMPT
    108 #define BB_BANNER ""
    109 #endif
    110 #define SPECIAL_VAR_SYMBOL 03
    111 #define FLAG_EXIT_FROM_LOOP 1
    112 #define FLAG_PARSE_SEMICOLON (1 << 1)       /* symbol ';' is special for parser */
    113 #define FLAG_REPARSING       (1 << 2)       /* >=2nd pass */
     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 */
    114150
    115151typedef enum {
     
    123159/* The descrip member of this structure is only used to make debugging
    124160 * output pretty */
    125 static const struct {int mode; int default_fd; const char *descrip;} redir_table[] = {
     161static const struct {
     162    int mode;
     163    signed char default_fd;
     164    char descrip[3];
     165} redir_table[] = {
    126166    { 0,                         0, "()" },
    127167    { O_RDONLY,                  0, "<"  },
     
    142182typedef enum {
    143183    RES_NONE  = 0,
     184#if ENABLE_HUSH_IF
    144185    RES_IF    = 1,
    145186    RES_THEN  = 2,
     
    147188    RES_ELSE  = 4,
    148189    RES_FI    = 5,
     190#endif
     191#if ENABLE_HUSH_LOOPS
    149192    RES_FOR   = 6,
    150193    RES_WHILE = 7,
     
    152195    RES_DO    = 9,
    153196    RES_DONE  = 10,
    154     RES_XXXX  = 11,
    155     RES_IN    = 12,
     197    RES_IN    = 11,
     198#endif
     199    RES_XXXX  = 12,
    156200    RES_SNTX  = 13
    157201} reserved_style;
    158 #define FLAG_END   (1<<RES_NONE)
    159 #define FLAG_IF    (1<<RES_IF)
    160 #define FLAG_THEN  (1<<RES_THEN)
    161 #define FLAG_ELIF  (1<<RES_ELIF)
    162 #define FLAG_ELSE  (1<<RES_ELSE)
    163 #define FLAG_FI    (1<<RES_FI)
    164 #define FLAG_FOR   (1<<RES_FOR)
    165 #define FLAG_WHILE (1<<RES_WHILE)
    166 #define FLAG_UNTIL (1<<RES_UNTIL)
    167 #define FLAG_DO    (1<<RES_DO)
    168 #define FLAG_DONE  (1<<RES_DONE)
    169 #define FLAG_IN    (1<<RES_IN)
    170 #define FLAG_START (1<<RES_XXXX)
     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};
    171221
    172222/* This holds pointers to the various results of parsing */
     
    176226    struct pipe *pipe;
    177227    struct redir_struct *pending_redirect;
    178     reserved_style w;
    179     int old_flag;               /* for figuring out valid reserved words */
     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 */
    180231    struct p_context *stack;
    181     int type;           /* define type of parser : ";$" common or special symbol */
    182232    /* How about quoting status? */
    183233};
    184234
    185235struct redir_struct {
    186     redir_type type;            /* type of redirection */
    187     int fd;                     /* file descriptor being redirected */
    188     int dup;                    /* -1, or file descriptor being duplicated */
    189     struct redir_struct *next;  /* pointer to the next redirect in the list */
    190     glob_t word;                /* *word.gl_pathv is the filename */
     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 */
    191241};
    192242
    193243struct child_prog {
    194     pid_t pid;                  /* 0 if exited */
    195     char **argv;                /* program name and arguments */
    196     struct pipe *group;         /* if non-NULL, first in group or subshell */
    197     int subshell;               /* flag, non-zero if group must be forked */
    198     struct redir_struct *redirects; /* I/O redirections */
    199     glob_t glob_result;         /* result of parameter globbing */
    200     int is_stopped;             /* is the program currently running? */
    201     struct pipe *family;        /* pointer back to the child's parent pipe */
    202     int sp;             /* number of SPECIAL_VAR_SYMBOL */
    203     int type;
     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;
    204256};
     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 */
    205262
    206263struct pipe {
    207     int jobid;                  /* job number */
    208     int num_progs;              /* total number of programs in job */
    209     int running_progs;          /* number of programs running */
    210     char *text;                 /* name of job */
    211     char *cmdbuf;               /* buffer various argv's point into */
    212     pid_t pgrp;                 /* process group ID for the job */
    213     struct child_prog *progs;   /* array of commands in pipe */
    214     struct pipe *next;          /* to track background commands */
    215     int stopped_progs;          /* number of programs alive, but stopped */
    216     int job_context;            /* bitmask defining current context */
    217     pipe_style followup;        /* PIPE_BG, PIPE_SEQ, PIPE_OR, PIPE_AND */
    218     reserved_style r_mode;      /* supports if, for, while, until */
     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... */
    219278};
    220279
    221280struct close_me {
     281    struct close_me *next;
    222282    int fd;
    223     struct close_me *next;
    224283};
    225284
    226 struct variables {
    227     char *name;
    228     char *value;
    229     int flg_export;
    230     int flg_read_only;
    231     struct variables *next;
     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;
    232297};
    233 
    234 /* globals, connect us to the outside world
    235  * the first three support $?, $#, and $1 */
    236 static char **global_argv;
    237 static int global_argc;
    238 static int last_return_code;
    239 extern char **environ; /* This is in <unistd.h>, but protected with __USE_GNU */
    240 
    241 /* "globals" within this file */
    242 static char *ifs;
    243 static unsigned char map[256];
    244 static int fake_mode;
    245 static int interactive;
    246 static struct close_me *close_me_head;
    247 static const char *cwd;
    248 static struct pipe *job_list;
    249 static unsigned int last_bg_pid;
    250 static int last_jobid;
    251 static unsigned int shell_terminal;
    252 static char *PS1;
    253 static char *PS2;
    254 static struct variables shell_ver = { "HUSH_VERSION", "0.01", 1, 1, 0 };
    255 static struct variables *top_vars = &shell_ver;
    256 
    257 
    258 #define B_CHUNK (100)
    259 #define B_NOSPAC 1
    260298
    261299typedef struct {
     
    267305} o_string;
    268306#define NULL_O_STRING {NULL,0,0,0,0}
    269 /* used for initialization:
    270     o_string foo = NULL_O_STRING; */
     307/* used for initialization: o_string foo = NULL_O_STRING; */
    271308
    272309/* I can almost use ordinary FILE *.  Is open_memstream() universally
     
    274311struct in_str {
    275312    const char *p;
     313    /* eof_flag=1: last char in ->p is really an EOF */
     314    char eof_flag; /* meaningless if ->p == NULL */
    276315    char peek_buf[2];
    277     int __promptme;
    278     int promptmode;
     316#if ENABLE_HUSH_INTERACTIVE
     317    smallint promptme;
     318    smallint promptmode; /* 0: PS1, 1: PS2 */
     319#endif
    279320    FILE *file;
    280321    int (*get) (struct in_str *);
     
    284325#define b_peek(input) ((input)->peek(input))
    285326
     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
    286429#define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n"
    287430
    288 struct built_in_command {
    289     const char *cmd;            /* name */
    290     const char *descr;          /* description */
    291     int (*function) (struct child_prog *);  /* function ptr */
    292 };
    293 
    294 /* belongs in busybox.h */
    295 static inline int max(int a, int b) {
    296     return (a>b)?a:b;
    297 }
    298 
    299 /* This should be in utility.c */
    300 #ifdef DEBUG_SHELL
    301 static void debug_printf(const char *format, ...)
    302 {
    303     va_list args;
    304     va_start(args, format);
    305     vfprintf(stderr, format, args);
    306     va_end(args);
    307 }
     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
    308444#else
    309 static inline void debug_printf(const char *format ATTRIBUTE_UNUSED, ...) { }
    310 #endif
    311 #define final_printf debug_printf
    312 
    313 static void __syntax(char *file, int line) {
    314     bb_error_msg("syntax error %s:%d", file, line);
    315 }
    316 #define syntax() __syntax(__FILE__, __LINE__)
     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
    317455
    318456/* Index of subroutines: */
    319457/*   function prototypes for builtins */
    320 static int builtin_cd(struct child_prog *child);
    321 static int builtin_env(struct child_prog *child);
    322 static int builtin_eval(struct child_prog *child);
    323 static int builtin_exec(struct child_prog *child);
    324 static int builtin_exit(struct child_prog *child);
    325 static int builtin_export(struct child_prog *child);
    326 static int builtin_fg_bg(struct child_prog *child);
    327 static int builtin_help(struct child_prog *child);
    328 static int builtin_jobs(struct child_prog *child);
    329 static int builtin_pwd(struct child_prog *child);
    330 static int builtin_read(struct child_prog *child);
    331 static int builtin_set(struct child_prog *child);
    332 static int builtin_shift(struct child_prog *child);
    333 static int builtin_source(struct child_prog *child);
    334 static int builtin_umask(struct child_prog *child);
    335 static int builtin_unset(struct child_prog *child);
    336 static int builtin_not_written(struct child_prog *child);
     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);
    337478/*   o_string manipulation: */
    338479static int b_check_space(o_string *o, int len);
     
    340481static void b_reset(o_string *o);
    341482static int b_addqchr(o_string *o, int ch, int quote);
    342 static int b_adduint(o_string *o, unsigned int i);
    343483/*  in_str manipulations: */
    344484static int static_get(struct in_str *i);
     
    353493static void close_all(void);
    354494/*  "run" the final data structures: */
    355 static char *indenter(int i);
     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
    356499static int free_pipe_list(struct pipe *head, int indent);
    357500static int free_pipe(struct pipe *pi, int indent);
     
    359502static int setup_redirects(struct child_prog *prog, int squirrel[]);
    360503static int run_list_real(struct pipe *pi);
     504static void pseudo_exec_argv(char **argv) ATTRIBUTE_NORETURN;
    361505static void pseudo_exec(struct child_prog *child) ATTRIBUTE_NORETURN;
    362506static int run_pipe_real(struct pipe *pi);
     
    376520static int redirect_dup_num(struct in_str *input);
    377521static int redirect_opt_num(o_string *o);
    378 static int process_command_subs(o_string *dest, struct p_context *ctx, struct in_str *input, int subst_end);
     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
    379525static int parse_group(o_string *dest, struct p_context *ctx, struct in_str *input, int ch);
    380 static char *lookup_param(char *src);
    381 static char *make_string(char **inp);
     526static const char *lookup_param(const char *src);
    382527static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input);
    383 static int parse_string(o_string *dest, struct p_context *ctx, const char *src);
    384 static int parse_stream(o_string *dest, struct p_context *ctx, struct in_str *input0, int end_trigger);
     528static int parse_stream(o_string *dest, struct p_context *ctx, struct in_str *input0, const char *end_trigger);
    385529/*   setup: */
    386 static int parse_stream_outer(struct in_str *inp, int flag);
    387 static int parse_string_outer(const char *s, int flag);
    388 static int parse_file_outer(FILE *f);
     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);
    389533/*   job management: */
    390534static int checkjobs(struct pipe* fg_pipe);
     535#if ENABLE_HUSH_JOB
     536static int checkjobs_and_fg_shell(struct pipe* fg_pipe);
    391537static void insert_bg_job(struct pipe *pi);
    392538static 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
    393543/*     local variable support */
    394 static char **make_list_in(char **inp, char *name);
    395 static char *insert_var_value(char *inp);
    396 static char *get_local_var(const char *var);
    397 static void  unset_local_var(const char *name);
    398 static int set_local_var(const char *s, int flg_export);
     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);
    399552
    400553/* Table of built-in functions.  They can be forked or not, depending on
    401554 * context: within pipes, they fork.  As simple commands, they do not.
    402555 * When used in non-forking context, they can change global variables
    403  * in the parent shell process.  If forked, of course they can not.
     556 * in the parent shell process.  If forked, of course they cannot.
    404557 * For example, 'unset foo | whatever' will parse and run, but foo will
    405558 * 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
    406570static const struct built_in_command bltins[] = {
    407     {"bg", "Resume a job in the background", builtin_fg_bg},
    408     {"break", "Exit for, while or until loop", builtin_not_written},
    409     {"cd", "Change working directory", builtin_cd},
    410     {"continue", "Continue for, while or until loop", builtin_not_written},
    411     {"env", "Print all environment variables", builtin_env},
    412     {"eval", "Construct and run shell command", builtin_eval},
    413     {"exec", "Exec command, replacing this shell with the exec'd process",
    414         builtin_exec},
    415     {"exit", "Exit from shell()", builtin_exit},
    416     {"export", "Set environment variable", builtin_export},
    417     {"fg", "Bring job into the foreground", builtin_fg_bg},
    418     {"jobs", "Lists the active jobs", builtin_jobs},
    419     {"pwd", "Print current directory", builtin_pwd},
    420     {"read", "Input environment variable", builtin_read},
    421     {"return", "Return from a function", builtin_not_written},
    422     {"set", "Set/unset shell local variables", builtin_set},
    423     {"shift", "Shift positional parameters", builtin_shift},
    424     {"trap", "Trap signals", builtin_not_written},
    425     {"ulimit","Controls resource limits", builtin_not_written},
    426     {"umask","Sets file creation mask", builtin_umask},
    427     {"unset", "Unset environment variable", builtin_unset},
    428     {".", "Source-in and run commands in a file", builtin_source},
    429     {"help", "List shell built-in commands", builtin_help},
    430     {NULL, NULL, NULL}
     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)
    431600};
    432601
     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
    433734static const char *set_cwd(void)
    434735{
    435     if(cwd==bb_msg_unknown)
    436         cwd = NULL;     /* xgetcwd(arg) called free(arg) */
    437     cwd = xgetcwd((char *)cwd);
     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);
    438739    if (!cwd)
    439740        cwd = bb_msg_unknown;
     
    442743
    443744/* built-in 'eval' handler */
    444 static int builtin_eval(struct child_prog *child)
    445 {
    446     char *str = NULL;
     745static int builtin_eval(char **argv)
     746{
    447747    int rcode = EXIT_SUCCESS;
    448748
    449     if (child->argv[1]) {
    450         str = make_string(child->argv + 1);
    451         parse_string_outer(str, FLAG_EXIT_FROM_LOOP |
    452                     FLAG_PARSE_SEMICOLON);
     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);
    453753        free(str);
    454754        rcode = last_return_code;
     
    458758
    459759/* built-in 'cd <path>' handler */
    460 static int builtin_cd(struct child_prog *child)
    461 {
    462     char *newdir;
    463     if (child->argv[1] == NULL)
    464         newdir = getenv("HOME");
     760static int builtin_cd(char **argv)
     761{
     762    const char *newdir;
     763    if (argv[1] == NULL)
     764        newdir = getenv("HOME") ? : "/";
    465765    else
    466         newdir = child->argv[1];
     766        newdir = argv[1];
    467767    if (chdir(newdir)) {
    468768        printf("cd: %s: %s\n", newdir, strerror(errno));
     
    473773}
    474774
    475 /* built-in 'env' handler */
    476 static int builtin_env(struct child_prog *dummy ATTRIBUTE_UNUSED)
    477 {
    478     char **e = environ;
    479     if (e == NULL) return EXIT_FAILURE;
    480     for (; *e; e++) {
    481         puts(*e);
    482     }
     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);
    483834    return EXIT_SUCCESS;
    484835}
    485836
    486 /* built-in 'exec' handler */
    487 static int builtin_exec(struct child_prog *child)
    488 {
    489     if (child->argv[1] == NULL)
    490         return EXIT_SUCCESS;   /* Really? */
    491     child->argv++;
    492     pseudo_exec(child);
    493     /* never returns */
    494 }
    495 
    496 /* built-in 'exit' handler */
    497 static int builtin_exit(struct child_prog *child)
    498 {
    499     if (child->argv[1] == NULL)
    500         exit(last_return_code);
    501     exit (atoi(child->argv[1]));
    502 }
    503 
    504 /* built-in 'export VAR=value' handler */
    505 static int builtin_export(struct child_prog *child)
    506 {
    507     int res = 0;
    508     char *name = child->argv[1];
    509 
    510     if (name == NULL) {
    511         return (builtin_env(child));
    512     }
    513 
    514     name = strdup(name);
    515 
    516     if(name) {
    517         char *value = strchr(name, '=');
    518 
    519         if (!value) {
    520             char *tmp;
    521             /* They are exporting something without an =VALUE */
    522 
    523             value = get_local_var(name);
    524             if (value) {
    525                 size_t ln = strlen(name);
    526 
    527                 tmp = realloc(name, ln+strlen(value)+2);
    528                 if(tmp==NULL)
    529                     res = -1;
    530                 else {
    531                     sprintf(tmp+ln, "=%s", value);
    532                     name = tmp;
    533                 }
    534             } else {
    535                 /* bash does not return an error when trying to export
    536                  * an undefined variable.  Do likewise. */
    537                 res = 1;
    538             }
    539         }
    540     }
    541     if (res<0)
    542         bb_perror_msg("export");
    543     else if(res==0)
    544         res = set_local_var(name, 1);
    545     else
    546         res = 0;
    547     free(name);
    548     return res;
    549 }
    550 
     837#if ENABLE_HUSH_JOB
    551838/* built-in 'fg' and 'bg' handler */
    552 static int builtin_fg_bg(struct child_prog *child)
     839static int builtin_fg_bg(char **argv)
    553840{
    554841    int i, jobnum;
    555     struct pipe *pi=NULL;
    556 
    557     if (!interactive)
     842    struct pipe *pi;
     843
     844    if (!interactive_fd)
    558845        return EXIT_FAILURE;
    559846    /* If they gave us no args, assume they want the last backgrounded task */
    560     if (!child->argv[1]) {
     847    if (!argv[1]) {
    561848        for (pi = job_list; pi; pi = pi->next) {
    562849            if (pi->jobid == last_jobid) {
    563                 break;
    564             }
    565         }
    566         if (!pi) {
    567             bb_error_msg("%s: no current job", child->argv[0]);
    568             return EXIT_FAILURE;
    569         }
    570     } else {
    571         if (sscanf(child->argv[1], "%%%d", &jobnum) != 1) {
    572             bb_error_msg("%s: bad argument '%s'", child->argv[0], child->argv[1]);
    573             return EXIT_FAILURE;
    574         }
    575         for (pi = job_list; pi; pi = pi->next) {
    576             if (pi->jobid == jobnum) {
    577                 break;
    578             }
    579         }
    580         if (!pi) {
    581             bb_error_msg("%s: %d: no such job", child->argv[0], jobnum);
    582             return EXIT_FAILURE;
    583         }
    584     }
    585 
    586     if (*child->argv[0] == 'f') {
     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') {
    587871        /* Put the job into the foreground.  */
    588         tcsetpgrp(shell_terminal, pi->pgrp);
     872        tcsetpgrp(interactive_fd, pi->pgrp);
    589873    }
    590874
    591875    /* Restart the processes in the job */
    592     for (i = 0; i < pi->num_progs; i++)
     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);
    593879        pi->progs[i].is_stopped = 0;
    594 
    595     if ( (i=kill(- pi->pgrp, SIGCONT)) < 0) {
    596         if (i == ESRCH) {
    597             remove_bg_job(pi);
     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;
    598888        } else {
    599889            bb_perror_msg("kill (SIGCONT)");
     
    601891    }
    602892
    603     pi->stopped_progs = 0;
     893    if (*argv[0] == 'f') {
     894        remove_bg_job(pi);
     895        return checkjobs_and_fg_shell(pi);
     896    }
    604897    return EXIT_SUCCESS;
    605898}
     899#endif
    606900
    607901/* built-in 'help' handler */
    608 static int builtin_help(struct child_prog *dummy ATTRIBUTE_UNUSED)
     902#if ENABLE_HUSH_HELP
     903static int builtin_help(char **argv ATTRIBUTE_UNUSED)
    609904{
    610905    const struct built_in_command *x;
     
    613908    printf("-------------------\n");
    614909    for (x = bltins; x->cmd; x++) {
    615         if (x->descr==NULL)
    616             continue;
    617910        printf("%s\t%s\n", x->cmd, x->descr);
    618911    }
     
    620913    return EXIT_SUCCESS;
    621914}
    622 
     915#endif
     916
     917#if ENABLE_HUSH_JOB
    623918/* built-in 'jobs' handler */
    624 static int builtin_jobs(struct child_prog *child ATTRIBUTE_UNUSED)
     919static int builtin_jobs(char **argv ATTRIBUTE_UNUSED)
    625920{
    626921    struct pipe *job;
    627     char *status_string;
     922    const char *status_string;
    628923
    629924    for (job = job_list; job; job = job->next) {
     
    633928            status_string = "Running";
    634929
    635         printf(JOB_STATUS_FORMAT, job->jobid, status_string, job->text);
     930        printf(JOB_STATUS_FORMAT, job->jobid, status_string, job->cmdtext);
    636931    }
    637932    return EXIT_SUCCESS;
    638933}
    639 
     934#endif
    640935
    641936/* built-in 'pwd' handler */
    642 static int builtin_pwd(struct child_prog *dummy ATTRIBUTE_UNUSED)
     937static int builtin_pwd(char **argv ATTRIBUTE_UNUSED)
    643938{
    644939    puts(set_cwd());
     
    647942
    648943/* built-in 'read VAR' handler */
    649 static int builtin_read(struct child_prog *child)
    650 {
    651     int res;
    652 
    653     if (child->argv[1]) {
    654         char string[BUFSIZ];
    655         char *var = 0;
    656 
    657         string[0] = 0;  /* In case stdin has only EOF */
    658         /* read string */
    659         fgets(string, sizeof(string), stdin);
    660         chomp(string);
    661         var = malloc(strlen(child->argv[1])+strlen(string)+2);
    662         if(var) {
    663             sprintf(var, "%s=%s", child->argv[1], string);
    664             res = set_local_var(var, 0);
    665         } else
    666             res = -1;
    667         if (res)
    668             bb_perror_msg("read");
    669         free(var);      /* So not move up to avoid breaking errno */
    670         return res;
    671     } else {
    672         do res=getchar(); while(res!='\n' && res!=EOF);
    673         return 0;
    674     }
    675 }
    676 
    677 /* built-in 'set VAR=value' handler */
    678 static int builtin_set(struct child_prog *child)
    679 {
    680     char *temp = child->argv[1];
    681     struct variables *e;
     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;
    682958
    683959    if (temp == NULL)
    684         for(e = top_vars; e; e=e->next)
    685             printf("%s=%s\n", e->name, e->value);
     960        for (e = top_var; e; e = e->next)
     961            puts(e->varstr);
    686962    else
    687         set_local_var(temp, 0);
    688 
    689         return EXIT_SUCCESS;
     963        set_local_var(xstrdup(temp), 0);
     964
     965    return EXIT_SUCCESS;
    690966}
    691967
    692968
    693969/* Built-in 'shift' handler */
    694 static int builtin_shift(struct child_prog *child)
    695 {
    696     int n=1;
    697     if (child->argv[1]) {
    698         n=atoi(child->argv[1]);
    699     }
    700     if (n>=0 && n<global_argc) {
    701         /* XXX This probably breaks $0 */
     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];
    702978        global_argc -= n;
    703979        global_argv += n;
    704980        return EXIT_SUCCESS;
    705     } else {
    706         return EXIT_FAILURE;
    707     }
     981    }
     982    return EXIT_FAILURE;
    708983}
    709984
    710985/* Built-in '.' handler (read-in and execute commands from file) */
    711 static int builtin_source(struct child_prog *child)
     986static int builtin_source(char **argv)
    712987{
    713988    FILE *input;
    714989    int status;
    715990
    716     if (child->argv[1] == NULL)
     991    if (argv[1] == NULL)
    717992        return EXIT_FAILURE;
    718993
    719994    /* XXX search through $PATH is missing */
    720     input = fopen(child->argv[1], "r");
     995    input = fopen(argv[1], "r");
    721996    if (!input) {
    722         bb_error_msg("Couldn't open file '%s'", child->argv[1]);
     997        bb_error_msg("cannot open '%s'", argv[1]);
    723998        return EXIT_FAILURE;
    724999    }
     
    7271002    /* XXX argv and argc are broken; need to save old global_argv
    7281003     * (pointer only is OK!) on this stack frame,
    729      * set global_argv=child->argv+1, recurse, and restore. */
     1004     * set global_argv=argv+1, recurse, and restore. */
    7301005    mark_open(fileno(input));
    731     status = parse_file_outer(input);
     1006    status = parse_and_run_file(input);
    7321007    mark_closed(fileno(input));
    7331008    fclose(input);
    734     return (status);
    735 }
    736 
    737 static int builtin_umask(struct child_prog *child)
     1009    return status;
     1010}
     1011
     1012static int builtin_umask(char **argv)
    7381013{
    7391014    mode_t new_umask;
    740     const char *arg = child->argv[1];
     1015    const char *arg = argv[1];
    7411016    char *end;
    7421017    if (arg) {
    743         new_umask=strtoul(arg, &end, 8);
    744         if (*end!='\0' || end == arg) {
     1018        new_umask = strtoul(arg, &end, 8);
     1019        if (*end != '\0' || end == arg) {
    7451020            return EXIT_FAILURE;
    7461021        }
    7471022    } else {
    748         printf("%.3o\n", (unsigned int) (new_umask=umask(0)));
     1023        new_umask = umask(0);
     1024        printf("%.3o\n", (unsigned) new_umask);
    7491025    }
    7501026    umask(new_umask);
     
    7531029
    7541030/* built-in 'unset VAR' handler */
    755 static int builtin_unset(struct child_prog *child)
    756 {
    757     /* bash returned already true */
    758     unset_local_var(child->argv[1]);
     1031static int builtin_unset(char **argv)
     1032{
     1033    /* bash always returns true */
     1034    unset_local_var(argv[1]);
    7591035    return EXIT_SUCCESS;
    7601036}
    7611037
    762 static int builtin_not_written(struct child_prog *child)
    763 {
    764     printf("builtin_%s not written\n",child->argv[0]);
    765     return EXIT_FAILURE;
    766 }
     1038//static int builtin_not_written(char **argv)
     1039//{
     1040//  printf("builtin_%s not written\n", argv[0]);
     1041//  return EXIT_FAILURE;
     1042//}
    7671043
    7681044static int b_check_space(o_string *o, int len)
     
    7711047     * in here, such as setting a maximum string length */
    7721048    if (o->length + len > o->maxlen) {
    773         char *old_data = o->data;
    774         /* assert (data == NULL || o->maxlen != 0); */
    775         o->maxlen += max(2*len, B_CHUNK);
    776         o->data = realloc(o->data, 1 + o->maxlen);
    777         if (o->data == NULL) {
    778             free(old_data);
    779         }
     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);
    7801052    }
    7811053    return o->data == NULL;
     
    7841056static int b_addchr(o_string *o, int ch)
    7851057{
    786     debug_printf("b_addchr: %c %d %p\n", ch, o->length, o);
    787     if (b_check_space(o, 1)) return B_NOSPAC;
     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;
    7881061    o->data[o->length] = ch;
    7891062    o->length++;
     
    7961069    o->length = 0;
    7971070    o->nonnull = 0;
    798     if (o->data != NULL) *o->data = '\0';
     1071    if (o->data != NULL)
     1072        *o->data = '\0';
    7991073}
    8001074
     
    8121086static int b_addqchr(o_string *o, int ch, int quote)
    8131087{
    814     if (quote && strchr("*?[\\",ch)) {
     1088    if (quote && strchr("*?[\\", ch)) {
    8151089        int rc;
    8161090        rc = b_addchr(o, '\\');
    817         if (rc) return rc;
     1091        if (rc)
     1092            return rc;
    8181093    }
    8191094    return b_addchr(o, ch);
    8201095}
    8211096
    822 /* belongs in utility.c */
    823 static char *simple_itoa(unsigned int i)
    824 {
    825     /* 21 digits plus null terminator, good for 64-bit or smaller ints */
    826     static char local[22];
    827     char *p = &local[21];
    828     *p-- = '\0';
    829     do {
    830         *p-- = '0' + i % 10;
    831         i /= 10;
    832     } while (i > 0);
    833     return p + 1;
    834 }
    835 
    836 static int b_adduint(o_string *o, unsigned int i)
    837 {
    838     int r;
    839     char *p = simple_itoa(i);
    840     /* no escape checking necessary */
    841     do r=b_addchr(o, *p++); while (r==0 && *p);
    842     return r;
    843 }
    844 
    8451097static int static_get(struct in_str *i)
    8461098{
    847     int ch=*i->p++;
    848     if (ch=='\0') return EOF;
     1099    int ch = *i->p++;
     1100    if (ch == '\0') return EOF;
    8491101    return ch;
    8501102}
     
    8551107}
    8561108
    857 static inline void cmdedit_set_initial_prompt(void)
    858 {
    859 #ifndef CONFIG_FEATURE_SH_FANCY_PROMPT
     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
    8601114    PS1 = NULL;
    8611115#else
    8621116    PS1 = getenv("PS1");
    863     if(PS1==0)
     1117    if (PS1 == NULL)
    8641118        PS1 = "\\w \\$ ";
    8651119#endif
    8661120}
    867 
    868 static inline void setup_prompt_string(int promptmode, char **prompt_str)
    869 {
    870     debug_printf("setup_prompt_string %d ",promptmode);
    871 #ifndef CONFIG_FEATURE_SH_FANCY_PROMPT
     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
    8721128    /* Set up the prompt */
    873     if (promptmode == 1) {
    874         free(PS1);
    875         PS1=xmalloc(strlen(cwd)+4);
    876         sprintf(PS1, "%s %s", cwd, ( geteuid() != 0 ) ?  "$ ":"# ");
    877         *prompt_str = PS1;
     1129    if (promptmode == 0) { /* PS1 */
     1130        free((char*)PS1);
     1131        PS1 = xasprintf("%s %c ", cwd, (geteuid() != 0) ? '$' : '#');
     1132        prompt_str = PS1;
    8781133    } else {
    879         *prompt_str = PS2;
     1134        prompt_str = PS2;
    8801135    }
    8811136#else
    882     *prompt_str = (promptmode==1)? PS1 : PS2;
    883 #endif
    884     debug_printf("result %s\n",*prompt_str);
     1137    prompt_str = (promptmode == 0) ? PS1 : PS2;
     1138#endif
     1139    debug_printf("result '%s'\n", prompt_str);
     1140    return prompt_str;
    8851141}
    8861142
    8871143static void get_user_input(struct in_str *i)
    8881144{
    889     char *prompt_str;
    890     static char the_command[BUFSIZ];
    891 
    892     setup_prompt_string(i->promptmode, &prompt_str);
    893 #ifdef CONFIG_FEATURE_COMMAND_EDITING
    894     /*
    895      ** enable command line editing only while a command line
    896      ** is actually being read; otherwise, we'll end up bequeathing
    897      ** atexit() handlers and other unwanted stuff to our
    898      ** child processes (rob@sysgo.de)
    899      */
    900     cmdedit_read_input(prompt_str, the_command);
     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    }
    9011160#else
    9021161    fputs(prompt_str, stdout);
    9031162    fflush(stdout);
    904     the_command[0]=fgetc(i->file);
    905     the_command[1]='\0';
    906 #endif
    907     fflush(stdout);
    908     i->p = the_command;
    909 }
     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 */
    9101170
    9111171/* This is the magic location that prints prompts
     
    9151175    int ch;
    9161176
    917     ch = 0;
    9181177    /* If there is data waiting, eat it up */
    9191178    if (i->p && *i->p) {
    920         ch=*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;
    9211185    } else {
    9221186        /* need to double check i->file because we might be doing something
    9231187         * more complicated by now, like sourcing or substituting. */
    924         if (i->__promptme && interactive && i->file == stdin) {
    925             while(! i->p || (interactive && strlen(i->p)==0) ) {
     1188#if ENABLE_HUSH_INTERACTIVE
     1189        if (interactive_fd && i->promptme && i->file == stdin) {
     1190            do {
    9261191                get_user_input(i);
    927             }
    928             i->promptmode=2;
    929             i->__promptme = 0;
    930             if (i->p && *i->p) {
    931                 ch=*i->p++;
    932             }
    933         } else {
    934             ch = fgetc(i->file);
    935         }
    936 
    937         debug_printf("b_getch: got a %d\n", ch);
    938     }
    939     if (ch == '\n') i->__promptme=1;
     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
    9401205    return ch;
    9411206}
     
    9461211static int file_peek(struct in_str *i)
    9471212{
     1213    int ch;
    9481214    if (i->p && *i->p) {
     1215        if (i->eof_flag && !i->p[1])
     1216            return EOF;
    9491217        return *i->p;
    950     } else {
    951         i->peek_buf[0] = fgetc(i->file);
    952         i->peek_buf[1] = '\0';
    953         i->p = i->peek_buf;
    954         debug_printf("b_peek: got a %d\n", *i->p);
    955         return *i->p;
    956     }
     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;
    9571226}
    9581227
     
    9611230    i->peek = file_peek;
    9621231    i->get = file_get;
    963     i->__promptme=1;
    964     i->promptmode=1;
     1232#if ENABLE_HUSH_INTERACTIVE
     1233    i->promptme = 1;
     1234    i->promptmode = 0; /* PS1 */
     1235#endif
    9651236    i->file = f;
    9661237    i->p = NULL;
     
    9711242    i->peek = static_peek;
    9721243    i->get = static_get;
    973     i->__promptme=1;
    974     i->promptmode=1;
     1244#if ENABLE_HUSH_INTERACTIVE
     1245    i->promptme = 1;
     1246    i->promptmode = 0; /* PS1 */
     1247#endif
    9751248    i->p = s;
     1249    i->eof_flag = 0;
    9761250}
    9771251
     
    9971271{
    9981272    struct close_me *c;
    999     for (c=close_me_head; c; c=c->next) {
     1273    for (c = close_me_head; c; c = c->next) {
    10001274        close(c->fd);
    10011275    }
     
    10101284    struct redir_struct *redir;
    10111285
    1012     for (redir=prog->redirects; redir; redir=redir->next) {
     1286    for (redir = prog->redirects; redir; redir = redir->next) {
    10131287        if (redir->dup == -1 && redir->word.gl_pathv == NULL) {
    10141288            /* something went wrong in the parse.  Pretend it didn't happen */
     
    10161290        }
    10171291        if (redir->dup == -1) {
    1018             mode=redir_table[redir->type].mode;
    1019             openfd = open(redir->word.gl_pathv[0], mode, 0666);
     1292            mode = redir_table[redir->type].mode;
     1293            openfd = open_or_warn(redir->word.gl_pathv[0], mode);
    10201294            if (openfd < 0) {
    10211295            /* this could get lost if stderr has been redirected, but
    10221296               bash and ash both lose it as well (though zsh doesn't!) */
    1023                 bb_perror_msg("error opening %s", redir->word.gl_pathv[0]);
    10241297                return 1;
    10251298            }
     
    10371310                dup2(openfd, redir->fd);
    10381311                if (redir->dup == -1)
    1039                     close (openfd);
     1312                    close(openfd);
    10401313            }
    10411314        }
     
    10471320{
    10481321    int i, fd;
    1049     for (i=0; i<3; i++) {
     1322    for (i = 0; i < 3; i++) {
    10501323        fd = squirrel[i];
    10511324        if (fd != -1) {
    1052             /* No error checking.  I sure wouldn't know what
    1053              * to do with an error if I found one! */
    1054             dup2(fd, i);
    1055             close(fd);
     1325            /* We simply die on error */
     1326            xmove_fd(fd, i);
    10561327        }
    10571328    }
     
    10611332/* XXX no exit() here.  If you don't exec, use _exit instead.
    10621333 * The at_exit handlers apparently confuse the calling process,
    1063  * in particular stdin handling.  Not sure why? */
    1064 static void pseudo_exec(struct child_prog *child)
     1334 * in particular stdin handling.  Not sure why? -- because of vfork! (vda) */
     1335static void pseudo_exec_argv(char **argv)
    10651336{
    10661337    int i, rcode;
    10671338    char *p;
    10681339    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
    10691405    if (child->argv) {
    1070         for (i=0; is_assignment(child->argv[i]); i++) {
    1071             debug_printf("pid %d environment modification: %s\n",getpid(),child->argv[i]);
    1072             p = insert_var_value(child->argv[i]);
    1073             putenv(strdup(p));
    1074             if (p != child->argv[i]) free(p);
    1075         }
    1076         child->argv+=i;  /* XXX this hack isn't so horrible, since we are about
    1077                                 to exit, and therefore don't need to keep data
    1078                                 structures consistent for free() use. */
    1079         /* If a variable is assigned in a forest, and nobody listens,
    1080          * was it ever really set?
    1081          */
    1082         if (child->argv[0] == NULL) {
    1083             _exit(EXIT_SUCCESS);
    1084         }
    1085 
    1086         /*
    1087          * Check if the command matches any of the builtins.
    1088          * Depending on context, this might be redundant.  But it's
    1089          * easier to waste a few CPU cycles than it is to figure out
    1090          * if this is one of those cases.
    1091          */
    1092         for (x = bltins; x->cmd; x++) {
    1093             if (strcmp(child->argv[0], x->cmd) == 0 ) {
    1094                 debug_printf("builtin exec %s\n", child->argv[0]);
    1095                 rcode = x->function(child);
    1096                 fflush(stdout);
    1097                 _exit(rcode);
    1098             }
    1099         }
    1100 
    1101         /* Check if the command matches any busybox internal commands
    1102          * ("applets") here.
    1103          * FIXME: This feature is not 100% safe, since
    1104          * BusyBox is not fully reentrant, so we have no guarantee the things
    1105          * from the .bss are still zeroed, or that things from .data are still
    1106          * at their defaults.  We could exec ourself from /proc/self/exe, but I
    1107          * really dislike relying on /proc for things.  We could exec ourself
    1108          * from global_argv[0], but if we are in a chroot, we may not be able
    1109          * to find ourself... */
    1110 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
    1111         {
    1112             int argc_l;
    1113             char** argv_l=child->argv;
    1114             char *name = child->argv[0];
    1115 
    1116             /* Count argc for use in a second... */
    1117             for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++);
    1118             optind = 1;
    1119             debug_printf("running applet %s\n", name);
    1120             run_applet_by_name(name, argc_l, child->argv);
    1121         }
    1122 #endif
    1123         debug_printf("exec of %s\n",child->argv[0]);
    1124         execvp(child->argv[0],child->argv);
    1125         bb_perror_msg("couldn't exec: %s",child->argv[0]);
    1126         _exit(1);
    1127     } else if (child->group) {
    1128         debug_printf("runtime nesting to group\n");
    1129         interactive=0;    /* crucial!!!! */
     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");
    11301416        rcode = run_list_real(child->group);
    11311417        /* OK to leak memory by not calling free_pipe_list,
    11321418         * since this process is about to exit */
    11331419        _exit(rcode);
    1134     } else {
    1135         /* Can happen.  See what bash does with ">foo" by itself. */
    1136         debug_printf("trying to pseudo_exec null command\n");
    1137         _exit(EXIT_SUCCESS);
    1138     }
     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;
    11391455}
    11401456
     
    11421458{
    11431459    struct pipe *thejob;
     1460    int i;
    11441461
    11451462    /* Linear search for the ID of the job to use */
     
    11491466            pi->jobid = thejob->jobid + 1;
    11501467
    1151     /* add thejob to the list of running jobs */
     1468    /* Add thejob to the list of running jobs */
    11521469    if (!job_list) {
    11531470        thejob = job_list = xmalloc(sizeof(*thejob));
    11541471    } else {
    1155         for (thejob = job_list; thejob->next; thejob = thejob->next) /* nothing */;
     1472        for (thejob = job_list; thejob->next; thejob = thejob->next)
     1473            continue;
    11561474        thejob->next = xmalloc(sizeof(*thejob));
    11571475        thejob = thejob->next;
    11581476    }
    11591477
    1160     /* physically copy the struct job */
     1478    /* Physically copy the struct job */
    11611479    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    }
    11621488    thejob->next = NULL;
    1163     thejob->running_progs = thejob->num_progs;
    1164     thejob->stopped_progs = 0;
    1165     thejob->text = xmalloc(BUFSIZ); /* cmdedit buffer size */
    1166 
    1167     //if (pi->progs[0] && pi->progs[0].argv && pi->progs[0].argv[0])
    1168     {
    1169         char *bar=thejob->text;
    1170         char **foo=pi->progs[0].argv;
    1171         while(foo && *foo) {
    1172             bar += sprintf(bar, "%s ", *foo++);
    1173         }
    1174     }
    1175 
    1176     /* we don't wait for background thejobs to return -- append it
     1489    thejob->cmdtext = xstrdup(get_cmdtext(pi));
     1490
     1491    /* We don't wait for background thejobs to return -- append it
    11771492       to the list of backgrounded thejobs and leave it alone */
    1178     printf("[%d] %d\n", thejob->jobid, thejob->progs[0].pid);
     1493    printf("[%d] %d %s\n", thejob->jobid, thejob->progs[0].pid, thejob->cmdtext);
    11791494    last_bg_pid = thejob->progs[0].pid;
    11801495    last_jobid = thejob->jobid;
    11811496}
    11821497
    1183 /* remove a backgrounded job */
    11841498static void remove_bg_job(struct pipe *pi)
    11851499{
     
    11981512    else
    11991513        last_jobid = 0;
    1200 
     1514}
     1515
     1516/* remove a backgrounded job */
     1517static void delete_finished_bg_job(struct pipe *pi)
     1518{
     1519    remove_bg_job(pi);
    12011520    pi->stopped_progs = 0;
    12021521    free_pipe(pi, 0);
    12031522    free(pi);
    12041523}
     1524#endif /* JOB */
    12051525
    12061526/* Checks to see if any processes have exited -- if they
     
    12101530    int attributes;
    12111531    int status;
     1532#if ENABLE_HUSH_JOB
    12121533    int prognum = 0;
    12131534    struct pipe *pi;
     1535#endif
    12141536    pid_t childpid;
     1537    int rcode = 0;
    12151538
    12161539    attributes = WUNTRACED;
    1217     if (fg_pipe==NULL) {
     1540    if (fg_pipe == NULL) {
    12181541        attributes |= WNOHANG;
    12191542    }
    12201543
     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:
    12211557    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? */
    12221572        if (fg_pipe) {
    1223             int i, rcode = 0;
    1224             for (i=0; i < fg_pipe->num_progs; i++) {
     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);
    12251576                if (fg_pipe->progs[i].pid == childpid) {
    1226                     if (i==fg_pipe->num_progs-1)
    1227                         rcode=WEXITSTATUS(status);
    1228                     (fg_pipe->num_progs)--;
    1229                     return(rcode);
     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;
    12301600                }
    12311601            }
    1232         }
    1233 
     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 */
    12341608        for (pi = job_list; pi; pi = pi->next) {
    12351609            prognum = 0;
    1236             while (prognum < pi->num_progs && pi->progs[prognum].pid != childpid) {
     1610            while (prognum < pi->num_progs) {
     1611                if (pi->progs[prognum].pid == childpid)
     1612                    goto found_pi_and_prognum;
    12371613                prognum++;
    12381614            }
    1239             if (prognum < pi->num_progs)
    1240                 break;
    1241         }
    1242 
    1243         if(pi==NULL) {
    1244             debug_printf("checkjobs: pid %d was not in our list!\n", childpid);
    1245             continue;
    1246         }
    1247 
    1248         if (WIFEXITED(status) || WIFSIGNALED(status)) {
     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) {
    12491625            /* child exited */
     1626            pi->progs[prognum].pid = 0;
    12501627            pi->running_progs--;
    1251             pi->progs[prognum].pid = 0;
    1252 
    12531628            if (!pi->running_progs) {
    1254                 printf(JOB_STATUS_FORMAT, pi->jobid, "Done", pi->text);
    1255                 remove_bg_job(pi);
     1629                printf(JOB_STATUS_FORMAT, pi->jobid,
     1630                            "Done", pi->cmdtext);
     1631                delete_finished_bg_job(pi);
    12561632            }
    12571633        } else {
     
    12591635            pi->stopped_progs++;
    12601636            pi->progs[prognum].is_stopped = 1;
    1261 
    1262 #if 0
    1263             /* Printing this stuff is a pain, since it tends to
    1264              * overwrite the prompt an inconveinient moments.  So
    1265              * don't do that.  */
    1266             if (pi->stopped_progs == pi->num_progs) {
    1267                 printf("\n"JOB_STATUS_FORMAT, pi->jobid, "Stopped", pi->text);
    1268             }
    1269 #endif
    1270         }
    1271     }
    1272 
    1273     if (childpid == -1 && errno != ECHILD)
     1637        }
     1638#endif
     1639    }
     1640
     1641    /* wait found no children or failed */
     1642
     1643    if (childpid && errno != ECHILD)
    12741644        bb_perror_msg("waitpid");
    1275 
    1276     /* move the shell to the foreground */
    1277     //if (interactive && tcsetpgrp(shell_terminal, getpgid(0)))
    1278     //  bb_perror_msg("tcsetpgrp-2");
    1279     return -1;
    1280 }
    1281 
    1282 /* Figure out our controlling tty, checking in order stderr,
    1283  * stdin, and stdout.  If check_pgrp is set, also check that
    1284  * we belong to the foreground process group associated with
    1285  * that tty.  The value of shell_terminal is needed in order to call
    1286  * tcsetpgrp(shell_terminal, ...); */
    1287 #if 0
    1288 static void controlling_tty(int check_pgrp)
    1289 {
    1290     pid_t curpgrp;
    1291 
    1292     if ((curpgrp = tcgetpgrp(shell_terminal = 2)) < 0
    1293             && (curpgrp = tcgetpgrp(shell_terminal = 0)) < 0
    1294             && (curpgrp = tcgetpgrp(shell_terminal = 1)) < 0)
    1295         goto shell_terminal_error;
    1296 
    1297     if (check_pgrp && curpgrp != getpgid(0))
    1298         goto shell_terminal_error;
    1299 
    1300     return;
    1301 
    1302 shell_terminal_error:
    1303         shell_terminal = -1;
    1304         return;
     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;
    13051659}
    13061660#endif
     
    13211675 * now has its stdout directed to the input of the appropriate pipe,
    13221676 * 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!
    13231680 */
    13241681static int run_pipe_real(struct pipe *pi)
     
    13301687    const struct built_in_command *x;
    13311688    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);
    13321695
    13331696    nextin = 0;
     1697#if ENABLE_HUSH_JOB
    13341698    pi->pgrp = -1;
     1699#endif
     1700    pi->running_progs = 1;
     1701    pi->stopped_progs = 0;
    13351702
    13361703    /* Check if this is a simple builtin (not part of a pipe).
     
    13381705     * pseudo_exec.  "echo foo | read bar" doesn't work on bash, either.
    13391706     */
    1340     if (pi->num_progs == 1) child = & (pi->progs[0]);
    1341     if (pi->num_progs == 1 && child->group && child->subshell == 0) {
    1342         int squirrel[] = {-1, -1, -1};
    1343         int rcode;
     1707    child = &(pi->progs[0]);
     1708    if (single_fg && child->group && child->subshell == 0) {
    13441709        debug_printf("non-subshell grouping\n");
    13451710        setup_redirects(child, squirrel);
    1346         /* XXX could we merge code with following builtin case,
    1347          * by creating a pseudo builtin that calls run_list_real? */
     1711        debug_printf_exec(": run_list_real\n");
    13481712        rcode = run_list_real(child->group);
    13491713        restore_redirects(squirrel);
    1350         return rcode;
    1351     } else if (pi->num_progs == 1 && pi->progs[0].argv != NULL) {
    1352         for (i=0; is_assignment(child->argv[i]); i++) { /* nothing */ }
    1353         if (i!=0 && child->argv[i]==NULL) {
     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) {
    13541725            /* assignments, but no command: set the local environment */
    1355             for (i=0; child->argv[i]!=NULL; i++) {
    1356 
    1357                 /* Ok, this case is tricky.  We have to decide if this is a
    1358                  * local variable, or an already exported variable.  If it is
    1359                  * already exported, we have to export the new value.  If it is
    1360                  * not exported, we need only set this as a local variable.
    1361                  * This junk is all to decide whether or not to export this
    1362                  * variable. */
    1363                 int export_me=0;
    1364                 char *name, *value;
    1365                 name = bb_xstrdup(child->argv[i]);
    1366                 debug_printf("Local environment set: %s\n", name);
    1367                 value = strchr(name, '=');
    1368                 if (value)
    1369                     *value=0;
    1370                 if ( get_local_var(name)) {
    1371                     export_me=1;
    1372                 }
    1373                 free(name);
    1374                 p = insert_var_value(child->argv[i]);
    1375                 set_local_var(p, export_me);
    1376                 if (p != child->argv[i]) free(p);
     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);
    13771730            }
    13781731            return EXIT_SUCCESS;   /* don't worry about errors in set_local_var() yet */
    13791732        }
    1380         for (i = 0; is_assignment(child->argv[i]); i++) {
    1381             p = insert_var_value(child->argv[i]);
    1382             putenv(strdup(p));
    1383             if (p != child->argv[i]) {
    1384                 child->sp--;
    1385                 free(p);
    1386             }
    1387         }
    1388         if (child->sp) {
    1389             char * str = NULL;
    1390 
    1391             str = make_string((child->argv + i));
    1392             parse_string_outer(str, FLAG_EXIT_FROM_LOOP | FLAG_REPARSING);
    1393             free(str);
    1394             return last_return_code;
     1733        for (i = 0; is_assignment(argv[i]); i++) {
     1734            p = expand_string_to_string(argv[i]);
     1735            //sp: child->sp--;
     1736            putenv(p);
    13951737        }
    13961738        for (x = bltins; x->cmd; x++) {
    1397             if (strcmp(child->argv[i], x->cmd) == 0 ) {
    1398                 int squirrel[] = {-1, -1, -1};
    1399                 int rcode;
    1400                 if (x->function == builtin_exec && child->argv[i+1]==NULL) {
     1739            if (strcmp(argv[i], x->cmd) == 0) {
     1740                if (x->function == builtin_exec && argv[i+1] == NULL) {
    14011741                    debug_printf("magic exec\n");
    1402                     setup_redirects(child,NULL);
     1742                    setup_redirects(child, NULL);
    14031743                    return EXIT_SUCCESS;
    14041744                }
    1405                 debug_printf("builtin inline %s\n", child->argv[0]);
     1745                debug_printf("builtin inline %s\n", argv[0]);
    14061746                /* XXX setup_redirects acts on file descriptors, not FILEs.
    14071747                 * This is perfect for work that comes after exec().
     
    14091749                 * things seem to work with glibc. */
    14101750                setup_redirects(child, squirrel);
    1411                 child->argv+=i;  /* XXX horrible hack */
    1412                 rcode = x->function(child);
    1413                 child->argv-=i;  /* XXX restore hack so free() can work right */
     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);
    14141756                restore_redirects(squirrel);
     1757                debug_printf_exec("run_pipe_real return %d\n", rcode);
    14151758                return rcode;
    14161759            }
    14171760        }
    1418     }
     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);
    14191787
    14201788    for (i = 0; i < pi->num_progs; i++) {
    1421         child = & (pi->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");
    14221794
    14231795        /* pipes are inserted between pairs of commands */
    14241796        if ((i + 1) < pi->num_progs) {
    1425             if (pipe(pipefds)<0) bb_perror_msg_and_die("pipe");
     1797            pipe(pipefds);
    14261798            nextout = pipefds[1];
    14271799        } else {
    1428             nextout=1;
     1800            nextout = 1;
    14291801            pipefds[0] = -1;
    14301802        }
    14311803
    14321804        /* XXX test for failed fork()? */
    1433 #if !defined(__UCLIBC__) || defined(__ARCH_HAS_MMU__)
    1434         if (!(child->pid = fork()))
     1805#if BB_MMU
     1806        child->pid = fork();
    14351807#else
    1436         if (!(child->pid = vfork()))
    1437 #endif
    1438         {
    1439             /* Set the handling for job control signals back to the default.  */
    1440             signal(SIGINT, SIG_DFL);
    1441             signal(SIGQUIT, SIG_DFL);
    1442             signal(SIGTERM, SIG_DFL);
    1443             signal(SIGTSTP, SIG_DFL);
    1444             signal(SIGTTIN, SIG_DFL);
    1445             signal(SIGTTOU, SIG_DFL);
    1446             signal(SIGCHLD, SIG_DFL);
    1447 
     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 */
    14481827            close_all();
    1449 
    14501828            if (nextin != 0) {
    14511829                dup2(nextin, 0);
     
    14561834                close(nextout);
    14571835            }
    1458             if (pipefds[0]!=-1) {
     1836            if (pipefds[0] != -1) {
    14591837                close(pipefds[0]);  /* opposite end of our output pipe */
    14601838            }
    1461 
    14621839            /* Like bash, explicit redirects override pipes,
    14631840             * and the pipe fd is available for dup'ing. */
    1464             setup_redirects(child,NULL);
    1465 
    1466             if (interactive && pi->followup!=PIPE_BG) {
    1467                 /* If we (the child) win the race, put ourselves in the process
    1468                  * group whose leader is the first process in this pipe. */
    1469                 if (pi->pgrp < 0) {
    1470                     pi->pgrp = getpid();
    1471                 }
    1472                 if (setpgid(0, pi->pgrp) == 0) {
    1473                     tcsetpgrp(2, pi->pgrp);
    1474                 }
    1475             }
    1476 
     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);
    14771847            pseudo_exec(child);
    14781848        }
    14791849
    1480 
    1481         /* put our child in the process group whose leader is the
    1482            first process in this pipe */
    1483         if (pi->pgrp < 0) {
     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)
    14841855            pi->pgrp = child->pid;
    1485         }
    1486         /* Don't check for errors.  The child may be dead already,
    1487          * in which case setpgid returns error code EACCES. */
    1488         setpgid(child->pid, pi->pgrp);
    1489 
     1856#endif
    14901857        if (nextin != 0)
    14911858            close(nextin);
     
    14971864        nextin = pipefds[0];
    14981865    }
     1866    debug_printf_exec("run_pipe_real return -1\n");
    14991867    return -1;
    15001868}
    15011869
     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!) */
    15021935static int run_list_real(struct pipe *pi)
    15031936{
    1504     char *save_name = NULL;
    1505     char **list = NULL;
    1506     char **save_list = NULL;
    15071937    struct pipe *rpipe;
     1938#if ENABLE_HUSH_LOOPS
     1939    char *for_varname = NULL;
     1940    char **for_lcur = NULL;
     1941    char **for_list = NULL;
    15081942    int flag_rep = 0;
     1943#endif
    15091944    int save_num_progs;
    1510     int rcode=0, flag_skip=1;
     1945    int flag_skip = 1;
     1946    int rcode = 0; /* probably for gcc only */
    15111947    int flag_restore = 0;
    1512     int if_code=0, next_if_code=0;  /* need double-buffer to handle elif */
    1513     reserved_style rmode, skip_more_in_this_rmode=RES_XXXX;
     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
    15141959    /* check syntax for "for" */
    15151960    for (rpipe = pi; rpipe; rpipe = rpipe->next) {
    1516         if ((rpipe->r_mode == RES_IN ||
    1517             rpipe->r_mode == RES_FOR) &&
    1518             (rpipe->next == NULL)) {
    1519                 syntax();
    1520                 return 1;
    1521         }
    1522         if ((rpipe->r_mode == RES_IN &&
    1523             (rpipe->next->r_mode == RES_IN &&
    1524             rpipe->next->progs->argv != NULL))||
    1525             (rpipe->r_mode == RES_FOR &&
    1526             rpipe->next->r_mode != RES_IN)) {
    1527                 syntax();
    1528                 return 1;
    1529         }
    1530     }
    1531     for (; pi; pi = (flag_restore != 0) ? rpipe : pi->next) {
    1532         if (pi->r_mode == RES_WHILE || pi->r_mode == RES_UNTIL ||
    1533             pi->r_mode == RES_FOR) {
    1534                 flag_restore = 0;
    1535                 if (!rpipe) {
    1536                     flag_rep = 0;
    1537                     rpipe = pi;
    1538                 }
    1539         }
    1540         rmode = pi->r_mode;
    1541         debug_printf("rmode=%d  if_code=%d  next_if_code=%d skip_more=%d\n", rmode, if_code, next_if_code, skip_more_in_this_rmode);
    1542         if (rmode == skip_more_in_this_rmode && flag_skip) {
    1543             if (pi->followup == PIPE_SEQ) flag_skip=0;
     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;
    15442039            continue;
    15452040        }
    15462041        flag_skip = 1;
    1547         skip_more_in_this_rmode = RES_XXXX;
    1548         if (rmode == RES_THEN || rmode == RES_ELSE) if_code = next_if_code;
    1549         if (rmode == RES_THEN &&  if_code) continue;
    1550         if (rmode == RES_ELSE && !if_code) continue;
    1551         if (rmode == RES_ELIF && !if_code) break;
    1552         if (rmode == RES_FOR && pi->num_progs) {
    1553             if (!list) {
     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) {
    15542056                /* if no variable values after "in" we skip "for" */
    1555                 if (!pi->next->progs->argv) continue;
     2057                if (!pi->next->progs->argv)
     2058                    continue;
    15562059                /* create list of variable values */
    1557                 list = make_list_in(pi->next->progs->argv,
    1558                     pi->progs->argv[0]);
    1559                 save_list = list;
    1560                 save_name = pi->progs->argv[0];
     2060                for_list = expand_strvec_to_strvec(pi->next->progs->argv);
     2061                for_lcur = for_list;
     2062                for_varname = pi->progs->argv[0];
    15612063                pi->progs->argv[0] = NULL;
    15622064                flag_rep = 1;
    15632065            }
    1564             if (!(*list)) {
    1565                 free(pi->progs->argv[0]);
    1566                 free(save_list);
    1567                 list = NULL;
     2066            free(pi->progs->argv[0]);
     2067            if (!*for_lcur) {
     2068                free(for_list);
     2069                for_lcur = NULL;
    15682070                flag_rep = 0;
    1569                 pi->progs->argv[0] = save_name;
    1570                 pi->progs->glob_result.gl_pathv[0] =
    1571                     pi->progs->argv[0];
     2071                pi->progs->argv[0] = for_varname;
     2072                pi->progs->glob_result.gl_pathv[0] = pi->progs->argv[0];
    15722073                continue;
    1573             } else {
    1574                 /* insert new value from list for variable */
    1575                 if (pi->progs->argv[0])
    1576                     free(pi->progs->argv[0]);
    1577                 pi->progs->argv[0] = *list++;
    1578                 pi->progs->glob_result.gl_pathv[0] =
    1579                     pi->progs->argv[0];
    1580             }
    1581         }
    1582         if (rmode == RES_IN) continue;
    1583         if (rmode == RES_DO) {
    1584             if (!flag_rep) continue;
    1585         }
    1586         if ((rmode == RES_DONE)) {
     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) {
    15872087            if (flag_rep) {
    15882088                flag_restore = 1;
     
    15912091            }
    15922092        }
    1593         if (pi->num_progs == 0) continue;
     2093#endif
     2094        if (pi->num_progs == 0)
     2095            continue;
    15942096        save_num_progs = pi->num_progs; /* save number of programs */
     2097        debug_printf_exec(": run_pipe_real with %d members\n", pi->num_progs);
    15952098        rcode = run_pipe_real(pi);
    1596         debug_printf("run_pipe_real returned %d\n",rcode);
    1597         if (rcode!=-1) {
     2099        if (rcode != -1) {
    15982100            /* We only ran a builtin: rcode was set by the return value
    15992101             * of run_pipe_real(), and we don't need to wait for anything. */
    1600         } else if (pi->followup==PIPE_BG) {
    1601             /* XXX check bash's behavior with nontrivial pipes */
    1602             /* XXX compute jobid */
    1603             /* XXX what does bash do with attempts to background builtins? */
    1604             insert_bg_job(pi);
     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
    16052111            rcode = EXIT_SUCCESS;
    16062112        } else {
    1607             if (interactive) {
    1608                 /* move the new process group into the foreground */
    1609                 if (tcsetpgrp(shell_terminal, pi->pgrp) && errno != ENOTTY)
    1610                     bb_perror_msg("tcsetpgrp-3");
     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 */
    16112122                rcode = checkjobs(pi);
    1612                 /* move the shell to the foreground */
    1613                 if (tcsetpgrp(shell_terminal, getpgid(0)) && errno != ENOTTY)
    1614                     bb_perror_msg("tcsetpgrp-4");
    1615             } else {
    1616                 rcode = checkjobs(pi);
    1617             }
    1618             debug_printf("checkjobs returned %d\n",rcode);
    1619         }
    1620         last_return_code=rcode;
     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;
    16212128        pi->num_progs = save_num_progs; /* restore number of programs */
    1622         if ( rmode == RES_IF || rmode == RES_ELIF )
    1623             next_if_code=rcode;  /* can be overwritten a number of times */
    1624         if (rmode == RES_WHILE)
     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)
    16252135            flag_rep = !last_return_code;
    1626         if (rmode == RES_UNTIL)
     2136        if (rword == RES_UNTIL)
    16272137            flag_rep = last_return_code;
    1628         if ( (rcode==EXIT_SUCCESS && pi->followup==PIPE_OR) ||
    1629              (rcode!=EXIT_SUCCESS && pi->followup==PIPE_AND) )
    1630             skip_more_in_this_rmode=rmode;
     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        }
    16312144        checkjobs(NULL);
    16322145    }
     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);
    16332160    return rcode;
    1634 }
    1635 
    1636 /* broken, of course, but OK for testing */
    1637 static char *indenter(int i)
    1638 {
    1639     static char blanks[]="                                    ";
    1640     return &blanks[sizeof(blanks)-i-1];
    16412161}
    16422162
     
    16472167    struct child_prog *child;
    16482168    struct redir_struct *r, *rnext;
    1649     int a, i, ret_code=0;
    1650     char *ind = indenter(indent);
     2169    int a, i, ret_code = 0;
    16512170
    16522171    if (pi->stopped_progs > 0)
    16532172        return ret_code;
    1654     final_printf("%s run pipe: (pid %d)\n",ind,getpid());
    1655     for (i=0; i<pi->num_progs; i++) {
     2173    debug_printf_clean("%s run pipe: (pid %d)\n", indenter(indent), getpid());
     2174    for (i = 0; i < pi->num_progs; i++) {
    16562175        child = &pi->progs[i];
    1657         final_printf("%s  command %d:\n",ind,i);
     2176        debug_printf_clean("%s  command %d:\n", indenter(indent), i);
    16582177        if (child->argv) {
    1659             for (a=0,p=child->argv; *p; a++,p++) {
    1660                 final_printf("%s   argv[%d] = %s\n",ind,a,*p);
     2178            for (a = 0, p = child->argv; *p; a++, p++) {
     2179                debug_printf_clean("%s   argv[%d] = %s\n", indenter(indent), a, *p);
    16612180            }
    16622181            globfree(&child->glob_result);
    1663             child->argv=NULL;
     2182            child->argv = NULL;
    16642183        } else if (child->group) {
    1665             final_printf("%s   begin group (subshell:%d)\n",ind, child->subshell);
    1666             ret_code = free_pipe_list(child->group,indent+3);
    1667             final_printf("%s   end group\n",ind);
     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));
    16682187        } else {
    1669             final_printf("%s   (nil)\n",ind);
    1670         }
    1671         for (r=child->redirects; r; r=rnext) {
    1672             final_printf("%s   redirect %d%s", ind, r->fd, redir_table[r->type].descrip);
     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);
    16732192            if (r->dup == -1) {
    16742193                /* guard against the case >$FOO, where foo is unset or blank */
    16752194                if (r->word.gl_pathv) {
    1676                     final_printf(" %s\n", *r->word.gl_pathv);
     2195                    debug_printf_clean(" %s\n", *r->word.gl_pathv);
    16772196                    globfree(&r->word);
    16782197                }
    16792198            } else {
    1680                 final_printf("&%d\n", r->dup);
    1681             }
    1682             rnext=r->next;
     2199                debug_printf_clean("&%d\n", r->dup);
     2200            }
     2201            rnext = r->next;
    16832202            free(r);
    16842203        }
    1685         child->redirects=NULL;
     2204        child->redirects = NULL;
    16862205    }
    16872206    free(pi->progs);   /* children are an array, they get freed all at once */
    1688     pi->progs=NULL;
     2207    pi->progs = NULL;
     2208#if ENABLE_HUSH_JOB
     2209    free(pi->cmdtext);
     2210    pi->cmdtext = NULL;
     2211#endif
    16892212    return ret_code;
    16902213}
     
    16922215static int free_pipe_list(struct pipe *head, int indent)
    16932216{
    1694     int rcode=0;   /* if list has no members */
     2217    int rcode = 0;   /* if list has no members */
    16952218    struct pipe *pi, *next;
    1696     char *ind = indenter(indent);
    1697     for (pi=head; pi; pi=next) {
    1698         final_printf("%s pipe reserved mode %d\n", ind, pi->r_mode);
     2219
     2220    for (pi = head; pi; pi = next) {
     2221        debug_printf_clean("%s pipe reserved mode %d\n", indenter(indent), pi->res_word);
    16992222        rcode = free_pipe(pi, indent);
    1700         final_printf("%s pipe followup code %d\n", ind, pi->followup);
    1701         next=pi->next;
    1702         pi->next=NULL;
     2223        debug_printf_clean("%s pipe followup code %d\n", indenter(indent), pi->followup);
     2224        next = pi->next;
     2225        /*pi->next = NULL;*/
    17032226        free(pi);
    17042227    }
     
    17092232static int run_list(struct pipe *pi)
    17102233{
    1711     int rcode=0;
    1712     if (fake_mode==0) {
     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);
    17132238        rcode = run_list_real(pi);
    17142239    }
    1715     /* free_pipe_list has the side effect of clearing memory
     2240    /* free_pipe_list has the side effect of clearing memory.
    17162241     * In the long run that function can be merged with run_list_real,
    17172242     * but doing that now would hobble the debugging effort. */
    1718     free_pipe_list(pi,0);
     2243    free_pipe_list(pi, 0);
     2244    debug_printf_exec("run_list return %d\n", rcode);
    17192245    return rcode;
    17202246}
     
    17292255static int globhack(const char *src, int flags, glob_t *pglob)
    17302256{
    1731     int cnt=0, pathc;
     2257    int cnt = 0, pathc;
    17322258    const char *s;
    17332259    char *dest;
    1734     for (cnt=1, s=src; s && *s; s++) {
     2260    for (cnt = 1, s = src; s && *s; s++) {
    17352261        if (*s == '\\') s++;
    17362262        cnt++;
    17372263    }
    1738     dest = malloc(cnt);
    1739     if (!dest) return GLOB_NOSPACE;
     2264    dest = xmalloc(cnt);
    17402265    if (!(flags & GLOB_APPEND)) {
    1741         pglob->gl_pathv=NULL;
    1742         pglob->gl_pathc=0;
    1743         pglob->gl_offs=0;
    1744         pglob->gl_offs=0;
     2266        pglob->gl_pathv = NULL;
     2267        pglob->gl_pathc = 0;
     2268        pglob->gl_offs = 0;
     2269        pglob->gl_offs = 0;
    17452270    }
    17462271    pathc = ++pglob->gl_pathc;
    1747     pglob->gl_pathv = realloc(pglob->gl_pathv, (pathc+1)*sizeof(*pglob->gl_pathv));
    1748     if (pglob->gl_pathv == NULL) return GLOB_NOSPACE;
    1749     pglob->gl_pathv[pathc-1]=dest;
    1750     pglob->gl_pathv[pathc]=NULL;
    1751     for (s=src; s && *s; s++, dest++) {
     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++) {
    17522276        if (*s == '\\') s++;
    17532277        *dest = *s;
    17542278    }
    1755     *dest='\0';
     2279    *dest = '\0';
    17562280    return 0;
    17572281}
     
    17622286    for (; *s; s++) {
    17632287        if (*s == '\\') s++;
    1764         if (strchr("*[?",*s)) return 1;
     2288        if (strchr("*[?", *s)) return 1;
    17652289    }
    17662290    return 0;
    17672291}
    1768 
    1769 #if 0
    1770 static void globprint(glob_t *pglob)
    1771 {
    1772     int i;
    1773     debug_printf("glob_t at %p:\n", pglob);
    1774     debug_printf("  gl_pathc=%d  gl_pathv=%p  gl_offs=%d  gl_flags=%d\n",
    1775         pglob->gl_pathc, pglob->gl_pathv, pglob->gl_offs, pglob->gl_flags);
    1776     for (i=0; i<pglob->gl_pathc; i++)
    1777         debug_printf("pglob->gl_pathv[%d] = %p = %s\n", i,
    1778             pglob->gl_pathv[i], pglob->gl_pathv[i]);
    1779 }
    1780 #endif
    17812292
    17822293static int xglob(o_string *dest, int flags, glob_t *pglob)
     
    17902301            /* bash man page calls this an "explicit" null */
    17912302            gr = globhack(dest->data, flags, pglob);
    1792             debug_printf("globhack returned %d\n",gr);
     2303            debug_printf("globhack returned %d\n", gr);
    17932304        } else {
    17942305            return 0;
     
    17962307    } else if (glob_needed(dest->data)) {
    17972308        gr = glob(dest->data, flags, NULL, pglob);
    1798         debug_printf("glob returned %d\n",gr);
     2309        debug_printf("glob returned %d\n", gr);
    17992310        if (gr == GLOB_NOMATCH) {
    18002311            /* quote removal, or more accurately, backslash removal */
    18012312            gr = globhack(dest->data, flags, pglob);
    1802             debug_printf("globhack returned %d\n",gr);
     2313            debug_printf("globhack returned %d\n", gr);
    18032314        }
    18042315    } else {
    18052316        gr = globhack(dest->data, flags, pglob);
    1806         debug_printf("globhack returned %d\n",gr);
     2317        debug_printf("globhack returned %d\n", gr);
    18072318    }
    18082319    if (gr == GLOB_NOSPACE)
    18092320        bb_error_msg_and_die("out of memory during glob");
    18102321    if (gr != 0) { /* GLOB_ABORTED ? */
    1811         bb_error_msg("glob(3) error %d",gr);
     2322        bb_error_msg("glob(3) error %d", gr);
    18122323    }
    18132324    /* globprint(glob_target); */
     
    18152326}
    18162327
     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
    18172662/* This is used to get/check local shell variables */
    1818 static char *get_local_var(const char *s)
    1819 {
    1820     struct variables *cur;
    1821 
    1822     if (!s)
     2663static struct variable *get_local_var(const char *name)
     2664{
     2665    struct variable *cur;
     2666    int len;
     2667
     2668    if (!name)
    18232669        return NULL;
    1824     for (cur = top_vars; cur; cur=cur->next)
    1825         if(strcmp(cur->name, s)==0)
    1826             return cur->value;
     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    }
    18272675    return NULL;
    18282676}
    18292677
    1830 /* This is used to set local shell variables
    1831    flg_export==0 if only local (not exporting) variable
    1832    flg_export==1 if "new" exporting environ
    1833    flg_export>1  if current startup environ (not call putenv()) */
    1834 static int set_local_var(const char *s, int flg_export)
    1835 {
    1836     char *name, *value;
    1837     int result=0;
    1838     struct variables *cur;
    1839 
    1840     name=strdup(s);
    1841 
    1842     /* Assume when we enter this function that we are already in
    1843      * NAME=VALUE format.  So the first order of business is to
    1844      * split 's' on the '=' into 'name' and 'value' */
    1845     value = strchr(name, '=');
    1846     if (value==0 && ++value==0) {
    1847         free(name);
     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);
    18482689        return -1;
    18492690    }
    1850     *value++ = 0;
    1851 
    1852     for(cur = top_vars; cur; cur = cur->next) {
    1853         if(strcmp(cur->name, name)==0)
    1854             break;
    1855     }
    1856 
    1857     if(cur) {
    1858         if(strcmp(cur->value, value)==0) {
    1859             if(flg_export>0 && cur->flg_export==0)
    1860                 cur->flg_export=flg_export;
    1861             else
    1862                 result++;
    1863         } else {
    1864             if(cur->flg_read_only) {
    1865                 bb_error_msg("%s: readonly variable", name);
    1866                 result = -1;
    1867             } else {
    1868                 if(flg_export>0 || cur->flg_export>1)
    1869                     cur->flg_export=1;
    1870                 free(cur->value);
    1871 
    1872                 cur->value = strdup(value);
    1873             }
    1874         }
    1875     } else {
    1876         cur = malloc(sizeof(struct variables));
    1877         if(!cur) {
    1878             result = -1;
    1879         } else {
    1880             cur->name = strdup(name);
    1881             if(cur->name == 0) {
    1882                 free(cur);
    1883                 result = -1;
    1884             } else {
    1885                 struct variables *bottom = top_vars;
    1886                 cur->value = strdup(value);
    1887                 cur->next = 0;
    1888                 cur->flg_export = flg_export;
    1889                 cur->flg_read_only = 0;
    1890                 while(bottom->next) bottom=bottom->next;
    1891                 bottom->next = cur;
    1892             }
    1893         }
    1894     }
    1895 
    1896     if(result==0 && cur->flg_export==1) {
    1897         *(value-1) = '=';
    1898         result = putenv(name);
    1899     } else {
    1900         free(name);
    1901         if(result>0)            /* equivalent to previous set */
    1902             result = 0;
    1903     }
    1904     return result;
     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;
    19052743}
    19062744
    19072745static void unset_local_var(const char *name)
    19082746{
    1909     struct variables *cur;
    1910 
    1911     if (name) {
    1912         for (cur = top_vars; cur; cur=cur->next) {
    1913             if(strcmp(cur->name, name)==0)
    1914                 break;
    1915         }
    1916         if(cur!=0) {
    1917             struct variables *next = top_vars;
    1918             if(cur->flg_read_only) {
     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) {
    19192758                bb_error_msg("%s: readonly variable", name);
    19202759                return;
    1921             } else {
    1922                 if(cur->flg_export)
    1923                     unsetenv(cur->name);
    1924                 free(cur->name);
    1925                 free(cur->value);
    1926                 while (next->next != cur)
    1927                     next = next->next;
    1928                 next->next = cur->next;
    1929             }
     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);
    19302767            free(cur);
    1931         }
     2768            return;
     2769        }
     2770        prev = cur;
     2771        cur = cur->next;
    19322772    }
    19332773}
     
    19352775static int is_assignment(const char *s)
    19362776{
    1937     if (s==NULL || !isalpha(*s)) return 0;
    1938     ++s;
    1939     while(isalnum(*s) || *s=='_') ++s;
    1940     return *s=='=';
     2777    if (!s || !isalpha(*s))
     2778        return 0;
     2779    s++;
     2780    while (isalnum(*s) || *s == '_')
     2781        s++;
     2782    return *s == '=';
    19412783}
    19422784
     
    19482790    struct in_str *input)
    19492791{
    1950     struct child_prog *child=ctx->child;
     2792    struct child_prog *child = ctx->child;
    19512793    struct redir_struct *redir = child->redirects;
    1952     struct redir_struct *last_redir=NULL;
     2794    struct redir_struct *last_redir = NULL;
    19532795
    19542796    /* Create a new redir_struct and drop it onto the end of the linked list */
    1955     while(redir) {
    1956         last_redir=redir;
    1957         redir=redir->next;
     2797    while (redir) {
     2798        last_redir = redir;
     2799        redir = redir->next;
    19582800    }
    19592801    redir = xmalloc(sizeof(struct redir_struct));
    1960     redir->next=NULL;
    1961     redir->word.gl_pathv=NULL;
     2802    redir->next = NULL;
     2803    redir->word.gl_pathv = NULL;
    19622804    if (last_redir) {
    1963         last_redir->next=redir;
     2805        last_redir->next = redir;
    19642806    } else {
    1965         child->redirects=redir;
    1966     }
    1967 
    1968     redir->type=style;
    1969     redir->fd= (fd==-1) ? redir_table[style].default_fd : fd ;
     2807        child->redirects = redir;
     2808    }
     2809
     2810    redir->type = style;
     2811    redir->fd = (fd == -1) ? redir_table[style].default_fd : fd;
    19702812
    19712813    debug_printf("Redirect type %d%s\n", redir->fd, redir_table[style].descrip);
     
    19832825         * since we need to return and let src be expanded first.
    19842826         * Set ctx->pending_redirect, so we know what to do at the
    1985          * end of the next parsed word.
    1986          */
     2827         * end of the next parsed word. */
    19872828        ctx->pending_redirect = redir;
    19882829    }
     
    19902831}
    19912832
    1992 static struct pipe *new_pipe(void) {
     2833static struct pipe *new_pipe(void)
     2834{
    19932835    struct pipe *pi;
    1994     pi = xmalloc(sizeof(struct pipe));
    1995     pi->num_progs = 0;
    1996     pi->progs = NULL;
    1997     pi->next = NULL;
    1998     pi->followup = 0;  /* invalid */
    1999     pi->r_mode = RES_NONE;
     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;
    20002843    return pi;
    20012844}
     
    20032846static void initialize_context(struct p_context *ctx)
    20042847{
    2005     ctx->pipe=NULL;
    2006     ctx->pending_redirect=NULL;
    2007     ctx->child=NULL;
    2008     ctx->list_head=new_pipe();
    2009     ctx->pipe=ctx->list_head;
    2010     ctx->w=RES_NONE;
    2011     ctx->stack=NULL;
    2012     ctx->old_flag=0;
     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;
    20132855    done_command(ctx);   /* creates the memory for working child */
    20142856}
     
    20192861 * case, function, and select are obnoxious, save those for later.
    20202862 */
     2863#if ENABLE_HUSH_IF || ENABLE_HUSH_LOOPS
    20212864static int reserved_word(o_string *dest, struct p_context *ctx)
    20222865{
    20232866    struct reserved_combo {
    2024         char *literal;
    2025         int code;
    2026         long flag;
     2867        char literal[7];
     2868        unsigned char code;
     2869        int flag;
    20272870    };
    20282871    /* Mostly a list of accepted follow-up reserved words.
     
    20312874     * FLAG_START means the word must start a new compound list.
    20322875     */
    2033     static struct reserved_combo reserved_list[] = {
     2876    static const struct reserved_combo reserved_list[] = {
     2877#if ENABLE_HUSH_IF
    20342878        { "if",    RES_IF,    FLAG_THEN | FLAG_START },
    20352879        { "then",  RES_THEN,  FLAG_ELIF | FLAG_ELSE | FLAG_FI },
     
    20372881        { "else",  RES_ELSE,  FLAG_FI   },
    20382882        { "fi",    RES_FI,    FLAG_END  },
     2883#endif
     2884#if ENABLE_HUSH_LOOPS
    20392885        { "for",   RES_FOR,   FLAG_IN   | FLAG_START },
    20402886        { "while", RES_WHILE, FLAG_DO   | FLAG_START },
     
    20432889        { "do",    RES_DO,    FLAG_DONE },
    20442890        { "done",  RES_DONE,  FLAG_END  }
     2891#endif
    20452892    };
    2046     struct reserved_combo *r;
    2047     for (r=reserved_list;
    2048 #define NRES sizeof(reserved_list)/sizeof(struct reserved_combo)
    2049         r<reserved_list+NRES; r++) {
    2050         if (strcmp(dest->data, r->literal) == 0) {
    2051             debug_printf("found reserved word %s, code %d\n",r->literal,r->code);
    2052             if (r->flag & FLAG_START) {
    2053                 struct p_context *new = xmalloc(sizeof(struct p_context));
    2054                 debug_printf("push stack\n");
    2055                 if (ctx->w == RES_IN || ctx->w == RES_FOR) {
    2056                     syntax();
    2057                     free(new);
    2058                     ctx->w = RES_SNTX;
    2059                     b_reset(dest);
    2060                     return 1;
    2061                 }
    2062                 *new = *ctx;   /* physical copy */
    2063                 initialize_context(ctx);
    2064                 ctx->stack=new;
    2065             } else if ( ctx->w == RES_NONE || ! (ctx->old_flag & (1<<r->code))) {
    2066                 syntax();
    2067                 ctx->w = RES_SNTX;
     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;
    20682907                b_reset(dest);
    20692908                return 1;
    20702909            }
    2071             ctx->w=r->code;
    2072             ctx->old_flag = r->flag;
    2073             if (ctx->old_flag & FLAG_END) {
    2074                 struct p_context *old;
    2075                 debug_printf("pop stack\n");
    2076                 done_pipe(ctx,PIPE_SEQ);
    2077                 old = ctx->stack;
    2078                 old->child->group = ctx->list_head;
    2079                 old->child->subshell = 0;
    2080                 *ctx = *old;   /* physical copy */
    2081                 free(old);
    2082             }
    2083             b_reset (dest);
     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);
    20842919            return 1;
    20852920        }
     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;
    20862935    }
    20872936    return 0;
    20882937}
    2089 
    2090 /* normal return is 0.
     2938#else
     2939#define reserved_word(dest, ctx) ((int)0)
     2940#endif
     2941
     2942/* Normal return is 0.
    20912943 * Syntax or xglob errors return 1. */
    20922944static int done_word(o_string *dest, struct p_context *ctx)
    20932945{
    2094     struct child_prog *child=ctx->child;
     2946    struct child_prog *child = ctx->child;
    20952947    glob_t *glob_target;
    20962948    int gr, flags = 0;
    20972949
    2098     debug_printf("done_word: %s %p\n", dest->data, child);
     2950    debug_printf_parse("done_word entered: '%s' %p\n", dest->data, child);
    20992951    if (dest->length == 0 && !dest->nonnull) {
    2100         debug_printf(" true null, ignored\n");
     2952        debug_printf_parse("done_word return 0: true null, ignored\n");
    21012953        return 0;
    21022954    }
     
    21052957    } else {
    21062958        if (child->group) {
    2107             syntax();
    2108             return 1;  /* syntax error, groups and arglists don't mix */
    2109         }
    2110         if (!child->argv && (ctx->type & FLAG_PARSE_SEMICOLON)) {
    2111             debug_printf("checking %s for reserved-ness\n",dest->data);
    2112             if (reserved_word(dest,ctx)) return ctx->w==RES_SNTX;
     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            }
    21132969        }
    21142970        glob_target = &child->glob_result;
    2115         if (child->argv) flags |= GLOB_APPEND;
     2971        if (child->argv)
     2972            flags |= GLOB_APPEND;
    21162973    }
    21172974    gr = xglob(dest, flags, glob_target);
    2118     if (gr != 0) return 1;
     2975    if (gr != 0) {
     2976        debug_printf_parse("done_word return 1: xglob returned %d\n", gr);
     2977        return 1;
     2978    }
    21192979
    21202980    b_reset(dest);
    21212981    if (ctx->pending_redirect) {
    2122         ctx->pending_redirect=NULL;
     2982        ctx->pending_redirect = NULL;
    21232983        if (glob_target->gl_pathc != 1) {
    21242984            bb_error_msg("ambiguous redirect");
     2985            debug_printf_parse("done_word return 1: ambiguous redirect\n");
    21252986            return 1;
    21262987        }
     
    21282989        child->argv = glob_target->gl_pathv;
    21292990    }
    2130     if (ctx->w == RES_FOR) {
    2131         done_word(dest,ctx);
    2132         done_pipe(ctx,PIPE_SEQ);
    2133     }
     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");
    21342998    return 0;
    21352999}
     
    21403004{
    21413005    /* The child is really already in the pipe structure, so
    2142      * advance the pipe counter and make a new, null child.
    2143      * Only real trickiness here is that the uncommitted
    2144      * child structure, to which ctx->child points, is not
    2145      * counted in pi->num_progs. */
    2146     struct pipe *pi=ctx->pipe;
    2147     struct child_prog *prog=ctx->child;
    2148 
    2149     if (prog && prog->group == NULL
    2150              && prog->argv == NULL
    2151              && prog->redirects == NULL) {
    2152         debug_printf("done_command: skipping null command\n");
    2153         return 0;
    2154     } else if (prog) {
     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        }
    21553018        pi->num_progs++;
    2156         debug_printf("done_command: num_progs incremented to %d\n",pi->num_progs);
     3019        debug_printf_parse("done_command: ++num_progs=%d\n", pi->num_progs);
    21573020    } else {
    2158         debug_printf("done_command: initializing\n");
    2159     }
     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. */
    21603026    pi->progs = xrealloc(pi->progs, sizeof(*pi->progs) * (pi->num_progs+1));
    2161 
    2162     prog = pi->progs + pi->num_progs;
    2163     prog->redirects = NULL;
    2164     prog->argv = NULL;
    2165     prog->is_stopped = 0;
    2166     prog->group = NULL;
    2167     prog->glob_result.gl_pathv = NULL;
    2168     prog->family = pi;
    2169     prog->sp = 0;
    2170     ctx->child = prog;
    2171     prog->type = ctx->type;
    2172 
     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;
    21733040    /* but ctx->pipe and ctx->list_head remain unchanged */
    2174     return 0;
     3041
     3042    return pi->num_progs; /* used only for 0/nonzero check */
    21753043}
    21763044
     
    21783046{
    21793047    struct pipe *new_p;
    2180     done_command(ctx);  /* implicit closure of previous command */
    2181     debug_printf("done_pipe, type %d\n", type);
     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 */
    21823052    ctx->pipe->followup = type;
    2183     ctx->pipe->r_mode = ctx->w;
    2184     new_p=new_pipe();
    2185     ctx->pipe->next = new_p;
    2186     ctx->pipe = new_p;
    2187     ctx->child = NULL;
    2188     done_command(ctx);  /* set up new pipe to accept commands */
     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");
    21893065    return 0;
    21903066}
     
    21963072static int redirect_dup_num(struct in_str *input)
    21973073{
    2198     int ch, d=0, ok=0;
     3074    int ch, d = 0, ok = 0;
    21993075    ch = b_peek(input);
    22003076    if (ch != '&') return -1;
    22013077
    22023078    b_getch(input);  /* get the & */
    2203     ch=b_peek(input);
     3079    ch = b_peek(input);
    22043080    if (ch == '-') {
    22053081        b_getch(input);
     
    22073083    }
    22083084    while (isdigit(ch)) {
    2209         d = d*10+(ch-'0');
    2210         ok=1;
     3085        d = d*10 + (ch-'0');
     3086        ok = 1;
    22113087        b_getch(input);
    22123088        ch = b_peek(input);
     
    22333109    int num;
    22343110
    2235     if (o->length==0) return -1;
    2236     for(num=0; num<o->length; num++) {
    2237         if (!isdigit(*(o->data+num))) {
     3111    if (o->length == 0)
     3112        return -1;
     3113    for (num = 0; num < o->length; num++) {
     3114        if (!isdigit(*(o->data + num))) {
    22383115            return -1;
    22393116        }
    22403117    }
    22413118    /* reuse num (and save an int) */
    2242     num=atoi(o->data);
     3119    num = atoi(o->data);
    22433120    b_reset(o);
    22443121    return num;
    22453122}
    22463123
     3124#if ENABLE_HUSH_TICK
    22473125static FILE *generate_stream_from_list(struct pipe *head)
    22483126{
    22493127    FILE *pf;
    2250 #if 1
    22513128    int pid, channel[2];
    2252     if (pipe(channel)<0) bb_perror_msg_and_die("pipe");
    2253 #if !defined(__UCLIBC__) || defined(__ARCH_HAS_MMU__)
    2254     pid=fork();
     3129
     3130    xpipe(channel);
     3131#if BB_MMU
     3132    pid = fork();
    22553133#else
    2256     pid=vfork();
    2257 #endif
    2258     if (pid<0) {
     3134    pid = vfork();
     3135#endif
     3136    if (pid < 0) {
    22593137        bb_perror_msg_and_die("fork");
    2260     } else if (pid==0) {
     3138    } else if (pid == 0) {
    22613139        close(channel[0]);
    22623140        if (channel[1] != 1) {
    2263             dup2(channel[1],1);
     3141            dup2(channel[1], 1);
    22643142            close(channel[1]);
    22653143        }
    2266 #if 0
    2267 #define SURROGATE "surrogate response"
    2268         write(1,SURROGATE,sizeof(SURROGATE));
    2269         _exit(run_list(head));
    2270 #else
     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);
    22713155        _exit(run_list_real(head));   /* leaks memory */
    2272 #endif
    2273     }
    2274     debug_printf("forked child %d\n",pid);
     3156    }
    22753157    close(channel[1]);
    2276     pf = fdopen(channel[0],"r");
    2277     debug_printf("pipe on FILE *%p\n",pf);
    2278 #else
    2279     free_pipe_list(head,0);
    2280     pf=popen("echo surrogate response","r");
    2281     debug_printf("started fake pipe on FILE *%p\n",pf);
    2282 #endif
     3158    pf = fdopen(channel[0], "r");
    22833159    return pf;
    22843160}
    22853161
    2286 /* this version hacked for testing purposes */
    2287 /* return code is exit status of the process that is run. */
    2288 static int process_command_subs(o_string *dest, struct p_context *ctx, struct in_str *input, int subst_end)
    2289 {
    2290     int retcode;
    2291     o_string result=NULL_O_STRING;
     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;
    22923168    struct p_context inner;
    22933169    FILE *p;
    22943170    struct in_str pipe_str;
     3171
    22953172    initialize_context(&inner);
    22963173
    22973174    /* recursion to generate command */
    22983175    retcode = parse_stream(&result, &inner, input, subst_end);
    2299     if (retcode != 0) return retcode;  /* syntax error or EOF */
     3176    if (retcode != 0)
     3177        return retcode;  /* syntax error or EOF */
    23003178    done_word(&result, &inner);
    23013179    done_pipe(&inner, PIPE_SEQ);
    23023180    b_free(&result);
    23033181
    2304     p=generate_stream_from_list(inner.list_head);
    2305     if (p==NULL) return 1;
     3182    p = generate_stream_from_list(inner.list_head);
     3183    if (p == NULL) return 1;
    23063184    mark_open(fileno(p));
    23073185    setup_file_in_str(&pipe_str, p);
    23083186
    23093187    /* now send results of command back into original context */
    2310     retcode = parse_stream(dest, ctx, &pipe_str, '\0');
    2311     /* XXX In case of a syntax error, should we try to kill the child?
    2312      * That would be tough to do right, so just read until EOF. */
    2313     if (retcode == 1) {
    2314         while (b_getch(&pipe_str)!=EOF) { /* discard */ };
     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);
    23153199    }
    23163200
     
    23183202    /* This is the step that wait()s for the child.  Should be pretty
    23193203     * safe, since we just read an EOF from its stdout.  We could try
    2320      * to better, by using wait(), and keeping track of background jobs
     3204     * to do better, by using wait(), and keeping track of background jobs
    23213205     * at the same time.  That would be a lot of work, and contrary
    23223206     * to the KISS philosophy of this program. */
    23233207    mark_closed(fileno(p));
    2324     retcode=pclose(p);
    2325     free_pipe_list(inner.list_head,0);
    2326     debug_printf("pclosed, retcode=%d\n",retcode);
    2327     /* XXX this process fails to trim a single trailing newline */
     3208    retcode = fclose(p);
     3209    free_pipe_list(inner.list_head, 0);
     3210    debug_printf("closed FILE from child, retcode=%d\n", retcode);
    23283211    return retcode;
    23293212}
     3213#endif
    23303214
    23313215static int parse_group(o_string *dest, struct p_context *ctx,
    23323216    struct in_str *input, int ch)
    23333217{
    2334     int rcode, endch=0;
     3218    int rcode;
     3219    const char *endch = NULL;
    23353220    struct p_context sub;
    23363221    struct child_prog *child = ctx->child;
     3222
     3223    debug_printf_parse("parse_group entered\n");
    23373224    if (child->argv) {
    2338         syntax();
    2339         return 1;  /* syntax error, groups and arglists don't mix */
     3225        syntax(NULL);
     3226        debug_printf_parse("parse_group return 1: syntax error, groups and arglists don't mix\n");
     3227        return 1;
    23403228    }
    23413229    initialize_context(&sub);
    2342     switch(ch) {
    2343         case '(': endch=')'; child->subshell=1; break;
    2344         case '{': endch='}'; break;
    2345         default: syntax();   /* really logic error */
    2346     }
    2347     rcode=parse_stream(dest,&sub,input,endch);
    2348     done_word(dest,&sub); /* finish off the final word in the subcontext */
     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 */
    23493238    done_pipe(&sub, PIPE_SEQ);  /* and the final command there, too */
    23503239    child->group = sub.list_head;
     3240
     3241    debug_printf_parse("parse_group return %d\n", rcode);
    23513242    return rcode;
    23523243    /* child remains "open", available for possible redirects */
    23533244}
    23543245
    2355 /* basically useful version until someone wants to get fancier,
     3246/* Basically useful version until someone wants to get fancier,
    23563247 * see the bash man page under "Parameter Expansion" */
    2357 static char *lookup_param(char *src)
    2358 {
    2359     char *p=NULL;
    2360     if (src) {
    2361         p = getenv(src);
    2362         if (!p)
    2363             p = get_local_var(src);
    2364     }
    2365     return p;
     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;
    23663254}
    23673255
     
    23693257static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input)
    23703258{
    2371     int i, advance=0;
    2372     char sep[]=" ";
    2373     int ch = input->peek(input);  /* first character after the $ */
    2374     debug_printf("handle_dollar: ch=%c\n",ch);
     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);
    23753263    if (isalpha(ch)) {
    23763264        b_addchr(dest, SPECIAL_VAR_SYMBOL);
    2377         ctx->child->sp++;
    2378         while(ch=b_peek(input),isalnum(ch) || ch=='_') {
     3265        //sp: ctx->child->sp++;
     3266        while (1) {
     3267            debug_printf_parse(": '%c'\n", ch);
    23793268            b_getch(input);
    2380             b_addchr(dest,ch);
     3269            b_addchr(dest, ch | quote_mask);
     3270            quote_mask = 0;
     3271            ch = b_peek(input);
     3272            if (!isalnum(ch) && ch != '_')
     3273                break;
    23813274        }
    23823275        b_addchr(dest, SPECIAL_VAR_SYMBOL);
    23833276    } else if (isdigit(ch)) {
    2384         i = ch-'0';  /* XXX is $0 special? */
    2385         if (i<global_argc) {
    2386             parse_string(dest, ctx, global_argv[i]); /* recursion */
    2387         }
    2388         advance = 1;
     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);
    23893284    } else switch (ch) {
    2390         case '$':
    2391             b_adduint(dest,getpid());
    2392             advance = 1;
    2393             break;
    2394         case '!':
    2395             if (last_bg_pid > 0) b_adduint(dest, last_bg_pid);
    2396             advance = 1;
    2397             break;
    2398         case '?':
    2399             b_adduint(dest,last_return_code);
    2400             advance = 1;
    2401             break;
    2402         case '#':
    2403             b_adduint(dest,global_argc ? global_argc-1 : 0);
    2404             advance = 1;
    2405             break;
     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;
    24063292        case '{':
    24073293            b_addchr(dest, SPECIAL_VAR_SYMBOL);
    2408             ctx->child->sp++;
     3294            //sp: ctx->child->sp++;
    24093295            b_getch(input);
    24103296            /* XXX maybe someone will try to escape the '}' */
    2411             while(ch=b_getch(input),ch!=EOF && ch!='}') {
    2412                 b_addchr(dest,ch);
    2413             }
    2414             if (ch != '}') {
    2415                 syntax();
    2416                 return 1;
     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;
    24173309            }
    24183310            b_addchr(dest, SPECIAL_VAR_SYMBOL);
    24193311            break;
     3312#if ENABLE_HUSH_TICK
    24203313        case '(':
    24213314            b_getch(input);
    2422             process_command_subs(dest, ctx, input, ')');
     3315            process_command_subs(dest, ctx, input, ")");
    24233316            break;
    2424         case '*':
    2425             sep[0]=ifs[0];
    2426             for (i=1; i<global_argc; i++) {
    2427                 parse_string(dest, ctx, global_argv[i]);
    2428                 if (i+1 < global_argc) parse_string(dest, ctx, sep);
    2429             }
    2430             break;
    2431         case '@':
     3317#endif
    24323318        case '-':
    24333319        case '_':
    24343320            /* still unhandled, but should be eventually */
    2435             bb_error_msg("unhandled syntax: $%c",ch);
     3321            bb_error_msg("unhandled syntax: $%c", ch);
    24363322            return 1;
    24373323            break;
    24383324        default:
    2439             b_addqchr(dest,'$',dest->quote);
    2440     }
    2441     /* Eat the character if the flag was set.  If the compiler
    2442      * is smart enough, we could substitute "b_getch(input);"
    2443      * for all the "advance = 1;" above, and also end up with
    2444      * a nice size-optimized program.  Hah!  That'll be the day.
    2445      */
    2446     if (advance) b_getch(input);
     3325            b_addqchr(dest, '$', dest->quote);
     3326    }
     3327    debug_printf_parse("handle_dollar return 0\n");
    24473328    return 0;
    24483329}
    24493330
    2450 int parse_string(o_string *dest, struct p_context *ctx, const char *src)
    2451 {
    2452     struct in_str foo;
    2453     setup_string_in_str(&foo, src);
    2454     return parse_stream(dest, ctx, &foo, '\0');
    2455 }
    2456 
    24573331/* return code is 0 for normal exit, 1 for syntax error */
    2458 int parse_stream(o_string *dest, struct p_context *ctx,
    2459     struct in_str *input, int end_trigger)
     3332static int parse_stream(o_string *dest, struct p_context *ctx,
     3333    struct in_str *input, const char *end_trigger)
    24603334{
    24613335    int ch, m;
     
    24683342     * found.  When recursing, quote state is passed in via dest->quote. */
    24693343
    2470     debug_printf("parse_stream, end_trigger=%d\n",end_trigger);
    2471     while ((ch=b_getch(input))!=EOF) {
    2472         m = map[ch];
    2473         next = (ch == '\n') ? 0 : b_peek(input);
    2474         debug_printf("parse_stream: ch=%c (%d) m=%d quote=%d\n",
    2475             ch,ch,m,dest->quote);
    2476         if (m==0 || ((m==1 || m==2) && dest->quote)) {
     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            }
    24773365            b_addqchr(dest, ch, dest->quote);
    2478         } else {
    2479             if (m==2) {  /* unquoted IFS */
    2480                 if (done_word(dest, ctx)) {
    2481                     return 1;
    2482                 }
    2483                 /* If we aren't performing a substitution, treat a newline as a
    2484                  * command separator.  */
    2485                 if (end_trigger != '\0' && ch=='\n')
    2486                     done_pipe(ctx,PIPE_SEQ);
    2487             }
    2488             if (ch == end_trigger && !dest->quote && ctx->w==RES_NONE) {
    2489                 debug_printf("leaving parse_stream (triggered)\n");
    2490                 return 0;
    2491             }
    2492 #if 0
    2493             if (ch=='\n') {
    2494                 /* Yahoo!  Time to run with it! */
    2495                 done_pipe(ctx,PIPE_SEQ);
    2496                 run_list(ctx->list_head);
    2497                 initialize_context(ctx);
    2498             }
    2499 #endif
    2500             if (m!=2) switch (ch) {
     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) {
    25013391        case '#':
    25023392            if (dest->length == 0 && !dest->quote) {
    2503                 while(ch=b_peek(input),ch!=EOF && ch!='\n') { b_getch(input); }
     3393                while (1) {
     3394                    ch = b_peek(input);
     3395                    if (ch == EOF || ch == '\n')
     3396                        break;
     3397                    b_getch(input);
     3398                }
    25043399            } else {
    25053400                b_addqchr(dest, ch, dest->quote);
     
    25083403        case '\\':
    25093404            if (next == EOF) {
    2510                 syntax();
     3405                syntax("\\<eof>");
     3406                debug_printf_parse("parse_stream return 1: \\<eof>\n");
    25113407                return 1;
    25123408            }
     
    25153411            break;
    25163412        case '$':
    2517             if (handle_dollar(dest, ctx, input)!=0) return 1;
     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            }
    25183417            break;
    25193418        case '\'':
    25203419            dest->nonnull = 1;
    2521             while(ch=b_getch(input),ch!=EOF && ch!='\'') {
    2522                 b_addchr(dest,ch);
    2523             }
    2524             if (ch==EOF) {
    2525                 syntax();
     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");
    25263429                return 1;
    25273430            }
     
    25313434            dest->quote = !dest->quote;
    25323435            break;
     3436#if ENABLE_HUSH_TICK
    25333437        case '`':
    2534             process_command_subs(dest, ctx, input, '`');
     3438            process_command_subs(dest, ctx, input, "`");
    25353439            break;
     3440#endif
    25363441        case '>':
    25373442            redir_fd = redirect_opt_num(dest);
    25383443            done_word(dest, ctx);
    2539             redir_style=REDIRECT_OVERWRITE;
     3444            redir_style = REDIRECT_OVERWRITE;
    25403445            if (next == '>') {
    2541                 redir_style=REDIRECT_APPEND;
     3446                redir_style = REDIRECT_APPEND;
    25423447                b_getch(input);
    2543             } else if (next == '(') {
    2544                 syntax();   /* until we support >(list) Process Substitution */
     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");
    25453453                return 1;
    25463454            }
     3455#endif
    25473456            setup_redirect(ctx, redir_fd, redir_style, input);
    25483457            break;
     
    25503459            redir_fd = redirect_opt_num(dest);
    25513460            done_word(dest, ctx);
    2552             redir_style=REDIRECT_INPUT;
     3461            redir_style = REDIRECT_INPUT;
    25533462            if (next == '<') {
    2554                 redir_style=REDIRECT_HEREIS;
     3463                redir_style = REDIRECT_HEREIS;
    25553464                b_getch(input);
    25563465            } else if (next == '>') {
    2557                 redir_style=REDIRECT_IO;
     3466                redir_style = REDIRECT_IO;
    25583467                b_getch(input);
    2559             } else if (next == '(') {
    2560                 syntax();   /* until we support <(list) Process Substitution */
     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");
    25613473                return 1;
    25623474            }
     3475#endif
    25633476            setup_redirect(ctx, redir_fd, redir_style, input);
    25643477            break;
    25653478        case ';':
    25663479            done_word(dest, ctx);
    2567             done_pipe(ctx,PIPE_SEQ);
     3480            done_pipe(ctx, PIPE_SEQ);
    25683481            break;
    25693482        case '&':
    25703483            done_word(dest, ctx);
    2571             if (next=='&') {
     3484            if (next == '&') {
    25723485                b_getch(input);
    2573                 done_pipe(ctx,PIPE_AND);
     3486                done_pipe(ctx, PIPE_AND);
    25743487            } else {
    2575                 done_pipe(ctx,PIPE_BG);
     3488                done_pipe(ctx, PIPE_BG);
    25763489            }
    25773490            break;
    25783491        case '|':
    25793492            done_word(dest, ctx);
    2580             if (next=='|') {
     3493            if (next == '|') {
    25813494                b_getch(input);
    2582                 done_pipe(ctx,PIPE_OR);
     3495                done_pipe(ctx, PIPE_OR);
    25833496            } else {
    25843497                /* we could pick up a file descriptor choice here
     
    25903503        case '(':
    25913504        case '{':
    2592             if (parse_group(dest, ctx, input, ch)!=0) return 1;
     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            }
    25933509            break;
    25943510        case ')':
    25953511        case '}':
    2596             syntax();   /* Proper use of this character caught by end_trigger */
     3512            syntax("unexpected }");   /* Proper use of this character is caught by end_trigger */
     3513            debug_printf_parse("parse_stream return 1: unexpected '}'\n");
    25973514            return 1;
    2598             break;
    25993515        default:
    2600             syntax();   /* this is really an internal logic error */
    2601             return 1;
    2602             }
    2603         }
    2604     }
    2605     /* complain if quote?  No, maybe we just finished a command substitution
     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
    26063521     * that was quoted.  Example:
    26073522     * $ echo "`cat foo` plus more"
    26083523     * and we just got the EOF generated by the subshell that ran "cat foo"
    2609      * The only real complaint is if we got an EOF when end_trigger != '\0',
     3524     * The only real complaint is if we got an EOF when end_trigger != NULL,
    26103525     * that is, we were really supposed to get end_trigger, and never got
    26113526     * one before the EOF.  Can't use the standard "syntax error" return code,
    26123527     * so that parse_stream_outer can distinguish the EOF and exit smoothly. */
    2613     debug_printf("leaving parse_stream (EOF)\n");
    2614     if (end_trigger != '\0') return -1;
     3528    debug_printf_parse("parse_stream return %d\n", -(end_trigger != NULL));
     3529    if (end_trigger)
     3530        return -1;
    26153531    return 0;
    26163532}
    26173533
    2618 static void mapset(const char *set, int code)
    2619 {
    2620     const unsigned char *s;
    2621     for (s = (const unsigned char *)set; *s; s++) map[(int)*s] = code;
    2622 }
    2623 
    2624 static void update_ifs_map(void)
    2625 {
    2626     /* char *ifs and char map[256] are both globals. */
     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. */
    26273543    ifs = getenv("IFS");
    2628     if (ifs == NULL) ifs=" \t\n";
     3544    if (ifs == NULL)
     3545        ifs = " \t\n";
    26293546    /* Precompute a list of 'flow through' behavior so it can be treated
    26303547     * quickly up front.  Computation is necessary because of IFS.
    26313548     * Special case handling of IFS == " \t\n" is not implemented.
    2632      * The map[] array only really needs two bits each, and on most machines
    2633      * that would be faster because of the reduced L1 cache footprint.
     3549     * The charmap[] array only really needs two bits each,
     3550     * and on most machines that would be faster (reduced L1 cache use).
    26343551     */
    2635     memset(map,0,sizeof(map)); /* most characters flow through always */
    2636     mapset("\\$'\"`", 3);      /* never flow through */
    2637     mapset("<>;&|(){}#", 1);   /* flow through if quoted */
    2638     mapset(ifs, 2);            /* also flow through if quoted */
     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 */
    26393560}
    26403561
    26413562/* most recursion does not come through here, the exception is
    2642  * from builtin_source() */
    2643 int parse_stream_outer(struct in_str *inp, int flag)
    2644 {
    2645 
     3563 * from builtin_source() and builtin_eval() */
     3564static int parse_and_run_stream(struct in_str *inp, int parse_flag)
     3565{
    26463566    struct p_context ctx;
    2647     o_string temp=NULL_O_STRING;
     3567    o_string temp = NULL_O_STRING;
    26483568    int rcode;
    26493569    do {
    2650         ctx.type = flag;
     3570        ctx.parse_type = parse_flag;
    26513571        initialize_context(&ctx);
    2652         update_ifs_map();
    2653         if (!(flag & FLAG_PARSE_SEMICOLON) || (flag & FLAG_REPARSING)) mapset(";$&|", 0);
    2654         inp->promptmode=1;
    2655         rcode = parse_stream(&temp, &ctx, inp, '\n');
     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");
    26563582        if (rcode != 1 && ctx.old_flag != 0) {
    2657             syntax();
     3583            syntax(NULL);
    26583584        }
    26593585        if (rcode != 1 && ctx.old_flag == 0) {
    26603586            done_word(&temp, &ctx);
    2661             done_pipe(&ctx,PIPE_SEQ);
     3587            done_pipe(&ctx, PIPE_SEQ);
     3588            debug_print_tree(ctx.list_head, 0);
     3589            debug_printf_exec("parse_stream_outer: run_list\n");
    26623590            run_list(ctx.list_head);
    26633591        } else {
     
    26693597            temp.quote = 0;
    26703598            inp->p = NULL;
    2671             free_pipe_list(ctx.list_head,0);
     3599            free_pipe_list(ctx.list_head, 0);
    26723600        }
    26733601        b_free(&temp);
    2674     } while (rcode != -1 && !(flag & FLAG_EXIT_FROM_LOOP));   /* loop on syntax errors, return on EOF */
     3602    } while (rcode != -1 && !(parse_flag & PARSEFLAG_EXIT_FROM_LOOP));   /* loop on syntax errors, return on EOF */
    26753603    return 0;
    26763604}
    26773605
    2678 static int parse_string_outer(const char *s, int flag)
     3606static int parse_and_run_string(const char *s, int parse_flag)
    26793607{
    26803608    struct in_str input;
    26813609    setup_string_in_str(&input, s);
    2682     return parse_stream_outer(&input, flag);
    2683 }
    2684 
    2685 static int parse_file_outer(FILE *f)
     3610    return parse_and_run_stream(&input, parse_flag);
     3611}
     3612
     3613static int parse_and_run_file(FILE *f)
    26863614{
    26873615    int rcode;
    26883616    struct in_str input;
    26893617    setup_file_in_str(&input, f);
    2690     rcode = parse_stream_outer(&input, FLAG_PARSE_SEMICOLON);
     3618    rcode = parse_and_run_stream(&input, PARSEFLAG_SEMICOLON);
    26913619    return rcode;
    26923620}
    26933621
     3622#if ENABLE_HUSH_JOB
    26943623/* Make sure we have a controlling tty.  If we get started under a job
    26953624 * aware app (like bash for example), make sure we are now in charge so
     
    26973626static void setup_job_control(void)
    26983627{
    2699     static pid_t shell_pgrp;
    2700     /* Loop until we are in the foreground.  */
    2701     while (tcgetpgrp (shell_terminal) != (shell_pgrp = getpgrp ()))
    2702         kill (- shell_pgrp, SIGTTIN);
    2703 
    2704     /* Ignore interactive and job-control signals.  */
    2705     signal(SIGINT, SIG_IGN);
    2706     signal(SIGQUIT, SIG_IGN);
    2707     signal(SIGTERM, SIG_IGN);
    2708     signal(SIGTSTP, SIG_IGN);
    2709     signal(SIGTTIN, SIG_IGN);
    2710     signal(SIGTTOU, SIG_IGN);
    2711     signal(SIGCHLD, SIG_IGN);
     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);
    27123649
    27133650    /* Put ourselves in our own process group.  */
    2714     setsid();
    2715     shell_pgrp = getpid ();
    2716     setpgid (shell_pgrp, shell_pgrp);
    2717 
     3651    setpgrp(); /* is the same as setpgid(our_pid, our_pid); */
    27183652    /* Grab control of the terminal.  */
    2719     tcsetpgrp(shell_terminal, shell_pgrp);
    2720 }
    2721 
     3653    tcsetpgrp(interactive_fd, getpid());
     3654}
     3655#endif
     3656
     3657int hush_main(int argc, char **argv);
    27223658int hush_main(int argc, char **argv)
    27233659{
     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
    27243669    int opt;
    27253670    FILE *input;
    2726     char **e = environ;
    2727 
     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
    27283700    /* XXX what should these be while sourcing /etc/profile? */
    27293701    global_argc = argc;
    27303702    global_argv = argv;
    2731 
    2732     /* (re?) initialize globals.  Sometimes hush_main() ends up calling
    2733      * hush_main(), therefore we cannot rely on the BSS to zero out this
    2734      * stuff.  Reset these to 0 every time. */
    2735     ifs = NULL;
    2736     /* map[] is taken care of with call to update_ifs_map() */
    2737     fake_mode = 0;
    2738     interactive = 0;
    2739     close_me_head = NULL;
    2740     last_bg_pid = 0;
    2741     job_list = NULL;
    2742     last_jobid = 0;
    2743 
    27443703    /* Initialize some more globals to non-zero values */
    27453704    set_cwd();
    2746 #ifdef CONFIG_FEATURE_COMMAND_EDITING
     3705#if ENABLE_HUSH_INTERACTIVE
     3706#if ENABLE_FEATURE_EDITING
    27473707    cmdedit_set_initial_prompt();
    2748 #else
    2749     PS1 = NULL;
    27503708#endif
    27513709    PS2 = "> ";
    2752 
    2753     /* initialize our shell local variables with the values
    2754      * currently living in the environment */
    2755     if (e) {
    2756         for (; *e; e++)
    2757             set_local_var(*e, 2);   /* without call putenv() */
    2758     }
    2759 
    2760     last_return_code=EXIT_SUCCESS;
    2761 
     3710#endif
     3711
     3712    if (EXIT_SUCCESS) /* otherwise is already done */
     3713        last_return_code = EXIT_SUCCESS;
    27623714
    27633715    if (argv[0] && argv[0][0] == '-') {
    2764         debug_printf("\nsourcing /etc/profile\n");
    2765         if ((input = fopen("/etc/profile", "r")) != NULL) {
     3716        debug_printf("sourcing /etc/profile\n");
     3717        input = fopen("/etc/profile", "r");
     3718        if (input != NULL) {
    27663719            mark_open(fileno(input));
    2767             parse_file_outer(input);
     3720            parse_and_run_file(input);
    27683721            mark_closed(fileno(input));
    27693722            fclose(input);
    27703723        }
    27713724    }
    2772     input=stdin;
     3725    input = stdin;
    27733726
    27743727    while ((opt = getopt(argc, argv, "c:xif")) > 0) {
    27753728        switch (opt) {
    2776             case 'c':
    2777                 {
    2778                     global_argv = argv+optind;
    2779                     global_argc = argc-optind;
    2780                     opt = parse_string_outer(optarg, FLAG_PARSE_SEMICOLON);
    2781                     goto final_return;
    2782                 }
    2783                 break;
    2784             case 'i':
    2785                 interactive++;
    2786                 break;
    2787             case 'f':
    2788                 fake_mode++;
    2789                 break;
    2790             default:
     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:
    27913743#ifndef BB_VER
    2792                 fprintf(stderr, "Usage: sh [FILE]...\n"
    2793                         "   or: sh -c command [args]...\n\n");
    2794                 exit(EXIT_FAILURE);
     3744            fprintf(stderr, "Usage: sh [FILE]...\n"
     3745                    "   or: sh -c command [args]...\n\n");
     3746            exit(EXIT_FAILURE);
    27953747#else
    2796                 bb_show_usage();
    2797 #endif
    2798         }
    2799     }
    2800     /* A shell is interactive if the `-i' flag was given, or if all of
     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
    28013754     * the following conditions are met:
    2802      *    no -c command
     3755     *    no -c command
    28033756     *    no arguments remaining or the -s flag given
    28043757     *    standard input is a terminal
    28053758     *    standard output is a terminal
    2806      *    Refer to Posix.2, the description of the `sh' utility. */
    2807     if (argv[optind]==NULL && input==stdin &&
    2808             isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) {
    2809         interactive++;
    2810     }
    2811 
    2812     debug_printf("\ninteractive=%d\n", interactive);
    2813     if (interactive) {
     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) {
    28143781        /* Looks like they want an interactive shell */
    2815 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
    2816         printf( "\n\n%s hush - the humble shell v0.01 (testing)\n",
    2817             BB_BANNER);
    2818         printf( "Enter 'help' for a list of built-in commands.\n\n");
    2819 #endif
    28203782        setup_job_control();
    2821     }
    2822 
    2823     if (argv[optind]==NULL) {
    2824         opt=parse_file_outer(stdin);
     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);
    28253814        goto final_return;
    28263815    }
    28273816
    28283817    debug_printf("\nrunning script '%s'\n", argv[optind]);
    2829     global_argv = argv+optind;
    2830     global_argc = argc-optind;
    2831     input = bb_xfopen(argv[optind], "r");
    2832     opt = parse_file_outer(input);
    2833 
    2834 #ifdef CONFIG_FEATURE_CLEAN_UP
     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
    28353826    fclose(input);
    2836     if (cwd && cwd != bb_msg_unknown)
     3827    if (cwd != bb_msg_unknown)
    28373828        free((char*)cwd);
    2838     {
    2839         struct variables *cur, *tmp;
    2840         for(cur = top_vars; cur; cur = tmp) {
    2841             tmp = cur->next;
    2842             if (!cur->flg_read_only) {
    2843                 free(cur->name);
    2844                 free(cur->value);
    2845                 free(cur);
    2846             }
    2847         }
    2848     }
    2849 #endif
    2850 
    2851 final_return:
    2852     return(opt?opt:last_return_code);
    2853 }
    2854 
    2855 static char *insert_var_value(char *inp)
    2856 {
    2857     int res_str_len = 0;
    2858     int len;
    2859     int done = 0;
    2860     char *p, *p1, *res_str = NULL;
    2861 
    2862     while ((p = strchr(inp, SPECIAL_VAR_SYMBOL))) {
    2863         if (p != inp) {
    2864             len = p - inp;
    2865             res_str = xrealloc(res_str, (res_str_len + len));
    2866             strncpy((res_str + res_str_len), inp, len);
    2867             res_str_len += len;
    2868         }
    2869         inp = ++p;
    2870         p = strchr(inp, SPECIAL_VAR_SYMBOL);
    2871         *p = '\0';
    2872         if ((p1 = lookup_param(inp))) {
    2873             len = res_str_len + strlen(p1);
    2874             res_str = xrealloc(res_str, (1 + len));
    2875             strcpy((res_str + res_str_len), p1);
    2876             res_str_len = len;
    2877         }
    2878         *p = SPECIAL_VAR_SYMBOL;
    2879         inp = ++p;
    2880         done = 1;
    2881     }
    2882     if (done) {
    2883         res_str = xrealloc(res_str, (1 + res_str_len + strlen(inp)));
    2884         strcpy((res_str + res_str_len), inp);
    2885         while ((p = strchr(res_str, '\n'))) {
    2886             *p = ' ';
    2887         }
    2888     }
    2889     return (res_str == NULL) ? inp : res_str;
    2890 }
    2891 
    2892 static char **make_list_in(char **inp, char *name)
    2893 {
    2894     int len, i;
    2895     int name_len = strlen(name);
    2896     int n = 0;
    2897     char **list;
    2898     char *p1, *p2, *p3;
    2899 
    2900     /* create list of variable values */
    2901     list = xmalloc(sizeof(*list));
    2902     for (i = 0; inp[i]; i++) {
    2903         p3 = insert_var_value(inp[i]);
    2904         p1 = p3;
    2905         while (*p1) {
    2906             if ((*p1 == ' ')) {
    2907                 p1++;
    2908                 continue;
    2909             }
    2910             if ((p2 = strchr(p1, ' '))) {
    2911                 len = p2 - p1;
    2912             } else {
    2913                 len = strlen(p1);
    2914                 p2 = p1 + len;
    2915             }
    2916             /* we use n + 2 in realloc for list,because we add
    2917              * new element and then we will add NULL element */
    2918             list = xrealloc(list, sizeof(*list) * (n + 2));
    2919             list[n] = xmalloc(2 + name_len + len);
    2920             strcpy(list[n], name);
    2921             strcat(list[n], "=");
    2922             strncat(list[n], p1, len);
    2923             list[n++][name_len + len + 1] = '\0';
    2924             p1 = p2;
    2925         }
    2926         if (p3 != inp[i]) free(p3);
    2927     }
    2928     list[n] = NULL;
    2929     return list;
    2930 }
    2931 
    2932 /* Make new string for parser */
    2933 static char * make_string(char ** inp)
    2934 {
    2935     char *p;
    2936     char *str = NULL;
    2937     int n;
    2938     int len = 2;
    2939 
    2940     for (n = 0; inp[n]; n++) {
    2941         p = insert_var_value(inp[n]);
    2942         str = xrealloc(str, (len + strlen(p)));
    2943         if (n) {
    2944             strcat(str, " ");
    2945         } else {
    2946             *str = '\0';
    2947         }
    2948         strcat(str, p);
    2949         len = strlen(str) + 3;
    2950         if (p != inp[n]) free(p);
    2951     }
    2952     len = strlen(str);
    2953     *(str + len) = '\n';
    2954     *(str + len + 1) = '\0';
    2955     return str;
    2956 }
     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 TracChangeset for help on using the changeset viewer.