Changeset 1765 in MondoRescue for branches/2.2.5/mindi-busybox/shell


Ignore:
Timestamp:
Nov 4, 2007, 3:16:40 AM (16 years ago)
Author:
Bruno Cornec
Message:

Update to busybox 1.7.2

Location:
branches/2.2.5/mindi-busybox/shell
Files:
72 added
4 deleted
5 edited

Legend:

Unmodified
Added
Removed
  • branches/2.2.5/mindi-busybox/shell/Config.in

    r821 r1765  
    88choice
    99    prompt "Choose your default shell"
    10     default CONFIG_FEATURE_SH_IS_NONE
     10    default FEATURE_SH_IS_NONE
    1111    help
    1212      Choose a shell. The ash shell is the most bash compatible
    1313      and full featured one.
    1414
    15 config CONFIG_FEATURE_SH_IS_ASH
    16     select CONFIG_ASH
     15config FEATURE_SH_IS_ASH
     16    select ASH
    1717    bool "ash"
    1818
    19 config CONFIG_FEATURE_SH_IS_HUSH
    20     select CONFIG_HUSH
     19config FEATURE_SH_IS_HUSH
     20    select HUSH
    2121    bool "hush"
    2222
    23 config CONFIG_FEATURE_SH_IS_LASH
    24     select CONFIG_LASH
     23config FEATURE_SH_IS_LASH
     24    select LASH
    2525    bool "lash"
    2626
    27 config CONFIG_FEATURE_SH_IS_MSH
    28     select CONFIG_MSH
     27config FEATURE_SH_IS_MSH
     28    select MSH
    2929    bool "msh"
    3030
    31 config CONFIG_FEATURE_SH_IS_NONE
     31config FEATURE_SH_IS_NONE
    3232    bool "none"
    3333
    3434endchoice
    3535
    36 config CONFIG_ASH
     36config ASH
    3737    bool "ash"
    3838    default n
    39     select CONFIG_TEST
     39    select TEST
    4040    help
    4141      Tha 'ash' shell adds about 60k in the default configuration and is
     
    4646
    4747comment "Ash Shell Options"
    48     depends on CONFIG_ASH
    49 
    50 config CONFIG_ASH_JOB_CONTROL
     48    depends on ASH
     49
     50config ASH_JOB_CONTROL
    5151    bool "Job control"
    5252    default y
    53     depends on CONFIG_ASH
     53    depends on ASH
    5454    help
    5555      Enable job control in the ash shell.
    5656
    57 config CONFIG_ASH_READ_NCHARS
     57config ASH_READ_NCHARS
    5858    bool "'read -n N' and 'read -s' support"
    5959    default n
    60     depends on CONFIG_ASH
     60    depends on ASH
    6161    help
    6262      'read -n N' will return a value after N characters have been read.
    6363      'read -s' will read without echoing the user's input.
    6464
    65 config CONFIG_ASH_READ_TIMEOUT
     65config ASH_READ_TIMEOUT
    6666    bool "'read -t S' support."
    6767    default n
    68     depends on CONFIG_ASH
     68    depends on ASH
    6969    help
    7070      'read -t S' will return a value after S seconds have passed.
     
    7272      as a decimal fraction, e.g. 'read -t 2.5 foo'.
    7373
    74 config CONFIG_ASH_ALIAS
     74config ASH_ALIAS
    7575    bool "alias support"
    7676    default y
    77     depends on CONFIG_ASH
     77    depends on ASH
    7878    help
    7979      Enable alias support in the ash shell.
    8080
    81 config CONFIG_ASH_MATH_SUPPORT
     81config ASH_MATH_SUPPORT
    8282    bool "Posix math support"
    8383    default y
    84     depends on CONFIG_ASH
     84    depends on ASH
    8585    help
    8686      Enable math support in the ash shell.
    8787
    88 config CONFIG_ASH_MATH_SUPPORT_64
     88config ASH_MATH_SUPPORT_64
    8989    bool "Extend Posix math support to 64 bit"
    9090    default n
    91     depends on CONFIG_ASH_MATH_SUPPORT
     91    depends on ASH_MATH_SUPPORT
    9292    help
    9393      Enable 64-bit math support in the ash shell.  This will make
     
    9595      large numbers.
    9696
    97 config CONFIG_ASH_GETOPTS
     97config ASH_GETOPTS
    9898    bool "Builtin getopt to parse positional parameters"
    9999    default n
    100     depends on CONFIG_ASH
     100    depends on ASH
    101101    help
    102102      Enable getopts builtin in the ash shell.
    103103
    104 config CONFIG_ASH_BUILTIN_ECHO
     104config ASH_BUILTIN_ECHO
    105105    bool "Builtin version of 'echo'"
    106106    default y
    107     select CONFIG_ECHO
    108     depends on CONFIG_ASH
    109     help
    110       Enable support for echo, built in to ash.
    111 
    112 config CONFIG_ASH_BUILTIN_TEST
     107    select ECHO
     108    depends on ASH
     109    help
     110      Enable support for echo, builtin to ash.
     111
     112config ASH_BUILTIN_TEST
    113113    bool "Builtin version of 'test'"
    114114    default y
    115     select CONFIG_TEST
    116     depends on CONFIG_ASH
    117     help
    118       Enable support for test, built in to ash.
    119 
    120 config CONFIG_ASH_CMDCMD
     115    select TEST
     116    depends on ASH
     117    help
     118      Enable support for test, builtin to ash.
     119
     120config ASH_CMDCMD
    121121    bool "'command' command to override shell builtins"
    122122    default n
    123     depends on CONFIG_ASH
     123    depends on ASH
    124124    help
    125125      Enable support for the ash 'command' builtin, which allows
     
    127127      even when there is an ash builtin command with the same name.
    128128
    129 config CONFIG_ASH_MAIL
     129config ASH_MAIL
    130130    bool "Check for new mail on interactive shells"
    131131    default y
    132     depends on CONFIG_ASH
     132    depends on ASH
    133133    help
    134134      Enable "check for new mail" in the ash shell.
    135135
    136 config CONFIG_ASH_OPTIMIZE_FOR_SIZE
     136config ASH_OPTIMIZE_FOR_SIZE
    137137    bool "Optimize for size instead of speed"
    138138    default y
    139     depends on CONFIG_ASH
     139    depends on ASH
    140140    help
    141141      Compile ash for reduced size at the price of speed.
    142142
    143 config CONFIG_ASH_RANDOM_SUPPORT
     143config ASH_RANDOM_SUPPORT
    144144    bool "Pseudorandom generator and variable $RANDOM"
    145145    default n
    146     depends on CONFIG_ASH
     146    depends on ASH
    147147    help
    148148      Enable pseudorandom generator and dynamic variable "$RANDOM".
     
    152152      variable will no longer have special treatment.
    153153
    154 config CONFIG_ASH_EXPAND_PRMT
     154config ASH_EXPAND_PRMT
    155155    bool "Expand prompt string"
    156156    default n
    157     depends on CONFIG_ASH
     157    depends on ASH
    158158    help
    159159      "PS#" may be contain volatile content, such as backquote commands.
     
    161161      variable each time it is displayed.
    162162
    163 config CONFIG_HUSH
     163config HUSH
    164164    bool "hush"
    165165    default n
    166     select CONFIG_TRUE
    167     select CONFIG_FALSE
    168     select CONFIG_TEST
     166    select TRUE
     167    select FALSE
     168    select TEST
    169169    help
    170170      hush is a very small shell (just 18k) and it has fairly complete
     
    177177      expansion, &> and >& redirection of stdout+stderr, etc.
    178178
    179 
    180 config CONFIG_LASH
     179config HUSH_HELP
     180    bool "help builtin"
     181    default n
     182    depends on HUSH
     183    help
     184      Enable help builtin in hush. Code size + ~1 kbyte.
     185
     186config HUSH_INTERACTIVE
     187    bool "Interactive mode"
     188    default y
     189    depends on HUSH
     190    help
     191      Enable interactive mode (prompt and command editing).
     192      Without this, hush simply reads and executes commands
     193      from stdin just like a shell script from the file.
     194      No prompt, no PS1/PS2 magic shell variables.
     195
     196config HUSH_JOB
     197    bool "Job control"
     198    default n
     199    depends on HUSH_INTERACTIVE
     200    help
     201      Enable job control: Ctrl-Z backgrounds, Ctrl-C interrupts current
     202      command (not entire shell), fg/bg builtins work. Without this option,
     203      "cmd &" still works by simply spawning a process and immediately
     204      prompting for next command (or executing next command in a script),
     205      but no separate process group is formed.
     206
     207config HUSH_TICK
     208    bool "Process substitution"
     209    default n
     210    depends on HUSH
     211    help
     212      Enable process substitution `command` and $(command) in hush.
     213
     214config HUSH_IF
     215    bool "Support if/then/elif/else/fi"
     216    default n
     217    depends on HUSH
     218    help
     219      Enable if/then/elif/else/fi in hush.
     220
     221config HUSH_LOOPS
     222    bool "Support for, while and until loops"
     223    default n
     224    depends on HUSH
     225    help
     226      Enable for, while and until loops in hush.
     227
     228config LASH
    181229    bool "lash"
    182230    default n
    183     select CONFIG_TRUE
    184     select CONFIG_FALSE
    185     select CONFIG_TEST
     231    select TRUE
     232    select FALSE
     233    select TEST
    186234    help
    187235      lash is the very smallest shell (adds just 10k) and it is quite
     
    193241
    194242
    195 config CONFIG_MSH
     243config MSH
    196244    bool "msh"
    197245    default n
    198     select CONFIG_TRUE
    199     select CONFIG_FALSE
    200     select CONFIG_TEST
     246    select TRUE
     247    select FALSE
     248    select TEST
    201249    help
    202250      The minix shell (adds just 30k) is quite complete and handles things
     
    208256
    209257comment "Bourne Shell Options"
    210     depends on CONFIG_MSH || CONFIG_LASH || CONFIG_HUSH || CONFIG_ASH
    211 
    212 config CONFIG_FEATURE_SH_EXTRA_QUIET
     258    depends on MSH || LASH || HUSH || ASH
     259
     260config FEATURE_SH_EXTRA_QUIET
    213261    bool "Hide message on interactive shell startup"
    214262    default n
    215     depends on CONFIG_MSH || CONFIG_LASH || CONFIG_HUSH || CONFIG_ASH
     263    depends on MSH || LASH || HUSH || ASH
    216264    help
    217265      Remove the busybox introduction when starting a shell.
    218266
    219 config CONFIG_FEATURE_SH_STANDALONE_SHELL
     267config FEATURE_SH_STANDALONE
    220268    bool "Standalone shell"
    221269    default n
    222     depends on CONFIG_MSH || CONFIG_LASH || CONFIG_HUSH || CONFIG_ASH
    223     help
    224       This option causes the selected busybox shell to use busybox applets
     270    depends on (MSH || LASH || HUSH || ASH) && FEATURE_PREFER_APPLETS
     271    help
     272      This option causes busybox shells to use busybox applets
    225273      in preference to executables in the PATH whenever possible.  For
    226274      example, entering the command 'ifconfig' into the shell would cause
     
    231279      for use as a rescue shell, in the event that you screw up your system.
    232280
    233       Note that this will *also* cause applets to take precedence
    234       over shell builtins of the same name.  So turning this on will
    235       eliminate any performance gained by turning on the builtin "echo"
    236       and "test" commands in ash.
    237 
    238       Note that when using this option, the shell will attempt to directly
    239       run '/bin/busybox'.  If you do not have the busybox binary sitting in
    240       that exact location with that exact name, this option will not work at
    241       all.
    242 
    243 config CONFIG_FEATURE_COMMAND_EDITING
    244     bool "Command line editing"
    245     default n
    246     depends on CONFIG_MSH || CONFIG_LASH || CONFIG_HUSH || CONFIG_ASH
    247     help
    248       Enable command editing in shell.
    249 
    250 config CONFIG_FEATURE_COMMAND_EDITING_VI
    251     bool "vi-style line editing commands"
    252     default n
    253     depends on CONFIG_FEATURE_COMMAND_EDITING
    254     help
    255       Enable vi-style line editing in the shell.  This mode can be
    256       turned on and off with "set -o vi" and "set +o vi".
    257 
    258 config CONFIG_FEATURE_COMMAND_HISTORY
    259     int "History size"
    260     default 15
    261     depends on CONFIG_FEATURE_COMMAND_EDITING
    262     help
    263       Specify command history size in shell.
    264 
    265 config CONFIG_FEATURE_COMMAND_SAVEHISTORY
    266     bool "History saving"
    267     default n
    268     depends on CONFIG_ASH && CONFIG_FEATURE_COMMAND_EDITING
    269     help
    270       Enable history saving in ash shell.
    271 
    272 config CONFIG_FEATURE_COMMAND_TAB_COMPLETION
    273     bool "Tab completion"
    274     default n
    275     depends on CONFIG_FEATURE_COMMAND_EDITING
    276     help
    277       Enable tab completion in shell.
    278 
    279 config CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION
    280     bool "Username completion"
    281     default n
    282     depends on CONFIG_FEATURE_COMMAND_TAB_COMPLETION
    283     help
    284       Enable username completion in shell.
    285 
    286 config CONFIG_FEATURE_SH_FANCY_PROMPT
    287     bool "Fancy shell prompts"
    288     default n
    289     depends on CONFIG_FEATURE_COMMAND_EDITING
    290     help
    291       Setting this option allows for prompts to use things like \w and
    292       \$ and also using escape codes.
     281      This is implemented by re-execing /proc/self/exe (typically)
     282      with right parameters. Some selected applets ("NOFORK" applets)
     283      can even be executed without creating new process.
     284      Instead, busybox will call <applet>_main() internally.
     285
     286      However, this causes problems in chroot jails without mounted /proc
     287      and with ps/top (command name can be shown as 'exe' for applets
     288      started this way).
     289# untrue?
     290#     Note that this will *also* cause applets to take precedence
     291#     over shell builtins of the same name.  So turning this on will
     292#     eliminate any performance gained by turning on the builtin "echo"
     293#     and "test" commands in ash.
     294# untrue?
     295#     Note that when using this option, the shell will attempt to directly
     296#     run '/bin/busybox'.  If you do not have the busybox binary sitting in
     297#     that exact location with that exact name, this option will not work at
     298#     all.
     299
     300config CTTYHACK
     301    bool "cttyhack"
     302    default n
     303    help
     304      One common problem reported on the mailing list is "can't access tty;
     305      job control turned off" error message which typically appears when
     306      one tries to use shell with stdin/stdout opened to /dev/console.
     307      This device is special - it cannot be a controlling tty.
     308
     309      Proper solution is to use correct device instead of /dev/console.
     310
     311      cttyhack provides "quick and dirty" solution to this problem.
     312      It analyzes stdin with various ioctls, trying to determine whether
     313      it is a /dev/ttyN or /dev/ttySN (virtual terminal or serial line).
     314      If it detects one, it closes stdin/out/err and reopens that device.
     315      Then it executes given program. Usage example for /etc/inittab
     316      (for busybox init):
     317
     318      ::respawn:/bin/cttyhack /bin/sh
    293319
    294320endmenu
  • branches/2.2.5/mindi-busybox/shell/ash.c

    r821 r1765  
    3232 */
    3333
    34 
    3534/*
    3635 * The follow should be set to reflect the type of system you have:
     
    4342 * a quit signal will generate a core dump.
    4443 */
    45 
    46 
     44#define DEBUG 0
    4745#define IFS_BROKEN
    48 
    4946#define PROFILE 0
    50 
    51 #include "busybox.h"
    52 
    53 #ifdef DEBUG
     47#if ENABLE_ASH_JOB_CONTROL
     48#define JOBS 1
     49#else
     50#define JOBS 0
     51#endif
     52
     53#if DEBUG
    5454#define _GNU_SOURCE
    5555#endif
    56 
    57 #include <sys/types.h>
    58 #include <sys/ioctl.h>
    59 #include <sys/param.h>
    60 #include <sys/resource.h>
    61 #include <sys/stat.h>
    62 #include <sys/wait.h>
    63 
    64 #include <stdio.h>
    65 #include <stdlib.h>
    66 #include <string.h>
    67 #include <unistd.h>
    68 
    69 #include <stdarg.h>
    70 #include <stddef.h>
    71 #include <assert.h>
    72 #include <ctype.h>
    73 #include <dirent.h>
    74 #include <errno.h>
    75 #include <fcntl.h>
    76 #include <limits.h>
     56#include "busybox.h" /* for struct bb_applet */
    7757#include <paths.h>
    7858#include <setjmp.h>
    79 #include <signal.h>
    80 /*#include <stdint.h>*/
    81 #include <time.h>
    8259#include <fnmatch.h>
    83 
    84 #include "pwd_.h"
    85 
    86 #ifdef CONFIG_ASH_JOB_CONTROL
    87 #define JOBS 1
    88 #else
    89 #undef JOBS
    90 #endif
    91 
    92 #if JOBS || defined(CONFIG_ASH_READ_NCHARS)
     60#if JOBS || ENABLE_ASH_READ_NCHARS
    9361#include <termios.h>
    9462#endif
    95 
    96 #include "cmdedit.h"
    97 
    98 #ifdef __GLIBC__
    99 /* glibc sucks */
    100 static int *dash_errno;
    101 #undef errno
    102 #define errno (*dash_errno)
    103 #endif
     63extern char **environ;
    10464
    10565#if defined(__uClinux__)
     
    10767#endif
    10868
    109 #ifdef DEBUG
    110 #define _DIAGASSERT(assert_expr) assert(assert_expr)
    111 #else
    112 #define _DIAGASSERT(assert_expr)
    113 #endif
    114 
    115 
    116 #ifdef CONFIG_ASH_ALIAS
    117 /*      alias.h       */
    118 
    119 #define ALIASINUSE      1
    120 #define ALIASDEAD       2
    121 
    122 struct alias {
    123     struct alias *next;
    124     char *name;
    125     char *val;
    126     int flag;
     69
     70/* ============ Misc helpers */
     71
     72#define xbarrier() do { __asm__ __volatile__ ("": : :"memory"); } while (0)
     73
     74/* C99 say: "char" declaration may be signed or unsigned default */
     75#define signed_char2int(sc) ((int)((signed char)sc))
     76
     77
     78/* ============ Shell options */
     79
     80static const char *const optletters_optnames[] = {
     81    "e"   "errexit",
     82    "f"   "noglob",
     83    "I"   "ignoreeof",
     84    "i"   "interactive",
     85    "m"   "monitor",
     86    "n"   "noexec",
     87    "s"   "stdin",
     88    "x"   "xtrace",
     89    "v"   "verbose",
     90    "C"   "noclobber",
     91    "a"   "allexport",
     92    "b"   "notify",
     93    "u"   "nounset",
     94    "\0"  "vi"
     95#if DEBUG
     96    ,"\0"  "nolog"
     97    ,"\0"  "debug"
     98#endif
    12799};
    128100
    129 static struct alias *lookupalias(const char *, int);
    130 static int aliascmd(int, char **);
    131 static int unaliascmd(int, char **);
    132 static void rmaliases(void);
    133 static int unalias(const char *);
    134 static void printalias(const struct alias *);
    135 #endif
    136 
    137 /*      cd.h  */
    138 
    139 
    140 static void    setpwd(const char *, int);
    141 
    142 /*      error.h      */
    143 
    144 
    145 /*
    146  * Types of operations (passed to the errmsg routine).
    147  */
    148 
    149 
    150 static const char not_found_msg[] = "%s: not found";
    151 
    152 
    153 #define E_OPEN  "No such file"          /* opening a file */
    154 #define E_CREAT "Directory nonexistent" /* creating a file */
    155 #define E_EXEC  not_found_msg+4         /* executing a program */
     101#define optletters(n) optletters_optnames[(n)][0]
     102#define optnames(n) (&optletters_optnames[(n)][1])
     103
     104enum { NOPTS = ARRAY_SIZE(optletters_optnames) };
     105
     106static char optlist[NOPTS] ALIGN1;
     107
     108#define eflag optlist[0]
     109#define fflag optlist[1]
     110#define Iflag optlist[2]
     111#define iflag optlist[3]
     112#define mflag optlist[4]
     113#define nflag optlist[5]
     114#define sflag optlist[6]
     115#define xflag optlist[7]
     116#define vflag optlist[8]
     117#define Cflag optlist[9]
     118#define aflag optlist[10]
     119#define bflag optlist[11]
     120#define uflag optlist[12]
     121#define viflag optlist[13]
     122#if DEBUG
     123#define nolog optlist[14]
     124#define debug optlist[15]
     125#endif
     126
     127
     128/* ============ Misc data */
     129
     130static char nullstr[1] ALIGN1;  /* zero length string */
     131static const char homestr[] ALIGN1 = "HOME";
     132static const char snlfmt[] ALIGN1 = "%s\n";
     133static const char illnum[] ALIGN1 = "Illegal number: %s";
     134
     135static char *minusc;  /* argument to -c option */
     136
     137/* pid of main shell */
     138static int rootpid;
     139/* shell level: 0 for the main shell, 1 for its children, and so on */
     140static int shlvl;
     141#define rootshell (!shlvl)
     142/* trap handler commands */
     143static char *trap[NSIG];
     144static smallint isloginsh;
     145/* current value of signal */
     146static char sigmode[NSIG - 1];
     147/* indicates specified signal received */
     148static char gotsig[NSIG - 1];
     149static char *arg0; /* value of $0 */
     150
     151
     152/* ============ Interrupts / exceptions */
    156153
    157154/*
     
    164161 * inner scope, and restore handler on exit from the scope.
    165162 */
    166 
    167163struct jmploc {
    168164    jmp_buf loc;
    169165};
    170 
    171 static struct jmploc *handler;
     166static struct jmploc *exception_handler;
    172167static int exception;
    173 static volatile int suppressint;
    174 static volatile sig_atomic_t intpending;
    175 
    176168/* exceptions */
    177169#define EXINT 0         /* SIGINT received */
     
    181173#define EXEXIT 4        /* exit the shell */
    182174#define EXSIG 5         /* trapped signal in wait(1) */
    183 
    184 
     175static volatile int suppressint;
     176static volatile sig_atomic_t intpending;
    185177/* do we generate EXSIG events */
    186178static int exsig;
    187179/* last pending signal */
    188 static volatile sig_atomic_t pendingsigs;
     180static volatile sig_atomic_t pendingsig;
     181
     182/*
     183 * Sigmode records the current value of the signal handlers for the various
     184 * modes.  A value of zero means that the current handler is not known.
     185 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
     186 */
     187
     188#define S_DFL 1                 /* default signal handling (SIG_DFL) */
     189#define S_CATCH 2               /* signal is caught */
     190#define S_IGN 3                 /* signal is ignored (SIG_IGN) */
     191#define S_HARD_IGN 4            /* signal is ignored permenantly */
     192#define S_RESET 5               /* temporary - to reset a hard ignored sig */
    189193
    190194/*
     
    194198 * more fun than worrying about efficiency and portability. :-))
    195199 */
    196 
    197 #define xbarrier() ({ __asm__ __volatile__ ("": : :"memory"); })
    198 #define INTOFF \
    199     ({ \
     200#define INT_OFF \
     201    do { \
    200202        suppressint++; \
    201203        xbarrier(); \
    202         0; \
    203     })
    204 #define SAVEINT(v) ((v) = suppressint)
    205 #define RESTOREINT(v) \
    206     ({ \
     204    } while (0)
     205
     206/*
     207 * Called to raise an exception.  Since C doesn't include exceptions, we
     208 * just do a longjmp to the exception handler.  The type of exception is
     209 * stored in the global variable "exception".
     210 */
     211static void raise_exception(int) ATTRIBUTE_NORETURN;
     212static void
     213raise_exception(int e)
     214{
     215#if DEBUG
     216    if (exception_handler == NULL)
     217        abort();
     218#endif
     219    INT_OFF;
     220    exception = e;
     221    longjmp(exception_handler->loc, 1);
     222}
     223
     224/*
     225 * Called from trap.c when a SIGINT is received.  (If the user specifies
     226 * that SIGINT is to be trapped or ignored using the trap builtin, then
     227 * this routine is not called.)  Suppressint is nonzero when interrupts
     228 * are held using the INT_OFF macro.  (The test for iflag is just
     229 * defensive programming.)
     230 */
     231static void raise_interrupt(void) ATTRIBUTE_NORETURN;
     232static void
     233raise_interrupt(void)
     234{
     235    int i;
     236    sigset_t mask;
     237
     238    intpending = 0;
     239    /* Signal is not automatically re-enabled after it is raised,
     240     * do it ourself */
     241    sigemptyset(&mask);
     242    sigprocmask(SIG_SETMASK, &mask, 0);
     243    /* pendingsig = 0; - now done in onsig() */
     244
     245    i = EXSIG;
     246    if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
     247        if (!(rootshell && iflag)) {
     248            signal(SIGINT, SIG_DFL);
     249            raise(SIGINT);
     250        }
     251        i = EXINT;
     252    }
     253    raise_exception(i);
     254    /* NOTREACHED */
     255}
     256
     257#if ENABLE_ASH_OPTIMIZE_FOR_SIZE
     258static void
     259int_on(void)
     260{
     261    if (--suppressint == 0 && intpending) {
     262        raise_interrupt();
     263    }
     264}
     265#define INT_ON int_on()
     266static void
     267force_int_on(void)
     268{
     269    suppressint = 0;
     270    if (intpending)
     271        raise_interrupt();
     272}
     273#define FORCE_INT_ON force_int_on()
     274#else
     275#define INT_ON \
     276    do { \
    207277        xbarrier(); \
    208         if ((suppressint = (v)) == 0 && intpending) onint(); \
    209         0; \
    210     })
    211 #define EXSIGON() \
    212     ({ \
     278        if (--suppressint == 0 && intpending) \
     279            raise_interrupt(); \
     280    } while (0)
     281#define FORCE_INT_ON \
     282    do { \
     283        xbarrier(); \
     284        suppressint = 0; \
     285        if (intpending) \
     286            raise_interrupt(); \
     287    } while (0)
     288#endif /* ASH_OPTIMIZE_FOR_SIZE */
     289
     290#define SAVE_INT(v) ((v) = suppressint)
     291
     292#define RESTORE_INT(v) \
     293    do { \
     294        xbarrier(); \
     295        suppressint = (v); \
     296        if (suppressint == 0 && intpending) \
     297            raise_interrupt(); \
     298    } while (0)
     299
     300#define EXSIGON \
     301    do { \
    213302        exsig++; \
    214303        xbarrier(); \
    215         if (pendingsigs) \
    216             exraise(EXSIG); \
    217         0; \
    218     })
     304        if (pendingsig) \
     305            raise_exception(EXSIG); \
     306    } while (0)
    219307/* EXSIG is turned off by evalbltin(). */
    220308
    221 
    222 static void exraise(int) ATTRIBUTE_NORETURN;
    223 static void onint(void) ATTRIBUTE_NORETURN;
    224 
    225 static void sh_error(const char *, ...) ATTRIBUTE_NORETURN;
    226 static void exerror(int, const char *, ...) ATTRIBUTE_NORETURN;
    227 
    228 static void sh_warnx(const char *, ...);
    229 
    230 #ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
    231 static void
    232 inton(void) {
    233     if (--suppressint == 0 && intpending) {
    234         onint();
    235     }
    236 }
    237 #define INTON inton()
    238 static void forceinton(void)
    239 {
    240     suppressint = 0;
    241     if (intpending)
    242         onint();
    243 }
    244 #define FORCEINTON forceinton()
    245 #else
    246 #define INTON \
    247     ({ \
    248         xbarrier(); \
    249         if (--suppressint == 0 && intpending) onint(); \
    250         0; \
    251     })
    252 #define FORCEINTON \
    253     ({ \
    254         xbarrier(); \
    255         suppressint = 0; \
    256         if (intpending) onint(); \
    257         0; \
    258     })
    259 #endif /* CONFIG_ASH_OPTIMIZE_FOR_SIZE */
    260 
    261 /*      expand.h     */
    262 
    263 struct strlist {
    264     struct strlist *next;
    265     char *text;
     309/*
     310 * Ignore a signal. Only one usage site - in forkchild()
     311 */
     312static void
     313ignoresig(int signo)
     314{
     315    if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
     316        signal(signo, SIG_IGN);
     317    }
     318    sigmode[signo - 1] = S_HARD_IGN;
     319}
     320
     321/*
     322 * Signal handler. Only one usage site - in setsignal()
     323 */
     324static void
     325onsig(int signo)
     326{
     327    gotsig[signo - 1] = 1;
     328    pendingsig = signo;
     329
     330    if (exsig || (signo == SIGINT && !trap[SIGINT])) {
     331        if (!suppressint) {
     332            pendingsig = 0;
     333            raise_interrupt();
     334        }
     335        intpending = 1;
     336    }
     337}
     338
     339
     340/* ============ Stdout/stderr output */
     341
     342static void
     343outstr(const char *p, FILE *file)
     344{
     345    INT_OFF;
     346    fputs(p, file);
     347    INT_ON;
     348}
     349
     350static void
     351flush_stdout_stderr(void)
     352{
     353    INT_OFF;
     354    fflush(stdout);
     355    fflush(stderr);
     356    INT_ON;
     357}
     358
     359static void
     360flush_stderr(void)
     361{
     362    INT_OFF;
     363    fflush(stderr);
     364    INT_ON;
     365}
     366
     367static void
     368outcslow(int c, FILE *dest)
     369{
     370    INT_OFF;
     371    putc(c, dest);
     372    fflush(dest);
     373    INT_ON;
     374}
     375
     376static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2)));
     377static int
     378out1fmt(const char *fmt, ...)
     379{
     380    va_list ap;
     381    int r;
     382
     383    INT_OFF;
     384    va_start(ap, fmt);
     385    r = vprintf(fmt, ap);
     386    va_end(ap);
     387    INT_ON;
     388    return r;
     389}
     390
     391static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4)));
     392static int
     393fmtstr(char *outbuf, size_t length, const char *fmt, ...)
     394{
     395    va_list ap;
     396    int ret;
     397
     398    va_start(ap, fmt);
     399    INT_OFF;
     400    ret = vsnprintf(outbuf, length, fmt, ap);
     401    va_end(ap);
     402    INT_ON;
     403    return ret;
     404}
     405
     406static void
     407out1str(const char *p)
     408{
     409    outstr(p, stdout);
     410}
     411
     412static void
     413out2str(const char *p)
     414{
     415    outstr(p, stderr);
     416    flush_stderr();
     417}
     418
     419
     420/* ============ Parser structures */
     421
     422/* control characters in argument strings */
     423#define CTLESC '\201'           /* escape next character */
     424#define CTLVAR '\202'           /* variable defn */
     425#define CTLENDVAR '\203'
     426#define CTLBACKQ '\204'
     427#define CTLQUOTE 01             /* ored with CTLBACKQ code if in quotes */
     428/*      CTLBACKQ | CTLQUOTE == '\205' */
     429#define CTLARI  '\206'          /* arithmetic expression */
     430#define CTLENDARI '\207'
     431#define CTLQUOTEMARK '\210'
     432
     433/* variable substitution byte (follows CTLVAR) */
     434#define VSTYPE  0x0f            /* type of variable substitution */
     435#define VSNUL   0x10            /* colon--treat the empty string as unset */
     436#define VSQUOTE 0x80            /* inside double quotes--suppress splitting */
     437
     438/* values of VSTYPE field */
     439#define VSNORMAL        0x1             /* normal variable:  $var or ${var} */
     440#define VSMINUS         0x2             /* ${var-text} */
     441#define VSPLUS          0x3             /* ${var+text} */
     442#define VSQUESTION      0x4             /* ${var?message} */
     443#define VSASSIGN        0x5             /* ${var=text} */
     444#define VSTRIMRIGHT     0x6             /* ${var%pattern} */
     445#define VSTRIMRIGHTMAX  0x7             /* ${var%%pattern} */
     446#define VSTRIMLEFT      0x8             /* ${var#pattern} */
     447#define VSTRIMLEFTMAX   0x9             /* ${var##pattern} */
     448#define VSLENGTH        0xa             /* ${#var} */
     449
     450static const char dolatstr[] ALIGN1 = {
     451    CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'
    266452};
    267 
    268 
    269 struct arglist {
    270     struct strlist *list;
    271     struct strlist **lastp;
    272 };
    273 
    274 /*
    275  * expandarg() flags
    276  */
    277 #define EXP_FULL        0x1     /* perform word splitting & file globbing */
    278 #define EXP_TILDE       0x2     /* do normal tilde expansion */
    279 #define EXP_VARTILDE    0x4     /* expand tildes in an assignment */
    280 #define EXP_REDIR       0x8     /* file glob for a redirection (1 match only) */
    281 #define EXP_CASE        0x10    /* keeps quotes around for CASE pattern */
    282 #define EXP_RECORD      0x20    /* need to record arguments for ifs breakup */
    283 #define EXP_VARTILDE2   0x40    /* expand tildes after colons only */
    284 #define EXP_WORD        0x80    /* expand word in parameter expansion */
    285 #define EXP_QWORD       0x100   /* expand word in quoted parameter expansion */
    286 
    287 
    288 union node;
    289 static void expandarg(union node *, struct arglist *, int);
    290 #define rmescapes(p) _rmescapes((p), 0)
    291 static char *_rmescapes(char *, int);
    292 static int casematch(union node *, char *);
    293 
    294 #ifdef CONFIG_ASH_MATH_SUPPORT
    295 static void expari(int);
    296 #endif
    297 
    298 /*      eval.h       */
    299 
    300 static char *commandname;              /* currently executing command */
    301 static struct strlist *cmdenviron;     /* environment for builtin command */
    302 static int exitstatus;                 /* exit status of last command */
    303 static int back_exitstatus;            /* exit status of backquoted command */
    304 
    305 
    306 struct backcmd {                /* result of evalbackcmd */
    307     int fd;                 /* file descriptor to read from */
    308     char *buf;              /* buffer */
    309     int nleft;              /* number of chars in buffer */
    310     struct job *jp;         /* job structure for command */
    311 };
    312 
    313 /*
    314  * This file was generated by the mknodes program.
    315  */
    316453
    317454#define NCMD 0
     
    342479#define NNOT 25
    343480
    344 
     481union node;
    345482
    346483struct ncmd {
    347       int type;
    348       union node *assign;
    349       union node *args;
    350       union node *redirect;
     484    int type;
     485    union node *assign;
     486    union node *args;
     487    union node *redirect;
    351488};
    352489
    353 
    354490struct npipe {
    355       int type;
    356       int backgnd;
    357       struct nodelist *cmdlist;
     491    int type;
     492    int backgnd;
     493    struct nodelist *cmdlist;
    358494};
    359495
    360 
    361496struct nredir {
    362       int type;
    363       union node *n;
    364       union node *redirect;
     497    int type;
     498    union node *n;
     499    union node *redirect;
    365500};
    366501
    367 
    368502struct nbinary {
    369       int type;
    370       union node *ch1;
    371       union node *ch2;
     503    int type;
     504    union node *ch1;
     505    union node *ch2;
    372506};
    373507
    374 
    375508struct nif {
    376       int type;
    377       union node *test;
    378       union node *ifpart;
    379       union node *elsepart;
     509    int type;
     510    union node *test;
     511    union node *ifpart;
     512    union node *elsepart;
    380513};
    381514
    382 
    383515struct nfor {
    384       int type;
    385       union node *args;
    386       union node *body;
    387       char *var;
     516    int type;
     517    union node *args;
     518    union node *body;
     519    char *var;
    388520};
    389521
    390 
    391522struct ncase {
    392       int type;
    393       union node *expr;
    394       union node *cases;
     523    int type;
     524    union node *expr;
     525    union node *cases;
    395526};
    396527
    397 
    398528struct nclist {
    399       int type;
    400       union node *next;
    401       union node *pattern;
    402       union node *body;
     529    int type;
     530    union node *next;
     531    union node *pattern;
     532    union node *body;
    403533};
    404534
    405 
    406535struct narg {
    407       int type;
    408       union node *next;
    409       char *text;
    410       struct nodelist *backquote;
     536    int type;
     537    union node *next;
     538    char *text;
     539    struct nodelist *backquote;
    411540};
    412541
    413 
    414542struct nfile {
    415       int type;
    416       union node *next;
    417       int fd;
    418       union node *fname;
    419       char *expfname;
     543    int type;
     544    union node *next;
     545    int fd;
     546    union node *fname;
     547    char *expfname;
    420548};
    421549
    422 
    423550struct ndup {
    424       int type;
    425       union node *next;
    426       int fd;
    427       int dupfd;
    428       union node *vname;
     551    int type;
     552    union node *next;
     553    int fd;
     554    int dupfd;
     555    union node *vname;
    429556};
    430557
    431 
    432558struct nhere {
    433       int type;
    434       union node *next;
    435       int fd;
    436       union node *doc;
     559    int type;
     560    union node *next;
     561    int fd;
     562    union node *doc;
    437563};
    438564
    439 
    440565struct nnot {
    441       int type;
    442       union node *com;
     566    int type;
     567    union node *com;
    443568};
    444569
    445 
    446570union node {
    447       int type;
    448       struct ncmd ncmd;
    449       struct npipe npipe;
    450       struct nredir nredir;
    451       struct nbinary nbinary;
    452       struct nif nif;
    453       struct nfor nfor;
    454       struct ncase ncase;
    455       struct nclist nclist;
    456       struct narg narg;
    457       struct nfile nfile;
    458       struct ndup ndup;
    459       struct nhere nhere;
    460       struct nnot nnot;
     571    int type;
     572    struct ncmd ncmd;
     573    struct npipe npipe;
     574    struct nredir nredir;
     575    struct nbinary nbinary;
     576    struct nif nif;
     577    struct nfor nfor;
     578    struct ncase ncase;
     579    struct nclist nclist;
     580    struct narg narg;
     581    struct nfile nfile;
     582    struct ndup ndup;
     583    struct nhere nhere;
     584    struct nnot nnot;
    461585};
    462 
    463586
    464587struct nodelist {
     
    467590};
    468591
    469 
    470592struct funcnode {
    471593    int count;
     
    473595};
    474596
    475 
    476 static void freefunc(struct funcnode *);
    477 /*      parser.h     */
    478 
    479 /* control characters in argument strings */
    480 #define CTL_FIRST '\201'        /* first 'special' character */
    481 #define CTLESC '\201'           /* escape next character */
    482 #define CTLVAR '\202'           /* variable defn */
    483 #define CTLENDVAR '\203'
    484 #define CTLBACKQ '\204'
    485 #define CTLQUOTE 01             /* ored with CTLBACKQ code if in quotes */
    486 /*      CTLBACKQ | CTLQUOTE == '\205' */
    487 #define CTLARI  '\206'          /* arithmetic expression */
    488 #define CTLENDARI '\207'
    489 #define CTLQUOTEMARK '\210'
    490 #define CTL_LAST '\210'         /* last 'special' character */
    491 
    492 /* variable substitution byte (follows CTLVAR) */
    493 #define VSTYPE  0x0f            /* type of variable substitution */
    494 #define VSNUL   0x10            /* colon--treat the empty string as unset */
    495 #define VSQUOTE 0x80            /* inside double quotes--suppress splitting */
    496 
    497 /* values of VSTYPE field */
    498 #define VSNORMAL        0x1             /* normal variable:  $var or ${var} */
    499 #define VSMINUS         0x2             /* ${var-text} */
    500 #define VSPLUS          0x3             /* ${var+text} */
    501 #define VSQUESTION      0x4             /* ${var?message} */
    502 #define VSASSIGN        0x5             /* ${var=text} */
    503 #define VSTRIMRIGHT     0x6             /* ${var%pattern} */
    504 #define VSTRIMRIGHTMAX  0x7             /* ${var%%pattern} */
    505 #define VSTRIMLEFT      0x8             /* ${var#pattern} */
    506 #define VSTRIMLEFTMAX   0x9             /* ${var##pattern} */
    507 #define VSLENGTH        0xa             /* ${#var} */
    508 
    509 /* values of checkkwd variable */
    510 #define CHKALIAS        0x1
    511 #define CHKKWD          0x2
    512 #define CHKNL           0x4
    513 
    514 #define IBUFSIZ (BUFSIZ + 1)
    515 
    516 /*
    517  * NEOF is returned by parsecmd when it encounters an end of file.  It
    518  * must be distinct from NULL, so we use the address of a variable that
    519  * happens to be handy.
    520  */
    521 static int plinno = 1;                  /* input line number */
    522 
    523 /* number of characters left in input buffer */
    524 static int parsenleft;                  /* copy of parsefile->nleft */
    525 static int parselleft;                  /* copy of parsefile->lleft */
    526 
    527 /* next character in input buffer */
    528 static char *parsenextc;                /* copy of parsefile->nextc */
     597/*
     598 * Free a parse tree.
     599 */
     600static void
     601freefunc(struct funcnode *f)
     602{
     603    if (f && --f->count < 0)
     604        free(f);
     605}
     606
     607
     608/* ============ Debugging output */
     609
     610#if DEBUG
     611
     612static FILE *tracefile;
     613
     614static void
     615trace_printf(const char *fmt, ...)
     616{
     617    va_list va;
     618
     619    if (debug != 1)
     620        return;
     621    va_start(va, fmt);
     622    vfprintf(tracefile, fmt, va);
     623    va_end(va);
     624}
     625
     626static void
     627trace_vprintf(const char *fmt, va_list va)
     628{
     629    if (debug != 1)
     630        return;
     631    vfprintf(tracefile, fmt, va);
     632}
     633
     634static void
     635trace_puts(const char *s)
     636{
     637    if (debug != 1)
     638        return;
     639    fputs(s, tracefile);
     640}
     641
     642static void
     643trace_puts_quoted(char *s)
     644{
     645    char *p;
     646    char c;
     647
     648    if (debug != 1)
     649        return;
     650    putc('"', tracefile);
     651    for (p = s; *p; p++) {
     652        switch (*p) {
     653        case '\n':  c = 'n';  goto backslash;
     654        case '\t':  c = 't';  goto backslash;
     655        case '\r':  c = 'r';  goto backslash;
     656        case '"':  c = '"';  goto backslash;
     657        case '\\':  c = '\\';  goto backslash;
     658        case CTLESC:  c = 'e';  goto backslash;
     659        case CTLVAR:  c = 'v';  goto backslash;
     660        case CTLVAR+CTLQUOTE:  c = 'V'; goto backslash;
     661        case CTLBACKQ:  c = 'q';  goto backslash;
     662        case CTLBACKQ+CTLQUOTE:  c = 'Q'; goto backslash;
     663 backslash:
     664            putc('\\', tracefile);
     665            putc(c, tracefile);
     666            break;
     667        default:
     668            if (*p >= ' ' && *p <= '~')
     669                putc(*p, tracefile);
     670            else {
     671                putc('\\', tracefile);
     672                putc(*p >> 6 & 03, tracefile);
     673                putc(*p >> 3 & 07, tracefile);
     674                putc(*p & 07, tracefile);
     675            }
     676            break;
     677        }
     678    }
     679    putc('"', tracefile);
     680}
     681
     682static void
     683trace_puts_args(char **ap)
     684{
     685    if (debug != 1)
     686        return;
     687    if (!*ap)
     688        return;
     689    while (1) {
     690        trace_puts_quoted(*ap);
     691        if (!*++ap) {
     692            putc('\n', tracefile);
     693            break;
     694        }
     695        putc(' ', tracefile);
     696    }
     697}
     698
     699static void
     700opentrace(void)
     701{
     702    char s[100];
     703#ifdef O_APPEND
     704    int flags;
     705#endif
     706
     707    if (debug != 1) {
     708        if (tracefile)
     709            fflush(tracefile);
     710        /* leave open because libedit might be using it */
     711        return;
     712    }
     713    strcpy(s, "./trace");
     714    if (tracefile) {
     715        if (!freopen(s, "a", tracefile)) {
     716            fprintf(stderr, "Can't re-open %s\n", s);
     717            debug = 0;
     718            return;
     719        }
     720    } else {
     721        tracefile = fopen(s, "a");
     722        if (tracefile == NULL) {
     723            fprintf(stderr, "Can't open %s\n", s);
     724            debug = 0;
     725            return;
     726        }
     727    }
     728#ifdef O_APPEND
     729    flags = fcntl(fileno(tracefile), F_GETFL);
     730    if (flags >= 0)
     731        fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
     732#endif
     733    setlinebuf(tracefile);
     734    fputs("\nTracing started.\n", tracefile);
     735}
     736
     737static void
     738indent(int amount, char *pfx, FILE *fp)
     739{
     740    int i;
     741
     742    for (i = 0; i < amount; i++) {
     743        if (pfx && i == amount - 1)
     744            fputs(pfx, fp);
     745        putc('\t', fp);
     746    }
     747}
     748
     749/* little circular references here... */
     750static void shtree(union node *n, int ind, char *pfx, FILE *fp);
     751
     752static void
     753sharg(union node *arg, FILE *fp)
     754{
     755    char *p;
     756    struct nodelist *bqlist;
     757    int subtype;
     758
     759    if (arg->type != NARG) {
     760        out1fmt("<node type %d>\n", arg->type);
     761        abort();
     762    }
     763    bqlist = arg->narg.backquote;
     764    for (p = arg->narg.text; *p; p++) {
     765        switch (*p) {
     766        case CTLESC:
     767            putc(*++p, fp);
     768            break;
     769        case CTLVAR:
     770            putc('$', fp);
     771            putc('{', fp);
     772            subtype = *++p;
     773            if (subtype == VSLENGTH)
     774                putc('#', fp);
     775
     776            while (*p != '=')
     777                putc(*p++, fp);
     778
     779            if (subtype & VSNUL)
     780                putc(':', fp);
     781
     782            switch (subtype & VSTYPE) {
     783            case VSNORMAL:
     784                putc('}', fp);
     785                break;
     786            case VSMINUS:
     787                putc('-', fp);
     788                break;
     789            case VSPLUS:
     790                putc('+', fp);
     791                break;
     792            case VSQUESTION:
     793                putc('?', fp);
     794                break;
     795            case VSASSIGN:
     796                putc('=', fp);
     797                break;
     798            case VSTRIMLEFT:
     799                putc('#', fp);
     800                break;
     801            case VSTRIMLEFTMAX:
     802                putc('#', fp);
     803                putc('#', fp);
     804                break;
     805            case VSTRIMRIGHT:
     806                putc('%', fp);
     807                break;
     808            case VSTRIMRIGHTMAX:
     809                putc('%', fp);
     810                putc('%', fp);
     811                break;
     812            case VSLENGTH:
     813                break;
     814            default:
     815                out1fmt("<subtype %d>", subtype);
     816            }
     817            break;
     818        case CTLENDVAR:
     819            putc('}', fp);
     820            break;
     821        case CTLBACKQ:
     822        case CTLBACKQ|CTLQUOTE:
     823            putc('$', fp);
     824            putc('(', fp);
     825            shtree(bqlist->n, -1, NULL, fp);
     826            putc(')', fp);
     827            break;
     828        default:
     829            putc(*p, fp);
     830            break;
     831        }
     832    }
     833}
     834
     835static void
     836shcmd(union node *cmd, FILE *fp)
     837{
     838    union node *np;
     839    int first;
     840    const char *s;
     841    int dftfd;
     842
     843    first = 1;
     844    for (np = cmd->ncmd.args; np; np = np->narg.next) {
     845        if (!first)
     846            putc(' ', fp);
     847        sharg(np, fp);
     848        first = 0;
     849    }
     850    for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
     851        if (!first)
     852            putc(' ', fp);
     853        dftfd = 0;
     854        switch (np->nfile.type) {
     855        case NTO:      s = ">>"+1; dftfd = 1; break;
     856        case NCLOBBER: s = ">|"; dftfd = 1; break;
     857        case NAPPEND:  s = ">>"; dftfd = 1; break;
     858        case NTOFD:    s = ">&"; dftfd = 1; break;
     859        case NFROM:    s = "<";  break;
     860        case NFROMFD:  s = "<&"; break;
     861        case NFROMTO:  s = "<>"; break;
     862        default:       s = "*error*"; break;
     863        }
     864        if (np->nfile.fd != dftfd)
     865            fprintf(fp, "%d", np->nfile.fd);
     866        fputs(s, fp);
     867        if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
     868            fprintf(fp, "%d", np->ndup.dupfd);
     869        } else {
     870            sharg(np->nfile.fname, fp);
     871        }
     872        first = 0;
     873    }
     874}
     875
     876static void
     877shtree(union node *n, int ind, char *pfx, FILE *fp)
     878{
     879    struct nodelist *lp;
     880    const char *s;
     881
     882    if (n == NULL)
     883        return;
     884
     885    indent(ind, pfx, fp);
     886    switch (n->type) {
     887    case NSEMI:
     888        s = "; ";
     889        goto binop;
     890    case NAND:
     891        s = " && ";
     892        goto binop;
     893    case NOR:
     894        s = " || ";
     895 binop:
     896        shtree(n->nbinary.ch1, ind, NULL, fp);
     897        /* if (ind < 0) */
     898            fputs(s, fp);
     899        shtree(n->nbinary.ch2, ind, NULL, fp);
     900        break;
     901    case NCMD:
     902        shcmd(n, fp);
     903        if (ind >= 0)
     904            putc('\n', fp);
     905        break;
     906    case NPIPE:
     907        for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
     908            shcmd(lp->n, fp);
     909            if (lp->next)
     910                fputs(" | ", fp);
     911        }
     912        if (n->npipe.backgnd)
     913            fputs(" &", fp);
     914        if (ind >= 0)
     915            putc('\n', fp);
     916        break;
     917    default:
     918        fprintf(fp, "<node type %d>", n->type);
     919        if (ind >= 0)
     920            putc('\n', fp);
     921        break;
     922    }
     923}
     924
     925static void
     926showtree(union node *n)
     927{
     928    trace_puts("showtree called\n");
     929    shtree(n, 1, NULL, stdout);
     930}
     931
     932#define TRACE(param)    trace_printf param
     933#define TRACEV(param)   trace_vprintf param
     934
     935#else
     936
     937#define TRACE(param)
     938#define TRACEV(param)
     939
     940#endif /* DEBUG */
     941
     942
     943/* ============ Parser data */
     944
     945/*
     946 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
     947 */
     948struct strlist {
     949    struct strlist *next;
     950    char *text;
     951};
     952
     953#if ENABLE_ASH_ALIAS
     954struct alias;
     955#endif
    529956
    530957struct strpush {
     
    532959    char *prevstring;
    533960    int prevnleft;
    534 #ifdef CONFIG_ASH_ALIAS
     961#if ENABLE_ASH_ALIAS
    535962    struct alias *ap;       /* if push was associated with an alias */
    536963#endif
     
    551978
    552979static struct parsefile basepf;         /* top level input file */
    553 #define basebuf bb_common_bufsiz1       /* buffer for top level input file */
    554980static struct parsefile *parsefile = &basepf;  /* current input file */
    555 
    556 
    557 static int tokpushback;                 /* last token pushed back */
    558 #define NEOF ((union node *)&tokpushback)
    559 static int parsebackquote;             /* nonzero if we are inside backquotes */
     981static int startlinno;                 /* line # where last token started */
     982static char *commandname;              /* currently executing command */
     983static struct strlist *cmdenviron;     /* environment for builtin command */
     984static int exitstatus;                 /* exit status of last command */
     985
     986
     987/* ============ Message printing */
     988
     989static void
     990ash_vmsg(const char *msg, va_list ap)
     991{
     992    fprintf(stderr, "%s: ", arg0);
     993    if (commandname) {
     994        if (strcmp(arg0, commandname))
     995            fprintf(stderr, "%s: ", commandname);
     996        if (!iflag || parsefile->fd)
     997            fprintf(stderr, "line %d: ", startlinno);
     998    }
     999    vfprintf(stderr, msg, ap);
     1000    outcslow('\n', stderr);
     1001}
     1002
     1003/*
     1004 * Exverror is called to raise the error exception.  If the second argument
     1005 * is not NULL then error prints an error message using printf style
     1006 * formatting.  It then raises the error exception.
     1007 */
     1008static void ash_vmsg_and_raise(int, const char *, va_list) ATTRIBUTE_NORETURN;
     1009static void
     1010ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
     1011{
     1012#if DEBUG
     1013    if (msg) {
     1014        TRACE(("ash_vmsg_and_raise(%d, \"", cond));
     1015        TRACEV((msg, ap));
     1016        TRACE(("\") pid=%d\n", getpid()));
     1017    } else
     1018        TRACE(("ash_vmsg_and_raise(%d, NULL) pid=%d\n", cond, getpid()));
     1019    if (msg)
     1020#endif
     1021        ash_vmsg(msg, ap);
     1022
     1023    flush_stdout_stderr();
     1024    raise_exception(cond);
     1025    /* NOTREACHED */
     1026}
     1027
     1028static void ash_msg_and_raise_error(const char *, ...) ATTRIBUTE_NORETURN;
     1029static void
     1030ash_msg_and_raise_error(const char *msg, ...)
     1031{
     1032    va_list ap;
     1033
     1034    va_start(ap, msg);
     1035    ash_vmsg_and_raise(EXERROR, msg, ap);
     1036    /* NOTREACHED */
     1037    va_end(ap);
     1038}
     1039
     1040static void ash_msg_and_raise(int, const char *, ...) ATTRIBUTE_NORETURN;
     1041static void
     1042ash_msg_and_raise(int cond, const char *msg, ...)
     1043{
     1044    va_list ap;
     1045
     1046    va_start(ap, msg);
     1047    ash_vmsg_and_raise(cond, msg, ap);
     1048    /* NOTREACHED */
     1049    va_end(ap);
     1050}
     1051
     1052/*
     1053 * error/warning routines for external builtins
     1054 */
     1055static void
     1056ash_msg(const char *fmt, ...)
     1057{
     1058    va_list ap;
     1059
     1060    va_start(ap, fmt);
     1061    ash_vmsg(fmt, ap);
     1062    va_end(ap);
     1063}
     1064
     1065/*
     1066 * Return a string describing an error.  The returned string may be a
     1067 * pointer to a static buffer that will be overwritten on the next call.
     1068 * Action describes the operation that got the error.
     1069 */
     1070static const char *
     1071errmsg(int e, const char *em)
     1072{
     1073    if (e == ENOENT || e == ENOTDIR) {
     1074        return em;
     1075    }
     1076    return strerror(e);
     1077}
     1078
     1079
     1080/* ============ Memory allocation */
     1081
     1082/*
     1083 * It appears that grabstackstr() will barf with such alignments
     1084 * because stalloc() will return a string allocated in a new stackblock.
     1085 */
     1086#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
     1087enum {
     1088    /* Most machines require the value returned from malloc to be aligned
     1089     * in some way.  The following macro will get this right
     1090     * on many machines.  */
     1091    SHELL_SIZE = sizeof(union {int i; char *cp; double d; }) - 1,
     1092    /* Minimum size of a block */
     1093    MINSIZE  = SHELL_ALIGN(504),
     1094};
     1095
     1096struct stack_block {
     1097    struct stack_block *prev;
     1098    char space[MINSIZE];
     1099};
     1100
     1101struct stackmark {
     1102    struct stack_block *stackp;
     1103    char *stacknxt;
     1104    size_t stacknleft;
     1105    struct stackmark *marknext;
     1106};
     1107
     1108static struct stack_block stackbase;
     1109static struct stack_block *stackp = &stackbase;
     1110static struct stackmark *markp;
     1111static char *stacknxt = stackbase.space;
     1112static size_t stacknleft = MINSIZE;
     1113static char *sstrend = stackbase.space + MINSIZE;
     1114static int herefd = -1;
     1115
     1116#define stackblock() ((void *)stacknxt)
     1117#define stackblocksize() stacknleft
     1118
     1119static void *
     1120ckrealloc(void * p, size_t nbytes)
     1121{
     1122    p = realloc(p, nbytes);
     1123    if (!p)
     1124        ash_msg_and_raise_error(bb_msg_memory_exhausted);
     1125    return p;
     1126}
     1127
     1128static void *
     1129ckmalloc(size_t nbytes)
     1130{
     1131    return ckrealloc(NULL, nbytes);
     1132}
     1133
     1134/*
     1135 * Make a copy of a string in safe storage.
     1136 */
     1137static char *
     1138ckstrdup(const char *s)
     1139{
     1140    char *p = strdup(s);
     1141    if (!p)
     1142        ash_msg_and_raise_error(bb_msg_memory_exhausted);
     1143    return p;
     1144}
     1145
     1146/*
     1147 * Parse trees for commands are allocated in lifo order, so we use a stack
     1148 * to make this more efficient, and also to avoid all sorts of exception
     1149 * handling code to handle interrupts in the middle of a parse.
     1150 *
     1151 * The size 504 was chosen because the Ultrix malloc handles that size
     1152 * well.
     1153 */
     1154static void *
     1155stalloc(size_t nbytes)
     1156{
     1157    char *p;
     1158    size_t aligned;
     1159
     1160    aligned = SHELL_ALIGN(nbytes);
     1161    if (aligned > stacknleft) {
     1162        size_t len;
     1163        size_t blocksize;
     1164        struct stack_block *sp;
     1165
     1166        blocksize = aligned;
     1167        if (blocksize < MINSIZE)
     1168            blocksize = MINSIZE;
     1169        len = sizeof(struct stack_block) - MINSIZE + blocksize;
     1170        if (len < blocksize)
     1171            ash_msg_and_raise_error(bb_msg_memory_exhausted);
     1172        INT_OFF;
     1173        sp = ckmalloc(len);
     1174        sp->prev = stackp;
     1175        stacknxt = sp->space;
     1176        stacknleft = blocksize;
     1177        sstrend = stacknxt + blocksize;
     1178        stackp = sp;
     1179        INT_ON;
     1180    }
     1181    p = stacknxt;
     1182    stacknxt += aligned;
     1183    stacknleft -= aligned;
     1184    return p;
     1185}
     1186
     1187static void
     1188stunalloc(void *p)
     1189{
     1190#if DEBUG
     1191    if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
     1192        write(2, "stunalloc\n", 10);
     1193        abort();
     1194    }
     1195#endif
     1196    stacknleft += stacknxt - (char *)p;
     1197    stacknxt = p;
     1198}
     1199
     1200/*
     1201 * Like strdup but works with the ash stack.
     1202 */
     1203static char *
     1204ststrdup(const char *p)
     1205{
     1206    size_t len = strlen(p) + 1;
     1207    return memcpy(stalloc(len), p, len);
     1208}
     1209
     1210static void
     1211setstackmark(struct stackmark *mark)
     1212{
     1213    mark->stackp = stackp;
     1214    mark->stacknxt = stacknxt;
     1215    mark->stacknleft = stacknleft;
     1216    mark->marknext = markp;
     1217    markp = mark;
     1218}
     1219
     1220static void
     1221popstackmark(struct stackmark *mark)
     1222{
     1223    struct stack_block *sp;
     1224
     1225    if (!mark->stackp)
     1226        return;
     1227
     1228    INT_OFF;
     1229    markp = mark->marknext;
     1230    while (stackp != mark->stackp) {
     1231        sp = stackp;
     1232        stackp = sp->prev;
     1233        free(sp);
     1234    }
     1235    stacknxt = mark->stacknxt;
     1236    stacknleft = mark->stacknleft;
     1237    sstrend = mark->stacknxt + mark->stacknleft;
     1238    INT_ON;
     1239}
     1240
     1241/*
     1242 * When the parser reads in a string, it wants to stick the string on the
     1243 * stack and only adjust the stack pointer when it knows how big the
     1244 * string is.  Stackblock (defined in stack.h) returns a pointer to a block
     1245 * of space on top of the stack and stackblocklen returns the length of
     1246 * this block.  Growstackblock will grow this space by at least one byte,
     1247 * possibly moving it (like realloc).  Grabstackblock actually allocates the
     1248 * part of the block that has been used.
     1249 */
     1250static void
     1251growstackblock(void)
     1252{
     1253    size_t newlen;
     1254
     1255    newlen = stacknleft * 2;
     1256    if (newlen < stacknleft)
     1257        ash_msg_and_raise_error(bb_msg_memory_exhausted);
     1258    if (newlen < 128)
     1259        newlen += 128;
     1260
     1261    if (stacknxt == stackp->space && stackp != &stackbase) {
     1262        struct stack_block *oldstackp;
     1263        struct stackmark *xmark;
     1264        struct stack_block *sp;
     1265        struct stack_block *prevstackp;
     1266        size_t grosslen;
     1267
     1268        INT_OFF;
     1269        oldstackp = stackp;
     1270        sp = stackp;
     1271        prevstackp = sp->prev;
     1272        grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
     1273        sp = ckrealloc(sp, grosslen);
     1274        sp->prev = prevstackp;
     1275        stackp = sp;
     1276        stacknxt = sp->space;
     1277        stacknleft = newlen;
     1278        sstrend = sp->space + newlen;
     1279
     1280        /*
     1281         * Stack marks pointing to the start of the old block
     1282         * must be relocated to point to the new block
     1283         */
     1284        xmark = markp;
     1285        while (xmark != NULL && xmark->stackp == oldstackp) {
     1286            xmark->stackp = stackp;
     1287            xmark->stacknxt = stacknxt;
     1288            xmark->stacknleft = stacknleft;
     1289            xmark = xmark->marknext;
     1290        }
     1291        INT_ON;
     1292    } else {
     1293        char *oldspace = stacknxt;
     1294        int oldlen = stacknleft;
     1295        char *p = stalloc(newlen);
     1296
     1297        /* free the space we just allocated */
     1298        stacknxt = memcpy(p, oldspace, oldlen);
     1299        stacknleft += newlen;
     1300    }
     1301}
     1302
     1303static void
     1304grabstackblock(size_t len)
     1305{
     1306    len = SHELL_ALIGN(len);
     1307    stacknxt += len;
     1308    stacknleft -= len;
     1309}
     1310
     1311/*
     1312 * The following routines are somewhat easier to use than the above.
     1313 * The user declares a variable of type STACKSTR, which may be declared
     1314 * to be a register.  The macro STARTSTACKSTR initializes things.  Then
     1315 * the user uses the macro STPUTC to add characters to the string.  In
     1316 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
     1317 * grown as necessary.  When the user is done, she can just leave the
     1318 * string there and refer to it using stackblock().  Or she can allocate
     1319 * the space for it using grabstackstr().  If it is necessary to allow
     1320 * someone else to use the stack temporarily and then continue to grow
     1321 * the string, the user should use grabstack to allocate the space, and
     1322 * then call ungrabstr(p) to return to the previous mode of operation.
     1323 *
     1324 * USTPUTC is like STPUTC except that it doesn't check for overflow.
     1325 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
     1326 * is space for at least one character.
     1327 */
     1328static void *
     1329growstackstr(void)
     1330{
     1331    size_t len = stackblocksize();
     1332    if (herefd >= 0 && len >= 1024) {
     1333        full_write(herefd, stackblock(), len);
     1334        return stackblock();
     1335    }
     1336    growstackblock();
     1337    return stackblock() + len;
     1338}
     1339
     1340/*
     1341 * Called from CHECKSTRSPACE.
     1342 */
     1343static char *
     1344makestrspace(size_t newlen, char *p)
     1345{
     1346    size_t len = p - stacknxt;
     1347    size_t size = stackblocksize();
     1348
     1349    for (;;) {
     1350        size_t nleft;
     1351
     1352        size = stackblocksize();
     1353        nleft = size - len;
     1354        if (nleft >= newlen)
     1355            break;
     1356        growstackblock();
     1357    }
     1358    return stackblock() + len;
     1359}
     1360
     1361static char *
     1362stack_nputstr(const char *s, size_t n, char *p)
     1363{
     1364    p = makestrspace(n, p);
     1365    p = memcpy(p, s, n) + n;
     1366    return p;
     1367}
     1368
     1369static char *
     1370stack_putstr(const char *s, char *p)
     1371{
     1372    return stack_nputstr(s, strlen(s), p);
     1373}
     1374
     1375static char *
     1376_STPUTC(int c, char *p)
     1377{
     1378    if (p == sstrend)
     1379        p = growstackstr();
     1380    *p++ = c;
     1381    return p;
     1382}
     1383
     1384#define STARTSTACKSTR(p)        ((p) = stackblock())
     1385#define STPUTC(c, p)            ((p) = _STPUTC((c), (p)))
     1386#define CHECKSTRSPACE(n, p) \
     1387    do { \
     1388        char *q = (p); \
     1389        size_t l = (n); \
     1390        size_t m = sstrend - q; \
     1391        if (l > m) \
     1392            (p) = makestrspace(l, q); \
     1393    } while (0)
     1394#define USTPUTC(c, p)           (*p++ = (c))
     1395#define STACKSTRNUL(p) \
     1396    do { \
     1397        if ((p) == sstrend) \
     1398            p = growstackstr(); \
     1399        *p = '\0'; \
     1400    } while (0)
     1401#define STUNPUTC(p)             (--p)
     1402#define STTOPC(p)               (p[-1])
     1403#define STADJUST(amount, p)     (p += (amount))
     1404
     1405#define grabstackstr(p)         stalloc((char *)(p) - (char *)stackblock())
     1406#define ungrabstackstr(s, p)    stunalloc((s))
     1407#define stackstrend()           ((void *)sstrend)
     1408
     1409
     1410/* ============ String helpers */
     1411
     1412/*
     1413 * prefix -- see if pfx is a prefix of string.
     1414 */
     1415static char *
     1416prefix(const char *string, const char *pfx)
     1417{
     1418    while (*pfx) {
     1419        if (*pfx++ != *string++)
     1420            return 0;
     1421    }
     1422    return (char *) string;
     1423}
     1424
     1425/*
     1426 * Check for a valid number.  This should be elsewhere.
     1427 */
     1428static int
     1429is_number(const char *p)
     1430{
     1431    do {
     1432        if (!isdigit(*p))
     1433            return 0;
     1434    } while (*++p != '\0');
     1435    return 1;
     1436}
     1437
     1438/*
     1439 * Convert a string of digits to an integer, printing an error message on
     1440 * failure.
     1441 */
     1442static int
     1443number(const char *s)
     1444{
     1445    if (!is_number(s))
     1446        ash_msg_and_raise_error(illnum, s);
     1447    return atoi(s);
     1448}
     1449
     1450/*
     1451 * Produce a possibly single quoted string suitable as input to the shell.
     1452 * The return string is allocated on the stack.
     1453 */
     1454static char *
     1455single_quote(const char *s)
     1456{
     1457    char *p;
     1458
     1459    STARTSTACKSTR(p);
     1460
     1461    do {
     1462        char *q;
     1463        size_t len;
     1464
     1465        len = strchrnul(s, '\'') - s;
     1466
     1467        q = p = makestrspace(len + 3, p);
     1468
     1469        *q++ = '\'';
     1470        q = memcpy(q, s, len) + len;
     1471        *q++ = '\'';
     1472        s += len;
     1473
     1474        STADJUST(q - p, p);
     1475
     1476        len = strspn(s, "'");
     1477        if (!len)
     1478            break;
     1479
     1480        q = p = makestrspace(len + 3, p);
     1481
     1482        *q++ = '"';
     1483        q = memcpy(q, s, len) + len;
     1484        *q++ = '"';
     1485        s += len;
     1486
     1487        STADJUST(q - p, p);
     1488    } while (*s);
     1489
     1490    USTPUTC(0, p);
     1491
     1492    return stackblock();
     1493}
     1494
     1495
     1496/* ============ nextopt */
     1497
     1498static char **argptr;                  /* argument list for builtin commands */
     1499static char *optionarg;                /* set by nextopt (like getopt) */
     1500static char *optptr;                   /* used by nextopt */
     1501
     1502/*
     1503 * XXX - should get rid of.  have all builtins use getopt(3).  the
     1504 * library getopt must have the BSD extension static variable "optreset"
     1505 * otherwise it can't be used within the shell safely.
     1506 *
     1507 * Standard option processing (a la getopt) for builtin routines.  The
     1508 * only argument that is passed to nextopt is the option string; the
     1509 * other arguments are unnecessary.  It return the character, or '\0' on
     1510 * end of input.
     1511 */
     1512static int
     1513nextopt(const char *optstring)
     1514{
     1515    char *p;
     1516    const char *q;
     1517    char c;
     1518
     1519    p = optptr;
     1520    if (p == NULL || *p == '\0') {
     1521        p = *argptr;
     1522        if (p == NULL || *p != '-' || *++p == '\0')
     1523            return '\0';
     1524        argptr++;
     1525        if (LONE_DASH(p))        /* check for "--" */
     1526            return '\0';
     1527    }
     1528    c = *p++;
     1529    for (q = optstring; *q != c; ) {
     1530        if (*q == '\0')
     1531            ash_msg_and_raise_error("illegal option -%c", c);
     1532        if (*++q == ':')
     1533            q++;
     1534    }
     1535    if (*++q == ':') {
     1536        if (*p == '\0' && (p = *argptr++) == NULL)
     1537            ash_msg_and_raise_error("no arg for -%c option", c);
     1538        optionarg = p;
     1539        p = NULL;
     1540    }
     1541    optptr = p;
     1542    return c;
     1543}
     1544
     1545
     1546/* ============ Math support definitions */
     1547
     1548#if ENABLE_ASH_MATH_SUPPORT_64
     1549typedef int64_t arith_t;
     1550#define arith_t_type long long
     1551#else
     1552typedef long arith_t;
     1553#define arith_t_type long
     1554#endif
     1555
     1556#if ENABLE_ASH_MATH_SUPPORT
     1557static arith_t dash_arith(const char *);
     1558static arith_t arith(const char *expr, int *perrcode);
     1559#endif
     1560
     1561#if ENABLE_ASH_RANDOM_SUPPORT
     1562static unsigned long rseed;
     1563#ifndef DYNAMIC_VAR
     1564#define DYNAMIC_VAR
     1565#endif
     1566#endif
     1567
     1568
     1569/* ============ Shell variables */
     1570
     1571/* flags */
     1572#define VEXPORT         0x01    /* variable is exported */
     1573#define VREADONLY       0x02    /* variable cannot be modified */
     1574#define VSTRFIXED       0x04    /* variable struct is statically allocated */
     1575#define VTEXTFIXED      0x08    /* text is statically allocated */
     1576#define VSTACK          0x10    /* text is allocated on the stack */
     1577#define VUNSET          0x20    /* the variable is not set */
     1578#define VNOFUNC         0x40    /* don't call the callback function */
     1579#define VNOSET          0x80    /* do not set variable - just readonly test */
     1580#define VNOSAVE         0x100   /* when text is on the heap before setvareq */
     1581#ifdef DYNAMIC_VAR
     1582# define VDYNAMIC       0x200   /* dynamic variable */
     1583#else
     1584# define VDYNAMIC       0
     1585#endif
     1586
     1587#ifdef IFS_BROKEN
     1588static const char defifsvar[] ALIGN1 = "IFS= \t\n";
     1589#define defifs (defifsvar + 4)
     1590#else
     1591static const char defifs[] ALIGN1 = " \t\n";
     1592#endif
     1593
     1594struct shparam {
     1595    int nparam;             /* # of positional parameters (without $0) */
     1596    unsigned char malloc;   /* if parameter list dynamically allocated */
     1597    char **p;               /* parameter list */
     1598#if ENABLE_ASH_GETOPTS
     1599    int optind;             /* next parameter to be processed by getopts */
     1600    int optoff;             /* used by getopts */
     1601#endif
     1602};
     1603
     1604static struct shparam shellparam;      /* $@ current positional parameters */
     1605
     1606/*
     1607 * Free the list of positional parameters.
     1608 */
     1609static void
     1610freeparam(volatile struct shparam *param)
     1611{
     1612    char **ap;
     1613
     1614    if (param->malloc) {
     1615        for (ap = param->p; *ap; ap++)
     1616            free(*ap);
     1617        free(param->p);
     1618    }
     1619}
     1620
     1621#if ENABLE_ASH_GETOPTS
     1622static void
     1623getoptsreset(const char *value)
     1624{
     1625    shellparam.optind = number(value);
     1626    shellparam.optoff = -1;
     1627}
     1628#endif
     1629
     1630struct var {
     1631    struct var *next;               /* next entry in hash list */
     1632    int flags;                      /* flags are defined above */
     1633    const char *text;               /* name=value */
     1634    void (*func)(const char *);     /* function to be called when  */
     1635                    /* the variable gets set/unset */
     1636};
     1637
     1638struct localvar {
     1639    struct localvar *next;          /* next local variable in list */
     1640    struct var *vp;                 /* the variable that was made local */
     1641    int flags;                      /* saved flags */
     1642    const char *text;               /* saved text */
     1643};
     1644
     1645/* Forward decls for varinit[] */
     1646#if ENABLE_LOCALE_SUPPORT
     1647static void
     1648change_lc_all(const char *value)
     1649{
     1650    if (value && *value != '\0')
     1651        setlocale(LC_ALL, value);
     1652}
     1653static void
     1654change_lc_ctype(const char *value)
     1655{
     1656    if (value && *value != '\0')
     1657        setlocale(LC_CTYPE, value);
     1658}
     1659#endif
     1660#if ENABLE_ASH_MAIL
     1661static void chkmail(void);
     1662static void changemail(const char *);
     1663#endif
     1664static void changepath(const char *);
     1665#if ENABLE_ASH_RANDOM_SUPPORT
     1666static void change_random(const char *);
     1667#endif
     1668
     1669static struct var varinit[] = {
     1670#ifdef IFS_BROKEN
     1671    { NULL, VSTRFIXED|VTEXTFIXED,           defifsvar,      NULL },
     1672#else
     1673    { NULL, VSTRFIXED|VTEXTFIXED|VUNSET,    "IFS\0",        NULL },
     1674#endif
     1675#if ENABLE_ASH_MAIL
     1676    { NULL, VSTRFIXED|VTEXTFIXED|VUNSET,    "MAIL\0",       changemail },
     1677    { NULL, VSTRFIXED|VTEXTFIXED|VUNSET,    "MAILPATH\0",   changemail },
     1678#endif
     1679    { NULL, VSTRFIXED|VTEXTFIXED,           bb_PATH_root_path, changepath },
     1680    { NULL, VSTRFIXED|VTEXTFIXED,           "PS1=$ ",       NULL },
     1681    { NULL, VSTRFIXED|VTEXTFIXED,           "PS2=> ",       NULL },
     1682    { NULL, VSTRFIXED|VTEXTFIXED,           "PS4=+ ",       NULL },
     1683#if ENABLE_ASH_GETOPTS
     1684    { NULL, VSTRFIXED|VTEXTFIXED,           "OPTIND=1",     getoptsreset },
     1685#endif
     1686#if ENABLE_ASH_RANDOM_SUPPORT
     1687    { NULL, VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random },
     1688#endif
     1689#if ENABLE_LOCALE_SUPPORT
     1690    { NULL, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL\0",    change_lc_all },
     1691    { NULL, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE\0",  change_lc_ctype },
     1692#endif
     1693#if ENABLE_FEATURE_EDITING_SAVEHISTORY
     1694    { NULL, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE\0",  NULL },
     1695#endif
     1696};
     1697
     1698#define vifs varinit[0]
     1699#if ENABLE_ASH_MAIL
     1700#define vmail (&vifs)[1]
     1701#define vmpath (&vmail)[1]
     1702#else
     1703#define vmpath vifs
     1704#endif
     1705#define vpath (&vmpath)[1]
     1706#define vps1 (&vpath)[1]
     1707#define vps2 (&vps1)[1]
     1708#define vps4 (&vps2)[1]
     1709#define voptind (&vps4)[1]
     1710#if ENABLE_ASH_GETOPTS
     1711#define vrandom (&voptind)[1]
     1712#else
     1713#define vrandom (&vps4)[1]
     1714#endif
     1715
     1716/*
     1717 * The following macros access the values of the above variables.
     1718 * They have to skip over the name.  They return the null string
     1719 * for unset variables.
     1720 */
     1721#define ifsval()        (vifs.text + 4)
     1722#define ifsset()        ((vifs.flags & VUNSET) == 0)
     1723#define mailval()       (vmail.text + 5)
     1724#define mpathval()      (vmpath.text + 9)
     1725#define pathval()       (vpath.text + 5)
     1726#define ps1val()        (vps1.text + 4)
     1727#define ps2val()        (vps2.text + 4)
     1728#define ps4val()        (vps4.text + 4)
     1729#define optindval()     (voptind.text + 7)
     1730
     1731#define mpathset()      ((vmpath.flags & VUNSET) == 0)
     1732
     1733/*
     1734 * The parsefile structure pointed to by the global variable parsefile
     1735 * contains information about the current file being read.
     1736 */
     1737struct redirtab {
     1738    struct redirtab *next;
     1739    int renamed[10];
     1740    int nullredirs;
     1741};
     1742
     1743static struct redirtab *redirlist;
     1744static int nullredirs;
     1745static int preverrout_fd;   /* save fd2 before print debug if xflag is set. */
     1746
     1747#define VTABSIZE 39
     1748
     1749static struct var *vartab[VTABSIZE];
     1750
     1751#define is_name(c)      ((c) == '_' || isalpha((unsigned char)(c)))
     1752#define is_in_name(c)   ((c) == '_' || isalnum((unsigned char)(c)))
     1753
     1754/*
     1755 * Return of a legal variable name (a letter or underscore followed by zero or
     1756 * more letters, underscores, and digits).
     1757 */
     1758static char *
     1759endofname(const char *name)
     1760{
     1761    char *p;
     1762
     1763    p = (char *) name;
     1764    if (!is_name(*p))
     1765        return p;
     1766    while (*++p) {
     1767        if (!is_in_name(*p))
     1768            break;
     1769    }
     1770    return p;
     1771}
     1772
     1773/*
     1774 * Compares two strings up to the first = or '\0'.  The first
     1775 * string must be terminated by '='; the second may be terminated by
     1776 * either '=' or '\0'.
     1777 */
     1778static int
     1779varcmp(const char *p, const char *q)
     1780{
     1781    int c, d;
     1782
     1783    while ((c = *p) == (d = *q)) {
     1784        if (!c || c == '=')
     1785            goto out;
     1786        p++;
     1787        q++;
     1788    }
     1789    if (c == '=')
     1790        c = '\0';
     1791    if (d == '=')
     1792        d = '\0';
     1793 out:
     1794    return c - d;
     1795}
     1796
     1797static int
     1798varequal(const char *a, const char *b)
     1799{
     1800    return !varcmp(a, b);
     1801}
     1802
     1803/*
     1804 * Find the appropriate entry in the hash table from the name.
     1805 */
     1806static struct var **
     1807hashvar(const char *p)
     1808{
     1809    unsigned hashval;
     1810
     1811    hashval = ((unsigned char) *p) << 4;
     1812    while (*p && *p != '=')
     1813        hashval += (unsigned char) *p++;
     1814    return &vartab[hashval % VTABSIZE];
     1815}
     1816
     1817static int
     1818vpcmp(const void *a, const void *b)
     1819{
     1820    return varcmp(*(const char **)a, *(const char **)b);
     1821}
     1822
     1823/*
     1824 * This routine initializes the builtin variables.
     1825 */
     1826static void
     1827initvar(void)
     1828{
     1829    struct var *vp;
     1830    struct var *end;
     1831    struct var **vpp;
     1832
     1833    /*
     1834     * PS1 depends on uid
     1835     */
     1836#if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
     1837    vps1.text = "PS1=\\w \\$ ";
     1838#else
     1839    if (!geteuid())
     1840        vps1.text = "PS1=# ";
     1841#endif
     1842    vp = varinit;
     1843    end = vp + ARRAY_SIZE(varinit);
     1844    do {
     1845        vpp = hashvar(vp->text);
     1846        vp->next = *vpp;
     1847        *vpp = vp;
     1848    } while (++vp < end);
     1849}
     1850
     1851static struct var **
     1852findvar(struct var **vpp, const char *name)
     1853{
     1854    for (; *vpp; vpp = &(*vpp)->next) {
     1855        if (varequal((*vpp)->text, name)) {
     1856            break;
     1857        }
     1858    }
     1859    return vpp;
     1860}
     1861
     1862/*
     1863 * Find the value of a variable.  Returns NULL if not set.
     1864 */
     1865static char *
     1866lookupvar(const char *name)
     1867{
     1868    struct var *v;
     1869
     1870    v = *findvar(hashvar(name), name);
     1871    if (v) {
     1872#ifdef DYNAMIC_VAR
     1873    /*
     1874     * Dynamic variables are implemented roughly the same way they are
     1875     * in bash. Namely, they're "special" so long as they aren't unset.
     1876     * As soon as they're unset, they're no longer dynamic, and dynamic
     1877     * lookup will no longer happen at that point. -- PFM.
     1878     */
     1879        if ((v->flags & VDYNAMIC))
     1880            (*v->func)(NULL);
     1881#endif
     1882        if (!(v->flags & VUNSET))
     1883            return strchrnul(v->text, '=') + 1;
     1884    }
     1885    return NULL;
     1886}
     1887
     1888/*
     1889 * Search the environment of a builtin command.
     1890 */
     1891static char *
     1892bltinlookup(const char *name)
     1893{
     1894    struct strlist *sp;
     1895
     1896    for (sp = cmdenviron; sp; sp = sp->next) {
     1897        if (varequal(sp->text, name))
     1898            return strchrnul(sp->text, '=') + 1;
     1899    }
     1900    return lookupvar(name);
     1901}
     1902
     1903/*
     1904 * Same as setvar except that the variable and value are passed in
     1905 * the first argument as name=value.  Since the first argument will
     1906 * be actually stored in the table, it should not be a string that
     1907 * will go away.
     1908 * Called with interrupts off.
     1909 */
     1910static void
     1911setvareq(char *s, int flags)
     1912{
     1913    struct var *vp, **vpp;
     1914
     1915    vpp = hashvar(s);
     1916    flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
     1917    vp = *findvar(vpp, s);
     1918    if (vp) {
     1919        if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
     1920            const char *n;
     1921
     1922            if (flags & VNOSAVE)
     1923                free(s);
     1924            n = vp->text;
     1925            ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
     1926        }
     1927
     1928        if (flags & VNOSET)
     1929            return;
     1930
     1931        if (vp->func && (flags & VNOFUNC) == 0)
     1932            (*vp->func)(strchrnul(s, '=') + 1);
     1933
     1934        if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
     1935            free((char*)vp->text);
     1936
     1937        flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
     1938    } else {
     1939        if (flags & VNOSET)
     1940            return;
     1941        /* not found */
     1942        vp = ckmalloc(sizeof(*vp));
     1943        vp->next = *vpp;
     1944        vp->func = NULL;
     1945        *vpp = vp;
     1946    }
     1947    if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
     1948        s = ckstrdup(s);
     1949    vp->text = s;
     1950    vp->flags = flags;
     1951}
     1952
     1953/*
     1954 * Set the value of a variable.  The flags argument is ored with the
     1955 * flags of the variable.  If val is NULL, the variable is unset.
     1956 */
     1957static void
     1958setvar(const char *name, const char *val, int flags)
     1959{
     1960    char *p, *q;
     1961    size_t namelen;
     1962    char *nameeq;
     1963    size_t vallen;
     1964
     1965    q = endofname(name);
     1966    p = strchrnul(q, '=');
     1967    namelen = p - name;
     1968    if (!namelen || p != q)
     1969        ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
     1970    vallen = 0;
     1971    if (val == NULL) {
     1972        flags |= VUNSET;
     1973    } else {
     1974        vallen = strlen(val);
     1975    }
     1976    INT_OFF;
     1977    nameeq = ckmalloc(namelen + vallen + 2);
     1978    p = memcpy(nameeq, name, namelen) + namelen;
     1979    if (val) {
     1980        *p++ = '=';
     1981        p = memcpy(p, val, vallen) + vallen;
     1982    }
     1983    *p = '\0';
     1984    setvareq(nameeq, flags | VNOSAVE);
     1985    INT_ON;
     1986}
     1987
     1988#if ENABLE_ASH_GETOPTS
     1989/*
     1990 * Safe version of setvar, returns 1 on success 0 on failure.
     1991 */
     1992static int
     1993setvarsafe(const char *name, const char *val, int flags)
     1994{
     1995    int err;
     1996    volatile int saveint;
     1997    struct jmploc *volatile savehandler = exception_handler;
     1998    struct jmploc jmploc;
     1999
     2000    SAVE_INT(saveint);
     2001    if (setjmp(jmploc.loc))
     2002        err = 1;
     2003    else {
     2004        exception_handler = &jmploc;
     2005        setvar(name, val, flags);
     2006        err = 0;
     2007    }
     2008    exception_handler = savehandler;
     2009    RESTORE_INT(saveint);
     2010    return err;
     2011}
     2012#endif
     2013
     2014/*
     2015 * Unset the specified variable.
     2016 */
     2017static int
     2018unsetvar(const char *s)
     2019{
     2020    struct var **vpp;
     2021    struct var *vp;
     2022    int retval;
     2023
     2024    vpp = findvar(hashvar(s), s);
     2025    vp = *vpp;
     2026    retval = 2;
     2027    if (vp) {
     2028        int flags = vp->flags;
     2029
     2030        retval = 1;
     2031        if (flags & VREADONLY)
     2032            goto out;
     2033#ifdef DYNAMIC_VAR
     2034        vp->flags &= ~VDYNAMIC;
     2035#endif
     2036        if (flags & VUNSET)
     2037            goto ok;
     2038        if ((flags & VSTRFIXED) == 0) {
     2039            INT_OFF;
     2040            if ((flags & (VTEXTFIXED|VSTACK)) == 0)
     2041                free((char*)vp->text);
     2042            *vpp = vp->next;
     2043            free(vp);
     2044            INT_ON;
     2045        } else {
     2046            setvar(s, 0, 0);
     2047            vp->flags &= ~VEXPORT;
     2048        }
     2049 ok:
     2050        retval = 0;
     2051    }
     2052 out:
     2053    return retval;
     2054}
     2055
     2056/*
     2057 * Process a linked list of variable assignments.
     2058 */
     2059static void
     2060listsetvar(struct strlist *list_set_var, int flags)
     2061{
     2062    struct strlist *lp = list_set_var;
     2063
     2064    if (!lp)
     2065        return;
     2066    INT_OFF;
     2067    do {
     2068        setvareq(lp->text, flags);
     2069        lp = lp->next;
     2070    } while (lp);
     2071    INT_ON;
     2072}
     2073
     2074/*
     2075 * Generate a list of variables satisfying the given conditions.
     2076 */
     2077static char **
     2078listvars(int on, int off, char ***end)
     2079{
     2080    struct var **vpp;
     2081    struct var *vp;
     2082    char **ep;
     2083    int mask;
     2084
     2085    STARTSTACKSTR(ep);
     2086    vpp = vartab;
     2087    mask = on | off;
     2088    do {
     2089        for (vp = *vpp; vp; vp = vp->next) {
     2090            if ((vp->flags & mask) == on) {
     2091                if (ep == stackstrend())
     2092                    ep = growstackstr();
     2093                *ep++ = (char *) vp->text;
     2094            }
     2095        }
     2096    } while (++vpp < vartab + VTABSIZE);
     2097    if (ep == stackstrend())
     2098        ep = growstackstr();
     2099    if (end)
     2100        *end = ep;
     2101    *ep++ = NULL;
     2102    return grabstackstr(ep);
     2103}
     2104
     2105
     2106/* ============ Path search helper
     2107 *
     2108 * The variable path (passed by reference) should be set to the start
     2109 * of the path before the first call; padvance will update
     2110 * this value as it proceeds.  Successive calls to padvance will return
     2111 * the possible path expansions in sequence.  If an option (indicated by
     2112 * a percent sign) appears in the path entry then the global variable
     2113 * pathopt will be set to point to it; otherwise pathopt will be set to
     2114 * NULL.
     2115 */
     2116static const char *pathopt;     /* set by padvance */
     2117
     2118static char *
     2119padvance(const char **path, const char *name)
     2120{
     2121    const char *p;
     2122    char *q;
     2123    const char *start;
     2124    size_t len;
     2125
     2126    if (*path == NULL)
     2127        return NULL;
     2128    start = *path;
     2129    for (p = start; *p && *p != ':' && *p != '%'; p++);
     2130    len = p - start + strlen(name) + 2;     /* "2" is for '/' and '\0' */
     2131    while (stackblocksize() < len)
     2132        growstackblock();
     2133    q = stackblock();
     2134    if (p != start) {
     2135        memcpy(q, start, p - start);
     2136        q += p - start;
     2137        *q++ = '/';
     2138    }
     2139    strcpy(q, name);
     2140    pathopt = NULL;
     2141    if (*p == '%') {
     2142        pathopt = ++p;
     2143        while (*p && *p != ':') p++;
     2144    }
     2145    if (*p == ':')
     2146        *path = p + 1;
     2147    else
     2148        *path = NULL;
     2149    return stalloc(len);
     2150}
     2151
     2152
     2153/* ============ Prompt */
     2154
    5602155static int doprompt;                   /* if set, prompt the user */
    5612156static int needprompt;                 /* true if interactive and at start of line */
    562 static int lasttoken;                  /* last token read */
    563 static char *wordtext;                 /* text of last word returned by readtoken */
    564 static int checkkwd;
    565 static struct nodelist *backquotelist;
    566 static union node *redirnode;
    567 static struct heredoc *heredoc;
    568 static int quoteflag;                  /* set if (part of) last token was quoted */
    569 static int startlinno;                 /* line # where last token started */
    570 
    571 static union node *parsecmd(int);
    572 static void fixredir(union node *, const char *, int);
    573 static const char *const *findkwd(const char *);
    574 static char *endofname(const char *);
    575 
    576 /*      shell.h   */
    577 
    578 typedef void *pointer;
    579 
    580 static char nullstr[1];                /* zero length string */
    581 static const char spcstr[] = " ";
    582 static const char snlfmt[] = "%s\n";
    583 static const char dolatstr[] = { CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' };
    584 static const char illnum[] = "Illegal number: %s";
    585 static const char homestr[] = "HOME";
    586 
    587 #ifdef DEBUG
    588 #define TRACE(param)    trace param
    589 #define TRACEV(param)   tracev param
     2157
     2158#if ENABLE_FEATURE_EDITING
     2159static line_input_t *line_input_state;
     2160static const char *cmdedit_prompt;
     2161static void
     2162putprompt(const char *s)
     2163{
     2164    if (ENABLE_ASH_EXPAND_PRMT) {
     2165        free((char*)cmdedit_prompt);
     2166        cmdedit_prompt = ckstrdup(s);
     2167        return;
     2168    }
     2169    cmdedit_prompt = s;
     2170}
    5902171#else
    591 #define TRACE(param)
    592 #define TRACEV(param)
    593 #endif
    594 
    595 #if !defined(__GNUC__) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
    596 #define __builtin_expect(x, expected_value) (x)
    597 #endif
    598 
    599 #define xlikely(x)       __builtin_expect((x),1)
    600 
    601 
    602 #define TEOF 0
    603 #define TNL 1
    604 #define TREDIR 2
    605 #define TWORD 3
    606 #define TSEMI 4
    607 #define TBACKGND 5
    608 #define TAND 6
    609 #define TOR 7
    610 #define TPIPE 8
    611 #define TLP 9
    612 #define TRP 10
    613 #define TENDCASE 11
    614 #define TENDBQUOTE 12
    615 #define TNOT 13
    616 #define TCASE 14
    617 #define TDO 15
    618 #define TDONE 16
    619 #define TELIF 17
    620 #define TELSE 18
    621 #define TESAC 19
    622 #define TFI 20
    623 #define TFOR 21
    624 #define TIF 22
    625 #define TIN 23
    626 #define TTHEN 24
    627 #define TUNTIL 25
    628 #define TWHILE 26
    629 #define TBEGIN 27
    630 #define TEND 28
    631 
    632 /* first char is indicating which tokens mark the end of a list */
    633 static const char *const tokname_array[] = {
    634     "\1end of file",
    635     "\0newline",
    636     "\0redirection",
    637     "\0word",
    638     "\0;",
    639     "\0&",
    640     "\0&&",
    641     "\0||",
    642     "\0|",
    643     "\0(",
    644     "\1)",
    645     "\1;;",
    646     "\1`",
    647 #define KWDOFFSET 13
    648     /* the following are keywords */
    649     "\0!",
    650     "\0case",
    651     "\1do",
    652     "\1done",
    653     "\1elif",
    654     "\1else",
    655     "\1esac",
    656     "\1fi",
    657     "\0for",
    658     "\0if",
    659     "\0in",
    660     "\1then",
    661     "\0until",
    662     "\0while",
    663     "\0{",
    664     "\1}",
    665 };
    666 
    667 static const char *tokname(int tok)
    668 {
    669     static char buf[16];
    670 
    671     if (tok >= TSEMI)
    672         buf[0] = '"';
    673     sprintf(buf + (tok >= TSEMI), "%s%c",
    674             tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0));
    675     return buf;
    676 }
    677 
    678 /*      machdep.h    */
    679 
    680 /*
    681  * Most machines require the value returned from malloc to be aligned
    682  * in some way.  The following macro will get this right on many machines.
    683  */
    684 
    685 #define SHELL_SIZE (sizeof(union {int i; char *cp; double d; }) - 1)
    686 /*
    687  * It appears that grabstackstr() will barf with such alignments
    688  * because stalloc() will return a string allocated in a new stackblock.
    689  */
    690 #define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
    691 
    692 /*
    693  * This file was generated by the mksyntax program.
    694  */
    695 
     2172static void
     2173putprompt(const char *s)
     2174{
     2175    out2str(s);
     2176}
     2177#endif
     2178
     2179#if ENABLE_ASH_EXPAND_PRMT
     2180/* expandstr() needs parsing machinery, so it is far away ahead... */
     2181static const char *expandstr(const char *ps);
     2182#else
     2183#define expandstr(s) s
     2184#endif
     2185
     2186static void
     2187setprompt(int whichprompt)
     2188{
     2189    const char *prompt;
     2190#if ENABLE_ASH_EXPAND_PRMT
     2191    struct stackmark smark;
     2192#endif
     2193
     2194    needprompt = 0;
     2195
     2196    switch (whichprompt) {
     2197    case 1:
     2198        prompt = ps1val();
     2199        break;
     2200    case 2:
     2201        prompt = ps2val();
     2202        break;
     2203    default:                        /* 0 */
     2204        prompt = nullstr;
     2205    }
     2206#if ENABLE_ASH_EXPAND_PRMT
     2207    setstackmark(&smark);
     2208    stalloc(stackblocksize());
     2209#endif
     2210    putprompt(expandstr(prompt));
     2211#if ENABLE_ASH_EXPAND_PRMT
     2212    popstackmark(&smark);
     2213#endif
     2214}
     2215
     2216
     2217/* ============ The cd and pwd commands */
     2218
     2219#define CD_PHYSICAL 1
     2220#define CD_PRINT 2
     2221
     2222static int docd(const char *, int);
     2223
     2224static char *curdir = nullstr;          /* current working directory */
     2225static char *physdir = nullstr;         /* physical working directory */
     2226
     2227static int
     2228cdopt(void)
     2229{
     2230    int flags = 0;
     2231    int i, j;
     2232
     2233    j = 'L';
     2234    while ((i = nextopt("LP"))) {
     2235        if (i != j) {
     2236            flags ^= CD_PHYSICAL;
     2237            j = i;
     2238        }
     2239    }
     2240
     2241    return flags;
     2242}
     2243
     2244/*
     2245 * Update curdir (the name of the current directory) in response to a
     2246 * cd command.
     2247 */
     2248static const char *
     2249updatepwd(const char *dir)
     2250{
     2251    char *new;
     2252    char *p;
     2253    char *cdcomppath;
     2254    const char *lim;
     2255
     2256    cdcomppath = ststrdup(dir);
     2257    STARTSTACKSTR(new);
     2258    if (*dir != '/') {
     2259        if (curdir == nullstr)
     2260            return 0;
     2261        new = stack_putstr(curdir, new);
     2262    }
     2263    new = makestrspace(strlen(dir) + 2, new);
     2264    lim = stackblock() + 1;
     2265    if (*dir != '/') {
     2266        if (new[-1] != '/')
     2267            USTPUTC('/', new);
     2268        if (new > lim && *lim == '/')
     2269            lim++;
     2270    } else {
     2271        USTPUTC('/', new);
     2272        cdcomppath++;
     2273        if (dir[1] == '/' && dir[2] != '/') {
     2274            USTPUTC('/', new);
     2275            cdcomppath++;
     2276            lim++;
     2277        }
     2278    }
     2279    p = strtok(cdcomppath, "/");
     2280    while (p) {
     2281        switch (*p) {
     2282        case '.':
     2283            if (p[1] == '.' && p[2] == '\0') {
     2284                while (new > lim) {
     2285                    STUNPUTC(new);
     2286                    if (new[-1] == '/')
     2287                        break;
     2288                }
     2289                break;
     2290            }
     2291            if (p[1] == '\0')
     2292                break;
     2293            /* fall through */
     2294        default:
     2295            new = stack_putstr(p, new);
     2296            USTPUTC('/', new);
     2297        }
     2298        p = strtok(0, "/");
     2299    }
     2300    if (new > lim)
     2301        STUNPUTC(new);
     2302    *new = 0;
     2303    return stackblock();
     2304}
     2305
     2306/*
     2307 * Find out what the current directory is. If we already know the current
     2308 * directory, this routine returns immediately.
     2309 */
     2310static char *
     2311getpwd(void)
     2312{
     2313    char *dir = getcwd(0, 0);
     2314    return dir ? dir : nullstr;
     2315}
     2316
     2317static void
     2318setpwd(const char *val, int setold)
     2319{
     2320    char *oldcur, *dir;
     2321
     2322    oldcur = dir = curdir;
     2323
     2324    if (setold) {
     2325        setvar("OLDPWD", oldcur, VEXPORT);
     2326    }
     2327    INT_OFF;
     2328    if (physdir != nullstr) {
     2329        if (physdir != oldcur)
     2330            free(physdir);
     2331        physdir = nullstr;
     2332    }
     2333    if (oldcur == val || !val) {
     2334        char *s = getpwd();
     2335        physdir = s;
     2336        if (!val)
     2337            dir = s;
     2338    } else
     2339        dir = ckstrdup(val);
     2340    if (oldcur != dir && oldcur != nullstr) {
     2341        free(oldcur);
     2342    }
     2343    curdir = dir;
     2344    INT_ON;
     2345    setvar("PWD", dir, VEXPORT);
     2346}
     2347
     2348static void hashcd(void);
     2349
     2350/*
     2351 * Actually do the chdir.  We also call hashcd to let the routines in exec.c
     2352 * know that the current directory has changed.
     2353 */
     2354static int
     2355docd(const char *dest, int flags)
     2356{
     2357    const char *dir = 0;
     2358    int err;
     2359
     2360    TRACE(("docd(\"%s\", %d) called\n", dest, flags));
     2361
     2362    INT_OFF;
     2363    if (!(flags & CD_PHYSICAL)) {
     2364        dir = updatepwd(dest);
     2365        if (dir)
     2366            dest = dir;
     2367    }
     2368    err = chdir(dest);
     2369    if (err)
     2370        goto out;
     2371    setpwd(dir, 1);
     2372    hashcd();
     2373 out:
     2374    INT_ON;
     2375    return err;
     2376}
     2377
     2378static int
     2379cdcmd(int argc, char **argv)
     2380{
     2381    const char *dest;
     2382    const char *path;
     2383    const char *p;
     2384    char c;
     2385    struct stat statb;
     2386    int flags;
     2387
     2388    flags = cdopt();
     2389    dest = *argptr;
     2390    if (!dest)
     2391        dest = bltinlookup(homestr);
     2392    else if (LONE_DASH(dest)) {
     2393        dest = bltinlookup("OLDPWD");
     2394        flags |= CD_PRINT;
     2395    }
     2396    if (!dest)
     2397        dest = nullstr;
     2398    if (*dest == '/')
     2399        goto step7;
     2400    if (*dest == '.') {
     2401        c = dest[1];
     2402 dotdot:
     2403        switch (c) {
     2404        case '\0':
     2405        case '/':
     2406            goto step6;
     2407        case '.':
     2408            c = dest[2];
     2409            if (c != '.')
     2410                goto dotdot;
     2411        }
     2412    }
     2413    if (!*dest)
     2414        dest = ".";
     2415    path = bltinlookup("CDPATH");
     2416    if (!path) {
     2417 step6:
     2418 step7:
     2419        p = dest;
     2420        goto docd;
     2421    }
     2422    do {
     2423        c = *path;
     2424        p = padvance(&path, dest);
     2425        if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
     2426            if (c && c != ':')
     2427                flags |= CD_PRINT;
     2428 docd:
     2429            if (!docd(p, flags))
     2430                goto out;
     2431            break;
     2432        }
     2433    } while (path);
     2434    ash_msg_and_raise_error("can't cd to %s", dest);
     2435    /* NOTREACHED */
     2436 out:
     2437    if (flags & CD_PRINT)
     2438        out1fmt(snlfmt, curdir);
     2439    return 0;
     2440}
     2441
     2442static int
     2443pwdcmd(int argc, char **argv)
     2444{
     2445    int flags;
     2446    const char *dir = curdir;
     2447
     2448    flags = cdopt();
     2449    if (flags) {
     2450        if (physdir == nullstr)
     2451            setpwd(dir, 0);
     2452        dir = physdir;
     2453    }
     2454    out1fmt(snlfmt, dir);
     2455    return 0;
     2456}
     2457
     2458
     2459/* ============ ... */
     2460
     2461#define IBUFSIZ (BUFSIZ + 1)
     2462#define basebuf bb_common_bufsiz1       /* buffer for top level input file */
    6962463
    6972464/* Syntax classes */
     
    7122479#define CIGN 14                 /* character should be ignored */
    7132480
    714 #ifdef CONFIG_ASH_ALIAS
     2481#if ENABLE_ASH_ALIAS
    7152482#define SYNBASE 130
    7162483#define PEOF -130
     
    7232490#endif
    7242491
    725 #define is_digit(c)     ((unsigned)((c) - '0') <= 9)
    726 #define is_name(c)      ((c) == '_' || isalpha((unsigned char)(c)))
    727 #define is_in_name(c)   ((c) == '_' || isalnum((unsigned char)(c)))
    728 
    729 /* C99 say: "char" declaration may be signed or unsigned default */
    730 #define SC2INT(chr2may_be_negative_int) (int)((signed char)chr2may_be_negative_int)
    731 
    732 /*
    733  * is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
    734  * (assuming ascii char codes, as the original implementation did)
    735  */
    736 #define is_special(c) \
    737     ( (((unsigned int)c) - 33 < 32) \
    738              && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1))
    739 
    740 #define digit_val(c)    ((c) - '0')
    741 
    742 /*
    743  * This file was generated by the mksyntax program.
    744  */
    745 
    746 #ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
     2492/* number syntax index */
     2493#define BASESYNTAX 0    /* not in quotes */
     2494#define DQSYNTAX   1    /* in double quotes */
     2495#define SQSYNTAX   2    /* in single quotes */
     2496#define ARISYNTAX  3    /* in arithmetic */
     2497
     2498#if ENABLE_ASH_OPTIMIZE_FOR_SIZE
    7472499#define USE_SIT_FUNCTION
    7482500#endif
    7492501
    750 /* number syntax index */
    751 #define  BASESYNTAX  0  /* not in quotes */
    752 #define  DQSYNTAX    1  /* in double quotes */
    753 #define  SQSYNTAX    2  /* in single quotes */
    754 #define  ARISYNTAX   3  /* in arithmetic */
    755 
    756 #ifdef CONFIG_ASH_MATH_SUPPORT
     2502#if ENABLE_ASH_MATH_SUPPORT
    7572503static const char S_I_T[][4] = {
    758 #ifdef CONFIG_ASH_ALIAS
    759     {CSPCL, CIGN, CIGN, CIGN},              /* 0, PEOA */
    760 #endif
    761     {CSPCL, CWORD, CWORD, CWORD},           /* 1, ' ' */
    762     {CNL, CNL, CNL, CNL},                   /* 2, \n */
    763     {CWORD, CCTL, CCTL, CWORD},             /* 3, !*-/:=?[]~ */
    764     {CDQUOTE, CENDQUOTE, CWORD, CWORD},     /* 4, '"' */
    765     {CVAR, CVAR, CWORD, CVAR},              /* 5, $ */
    766     {CSQUOTE, CWORD, CENDQUOTE, CWORD},     /* 6, "'" */
    767     {CSPCL, CWORD, CWORD, CLP},             /* 7, ( */
    768     {CSPCL, CWORD, CWORD, CRP},             /* 8, ) */
    769     {CBACK, CBACK, CCTL, CBACK},            /* 9, \ */
    770     {CBQUOTE, CBQUOTE, CWORD, CBQUOTE},     /* 10, ` */
    771     {CENDVAR, CENDVAR, CWORD, CENDVAR},     /* 11, } */
     2504#if ENABLE_ASH_ALIAS
     2505    { CSPCL, CIGN, CIGN, CIGN },            /* 0, PEOA */
     2506#endif
     2507    { CSPCL, CWORD, CWORD, CWORD },         /* 1, ' ' */
     2508    { CNL, CNL, CNL, CNL },                 /* 2, \n */
     2509    { CWORD, CCTL, CCTL, CWORD },           /* 3, !*-/:=?[]~ */
     2510    { CDQUOTE, CENDQUOTE, CWORD, CWORD },   /* 4, '"' */
     2511    { CVAR, CVAR, CWORD, CVAR },            /* 5, $ */
     2512    { CSQUOTE, CWORD, CENDQUOTE, CWORD },   /* 6, "'" */
     2513    { CSPCL, CWORD, CWORD, CLP },           /* 7, ( */
     2514    { CSPCL, CWORD, CWORD, CRP },           /* 8, ) */
     2515    { CBACK, CBACK, CCTL, CBACK },          /* 9, \ */
     2516    { CBQUOTE, CBQUOTE, CWORD, CBQUOTE },   /* 10, ` */
     2517    { CENDVAR, CENDVAR, CWORD, CENDVAR },   /* 11, } */
    7722518#ifndef USE_SIT_FUNCTION
    773     {CENDFILE, CENDFILE, CENDFILE, CENDFILE},      /* 12, PEOF */
    774     {CWORD, CWORD, CWORD, CWORD},           /* 13, 0-9A-Za-z */
    775     {CCTL, CCTL, CCTL, CCTL}                /* 14, CTLESC ... */
     2519    { CENDFILE, CENDFILE, CENDFILE, CENDFILE }, /* 12, PEOF */
     2520    { CWORD, CWORD, CWORD, CWORD },         /* 13, 0-9A-Za-z */
     2521    { CCTL, CCTL, CCTL, CCTL }              /* 14, CTLESC ... */
    7762522#endif
    7772523};
    7782524#else
    7792525static const char S_I_T[][3] = {
    780 #ifdef CONFIG_ASH_ALIAS
    781     {CSPCL, CIGN, CIGN},                    /* 0, PEOA */
    782 #endif
    783     {CSPCL, CWORD, CWORD},                  /* 1, ' ' */
    784     {CNL, CNL, CNL},                        /* 2, \n */
    785     {CWORD, CCTL, CCTL},                    /* 3, !*-/:=?[]~ */
    786     {CDQUOTE, CENDQUOTE, CWORD},            /* 4, '"' */
    787     {CVAR, CVAR, CWORD},                    /* 5, $ */
    788     {CSQUOTE, CWORD, CENDQUOTE},            /* 6, "'" */
    789     {CSPCL, CWORD, CWORD},                  /* 7, ( */
    790     {CSPCL, CWORD, CWORD},                  /* 8, ) */
    791     {CBACK, CBACK, CCTL},                   /* 9, \ */
    792     {CBQUOTE, CBQUOTE, CWORD},              /* 10, ` */
    793     {CENDVAR, CENDVAR, CWORD},              /* 11, } */
     2526#if ENABLE_ASH_ALIAS
     2527    { CSPCL, CIGN, CIGN },                  /* 0, PEOA */
     2528#endif
     2529    { CSPCL, CWORD, CWORD },                /* 1, ' ' */
     2530    { CNL, CNL, CNL },                      /* 2, \n */
     2531    { CWORD, CCTL, CCTL },                  /* 3, !*-/:=?[]~ */
     2532    { CDQUOTE, CENDQUOTE, CWORD },          /* 4, '"' */
     2533    { CVAR, CVAR, CWORD },                  /* 5, $ */
     2534    { CSQUOTE, CWORD, CENDQUOTE },          /* 6, "'" */
     2535    { CSPCL, CWORD, CWORD },                /* 7, ( */
     2536    { CSPCL, CWORD, CWORD },                /* 8, ) */
     2537    { CBACK, CBACK, CCTL },                 /* 9, \ */
     2538    { CBQUOTE, CBQUOTE, CWORD },            /* 10, ` */
     2539    { CENDVAR, CENDVAR, CWORD },            /* 11, } */
    7942540#ifndef USE_SIT_FUNCTION
    795     {CENDFILE, CENDFILE, CENDFILE},         /* 12, PEOF */
    796     {CWORD, CWORD, CWORD},                  /* 13, 0-9A-Za-z */
    797     {CCTL, CCTL, CCTL}                      /* 14, CTLESC ... */
     2541    { CENDFILE, CENDFILE, CENDFILE },       /* 12, PEOF */
     2542    { CWORD, CWORD, CWORD },                /* 13, 0-9A-Za-z */
     2543    { CCTL, CCTL, CCTL }                    /* 14, CTLESC ... */
    7982544#endif
    7992545};
    800 #endif /* CONFIG_ASH_MATH_SUPPORT */
     2546#endif /* ASH_MATH_SUPPORT */
    8012547
    8022548#ifdef USE_SIT_FUNCTION
    8032549
    804 #define U_C(c) ((unsigned char)(c))
    805 
    806 static int SIT(int c, int syntax)
    807 {
    808     static const char spec_symbls[] = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
    809 #ifdef CONFIG_ASH_ALIAS
    810     static const char syntax_index_table[] = {
     2550static int
     2551SIT(int c, int syntax)
     2552{
     2553    static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
     2554#if ENABLE_ASH_ALIAS
     2555    static const char syntax_index_table[] ALIGN1 = {
    8112556        1, 2, 1, 3, 4, 5, 1, 6,         /* "\t\n !\"$&'" */
    8122557        7, 8, 3, 3, 3, 3, 1, 1,         /* "()*-/:;<" */
     
    8152560    };
    8162561#else
    817     static const char syntax_index_table[] = {
     2562    static const char syntax_index_table[] ALIGN1 = {
    8182563        0, 1, 0, 2, 3, 4, 0, 5,         /* "\t\n !\"$&'" */
    8192564        6, 7, 2, 2, 2, 2, 0, 0,         /* "()*-/:;<" */
     
    8272572    if (c == PEOF)          /* 2^8+2 */
    8282573        return CENDFILE;
    829 #ifdef CONFIG_ASH_ALIAS
     2574#if ENABLE_ASH_ALIAS
    8302575    if (c == PEOA)          /* 2^8+1 */
    8312576        indx = 0;
    8322577    else
    8332578#endif
    834         if (U_C(c) >= U_C(CTLESC) && U_C(c) <= U_C(CTLQUOTEMARK))
    835             return CCTL;
    836     else {
     2579#define U_C(c) ((unsigned char)(c))
     2580
     2581    if ((unsigned char)c >= (unsigned char)(CTLESC)
     2582     && (unsigned char)c <= (unsigned char)(CTLQUOTEMARK)
     2583    ) {
     2584        return CCTL;
     2585    } else {
    8372586        s = strchr(spec_symbls, c);
    838         if (s == 0 || *s == 0)
     2587        if (s == NULL || *s == '\0')
    8392588            return CWORD;
    8402589        indx = syntax_index_table[(s - spec_symbls)];
     
    8432592}
    8442593
    845 #else   /* USE_SIT_FUNCTION */
    846 
    847 #define SIT(c, syntax) S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax]
    848 
    849 #ifdef CONFIG_ASH_ALIAS
    850 #define CSPCL_CIGN_CIGN_CIGN                           0
    851 #define CSPCL_CWORD_CWORD_CWORD                        1
    852 #define CNL_CNL_CNL_CNL                                2
    853 #define CWORD_CCTL_CCTL_CWORD                          3
    854 #define CDQUOTE_CENDQUOTE_CWORD_CWORD                  4
    855 #define CVAR_CVAR_CWORD_CVAR                           5
    856 #define CSQUOTE_CWORD_CENDQUOTE_CWORD                  6
    857 #define CSPCL_CWORD_CWORD_CLP                          7
    858 #define CSPCL_CWORD_CWORD_CRP                          8
    859 #define CBACK_CBACK_CCTL_CBACK                         9
    860 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE                 10
    861 #define CENDVAR_CENDVAR_CWORD_CENDVAR                 11
    862 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE           12
    863 #define CWORD_CWORD_CWORD_CWORD                       13
    864 #define CCTL_CCTL_CCTL_CCTL                           14
     2594#else   /* !USE_SIT_FUNCTION */
     2595
     2596#if ENABLE_ASH_ALIAS
     2597#define CSPCL_CIGN_CIGN_CIGN                     0
     2598#define CSPCL_CWORD_CWORD_CWORD                  1
     2599#define CNL_CNL_CNL_CNL                          2
     2600#define CWORD_CCTL_CCTL_CWORD                    3
     2601#define CDQUOTE_CENDQUOTE_CWORD_CWORD            4
     2602#define CVAR_CVAR_CWORD_CVAR                     5
     2603#define CSQUOTE_CWORD_CENDQUOTE_CWORD            6
     2604#define CSPCL_CWORD_CWORD_CLP                    7
     2605#define CSPCL_CWORD_CWORD_CRP                    8
     2606#define CBACK_CBACK_CCTL_CBACK                   9
     2607#define CBQUOTE_CBQUOTE_CWORD_CBQUOTE           10
     2608#define CENDVAR_CENDVAR_CWORD_CENDVAR           11
     2609#define CENDFILE_CENDFILE_CENDFILE_CENDFILE     12
     2610#define CWORD_CWORD_CWORD_CWORD                 13
     2611#define CCTL_CCTL_CCTL_CCTL                     14
    8652612#else
    866 #define CSPCL_CWORD_CWORD_CWORD                        0
    867 #define CNL_CNL_CNL_CNL                                1
    868 #define CWORD_CCTL_CCTL_CWORD                          2
    869 #define CDQUOTE_CENDQUOTE_CWORD_CWORD                  3
    870 #define CVAR_CVAR_CWORD_CVAR                           4
    871 #define CSQUOTE_CWORD_CENDQUOTE_CWORD                  5
    872 #define CSPCL_CWORD_CWORD_CLP                          6
    873 #define CSPCL_CWORD_CWORD_CRP                          7
    874 #define CBACK_CBACK_CCTL_CBACK                         8
    875 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE                  9
    876 #define CENDVAR_CENDVAR_CWORD_CENDVAR                 10
    877 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE           11
    878 #define CWORD_CWORD_CWORD_CWORD                       12
    879 #define CCTL_CCTL_CCTL_CCTL                           13
     2613#define CSPCL_CWORD_CWORD_CWORD                  0
     2614#define CNL_CNL_CNL_CNL                          1
     2615#define CWORD_CCTL_CCTL_CWORD                    2
     2616#define CDQUOTE_CENDQUOTE_CWORD_CWORD            3
     2617#define CVAR_CVAR_CWORD_CVAR                     4
     2618#define CSQUOTE_CWORD_CENDQUOTE_CWORD            5
     2619#define CSPCL_CWORD_CWORD_CLP                    6
     2620#define CSPCL_CWORD_CWORD_CRP                    7
     2621#define CBACK_CBACK_CCTL_CBACK                   8
     2622#define CBQUOTE_CBQUOTE_CWORD_CBQUOTE            9
     2623#define CENDVAR_CENDVAR_CWORD_CENDVAR           10
     2624#define CENDFILE_CENDFILE_CENDFILE_CENDFILE     11
     2625#define CWORD_CWORD_CWORD_CWORD                 12
     2626#define CCTL_CCTL_CCTL_CCTL                     13
    8802627#endif
    8812628
     
    8832630    /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
    8842631    /*   0  PEOF */      CENDFILE_CENDFILE_CENDFILE_CENDFILE,
    885 #ifdef CONFIG_ASH_ALIAS
     2632#if ENABLE_ASH_ALIAS
    8862633    /*   1  PEOA */      CSPCL_CIGN_CIGN_CIGN,
    8872634#endif
     
    11442891};
    11452892
     2893#define SIT(c, syntax) (S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax])
     2894
    11462895#endif  /* USE_SIT_FUNCTION */
    11472896
    1148 /*      alias.c      */
    1149 
     2897
     2898/* ============ Alias handling */
     2899
     2900#if ENABLE_ASH_ALIAS
     2901
     2902#define ALIASINUSE 1
     2903#define ALIASDEAD  2
    11502904
    11512905#define ATABSIZE 39
    11522906
    1153 static int     funcblocksize;          /* size of structures in function */
    1154 static int     funcstringsize;         /* size of strings in node */
    1155 static pointer funcblock;              /* block to allocate function from */
    1156 static char   *funcstring;             /* block to allocate strings from */
    1157 
    1158 static const short nodesize[26] = {
    1159       SHELL_ALIGN(sizeof (struct ncmd)),
    1160       SHELL_ALIGN(sizeof (struct npipe)),
    1161       SHELL_ALIGN(sizeof (struct nredir)),
    1162       SHELL_ALIGN(sizeof (struct nredir)),
    1163       SHELL_ALIGN(sizeof (struct nredir)),
    1164       SHELL_ALIGN(sizeof (struct nbinary)),
    1165       SHELL_ALIGN(sizeof (struct nbinary)),
    1166       SHELL_ALIGN(sizeof (struct nbinary)),
    1167       SHELL_ALIGN(sizeof (struct nif)),
    1168       SHELL_ALIGN(sizeof (struct nbinary)),
    1169       SHELL_ALIGN(sizeof (struct nbinary)),
    1170       SHELL_ALIGN(sizeof (struct nfor)),
    1171       SHELL_ALIGN(sizeof (struct ncase)),
    1172       SHELL_ALIGN(sizeof (struct nclist)),
    1173       SHELL_ALIGN(sizeof (struct narg)),
    1174       SHELL_ALIGN(sizeof (struct narg)),
    1175       SHELL_ALIGN(sizeof (struct nfile)),
    1176       SHELL_ALIGN(sizeof (struct nfile)),
    1177       SHELL_ALIGN(sizeof (struct nfile)),
    1178       SHELL_ALIGN(sizeof (struct nfile)),
    1179       SHELL_ALIGN(sizeof (struct nfile)),
    1180       SHELL_ALIGN(sizeof (struct ndup)),
    1181       SHELL_ALIGN(sizeof (struct ndup)),
    1182       SHELL_ALIGN(sizeof (struct nhere)),
    1183       SHELL_ALIGN(sizeof (struct nhere)),
    1184       SHELL_ALIGN(sizeof (struct nnot)),
     2907struct alias {
     2908    struct alias *next;
     2909    char *name;
     2910    char *val;
     2911    int flag;
    11852912};
    11862913
    1187 
    1188 static void calcsize(union node *);
    1189 static void sizenodelist(struct nodelist *);
    1190 static union node *copynode(union node *);
    1191 static struct nodelist *copynodelist(struct nodelist *);
    1192 static char *nodesavestr(char *);
    1193 
    1194 
    1195 static int evalstring(char *, int mask);
    1196 union node;     /* BLETCH for ansi C */
    1197 static void evaltree(union node *, int);
    1198 static void evalbackcmd(union node *, struct backcmd *);
    1199 
    1200 static int evalskip;                   /* set if we are skipping commands */
    1201 static int skipcount;           /* number of levels to skip */
    1202 static int funcnest;                   /* depth of function calls */
    1203 
    1204 /* reasons for skipping commands (see comment on breakcmd routine) */
    1205 #define SKIPBREAK      (1 << 0)
    1206 #define SKIPCONT       (1 << 1)
    1207 #define SKIPFUNC       (1 << 2)
    1208 #define SKIPFILE       (1 << 3)
    1209 #define SKIPEVAL       (1 << 4)
    1210 
    1211 /*
    1212  * This file was generated by the mkbuiltins program.
    1213  */
    1214 
    1215 #if JOBS
    1216 static int bgcmd(int, char **);
    1217 #endif
    1218 static int breakcmd(int, char **);
    1219 static int cdcmd(int, char **);
    1220 #ifdef CONFIG_ASH_CMDCMD
    1221 static int commandcmd(int, char **);
    1222 #endif
    1223 static int dotcmd(int, char **);
    1224 static int evalcmd(int, char **);
    1225 #ifdef CONFIG_ASH_BUILTIN_ECHO
    1226 static int echocmd(int, char **);
    1227 #endif
    1228 #ifdef CONFIG_ASH_BUILTIN_TEST
    1229 static int testcmd(int, char **);
    1230 #endif
    1231 static int execcmd(int, char **);
    1232 static int exitcmd(int, char **);
    1233 static int exportcmd(int, char **);
    1234 static int falsecmd(int, char **);
    1235 #if JOBS
    1236 static int fgcmd(int, char **);
    1237 #endif
    1238 #ifdef CONFIG_ASH_GETOPTS
    1239 static int getoptscmd(int, char **);
    1240 #endif
    1241 static int hashcmd(int, char **);
    1242 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
    1243 static int helpcmd(int argc, char **argv);
    1244 #endif
    1245 #if JOBS
    1246 static int jobscmd(int, char **);
    1247 #endif
    1248 #ifdef CONFIG_ASH_MATH_SUPPORT
    1249 static int letcmd(int, char **);
    1250 #endif
    1251 static int localcmd(int, char **);
    1252 static int pwdcmd(int, char **);
    1253 static int readcmd(int, char **);
    1254 static int returncmd(int, char **);
    1255 static int setcmd(int, char **);
    1256 static int shiftcmd(int, char **);
    1257 static int timescmd(int, char **);
    1258 static int trapcmd(int, char **);
    1259 static int truecmd(int, char **);
    1260 static int typecmd(int, char **);
    1261 static int umaskcmd(int, char **);
    1262 static int unsetcmd(int, char **);
    1263 static int waitcmd(int, char **);
    1264 static int ulimitcmd(int, char **);
    1265 #if JOBS
    1266 static int killcmd(int, char **);
    1267 #endif
    1268 
    1269 /*      mail.h        */
    1270 
    1271 #ifdef CONFIG_ASH_MAIL
    1272 static void chkmail(void);
    1273 static void changemail(const char *);
    1274 #endif
    1275 
    1276 /*      exec.h    */
    1277 
    1278 /* values of cmdtype */
    1279 #define CMDUNKNOWN      -1      /* no entry in table for command */
    1280 #define CMDNORMAL       0       /* command is an executable program */
    1281 #define CMDFUNCTION     1       /* command is a shell function */
    1282 #define CMDBUILTIN      2       /* command is a shell builtin */
    1283 
    1284 struct builtincmd {
    1285     const char *name;
    1286     int (*builtin)(int, char **);
    1287     /* unsigned flags; */
    1288 };
    1289 
    1290 
    1291 #define COMMANDCMD (builtincmd + 5 + \
    1292     2 * ENABLE_ASH_BUILTIN_TEST + \
    1293     ENABLE_ASH_ALIAS + \
    1294     ENABLE_ASH_JOB_CONTROL)
    1295 #define EXECCMD (builtincmd + 7 + \
    1296     2 * ENABLE_ASH_BUILTIN_TEST + \
    1297     ENABLE_ASH_ALIAS + \
    1298     ENABLE_ASH_JOB_CONTROL + \
    1299     ENABLE_ASH_CMDCMD + \
    1300     ENABLE_ASH_BUILTIN_ECHO)
    1301 
    1302 #define BUILTIN_NOSPEC  "0"
    1303 #define BUILTIN_SPECIAL "1"
    1304 #define BUILTIN_REGULAR "2"
    1305 #define BUILTIN_SPEC_REG "3"
    1306 #define BUILTIN_ASSIGN  "4"
    1307 #define BUILTIN_SPEC_ASSG  "5"
    1308 #define BUILTIN_REG_ASSG   "6"
    1309 #define BUILTIN_SPEC_REG_ASSG   "7"
    1310 
    1311 #define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
    1312 #define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
    1313 #define IS_BUILTIN_ASSIGN(builtincmd) ((builtincmd)->name[0] & 4)
    1314 
    1315 /* make sure to keep these in proper order since it is searched via bsearch() */
    1316 static const struct builtincmd builtincmd[] = {
    1317     { BUILTIN_SPEC_REG      ".", dotcmd },
    1318     { BUILTIN_SPEC_REG      ":", truecmd },
    1319 #ifdef CONFIG_ASH_BUILTIN_TEST
    1320     { BUILTIN_REGULAR   "[", testcmd },
    1321     { BUILTIN_REGULAR   "[[", testcmd },
    1322 #endif
    1323 #ifdef CONFIG_ASH_ALIAS
    1324     { BUILTIN_REG_ASSG      "alias", aliascmd },
    1325 #endif
    1326 #if JOBS
    1327     { BUILTIN_REGULAR       "bg", bgcmd },
    1328 #endif
    1329     { BUILTIN_SPEC_REG      "break", breakcmd },
    1330     { BUILTIN_REGULAR       "cd", cdcmd },
    1331     { BUILTIN_NOSPEC        "chdir", cdcmd },
    1332 #ifdef CONFIG_ASH_CMDCMD
    1333     { BUILTIN_REGULAR       "command", commandcmd },
    1334 #endif
    1335     { BUILTIN_SPEC_REG      "continue", breakcmd },
    1336 #ifdef CONFIG_ASH_BUILTIN_ECHO
    1337     { BUILTIN_REGULAR       "echo", echocmd },
    1338 #endif
    1339     { BUILTIN_SPEC_REG      "eval", evalcmd },
    1340     { BUILTIN_SPEC_REG      "exec", execcmd },
    1341     { BUILTIN_SPEC_REG      "exit", exitcmd },
    1342     { BUILTIN_SPEC_REG_ASSG "export", exportcmd },
    1343     { BUILTIN_REGULAR       "false", falsecmd },
    1344 #if JOBS
    1345     { BUILTIN_REGULAR       "fg", fgcmd },
    1346 #endif
    1347 #ifdef CONFIG_ASH_GETOPTS
    1348     { BUILTIN_REGULAR       "getopts", getoptscmd },
    1349 #endif
    1350     { BUILTIN_NOSPEC        "hash", hashcmd },
    1351 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
    1352     { BUILTIN_NOSPEC        "help", helpcmd },
    1353 #endif
    1354 #if JOBS
    1355     { BUILTIN_REGULAR       "jobs", jobscmd },
    1356     { BUILTIN_REGULAR       "kill", killcmd },
    1357 #endif
    1358 #ifdef CONFIG_ASH_MATH_SUPPORT
    1359     { BUILTIN_NOSPEC        "let", letcmd },
    1360 #endif
    1361     { BUILTIN_ASSIGN        "local", localcmd },
    1362     { BUILTIN_NOSPEC        "pwd", pwdcmd },
    1363     { BUILTIN_REGULAR       "read", readcmd },
    1364     { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
    1365     { BUILTIN_SPEC_REG      "return", returncmd },
    1366     { BUILTIN_SPEC_REG      "set", setcmd },
    1367     { BUILTIN_SPEC_REG      "shift", shiftcmd },
    1368     { BUILTIN_SPEC_REG      "source", dotcmd },
    1369 #ifdef CONFIG_ASH_BUILTIN_TEST
    1370     { BUILTIN_REGULAR   "test", testcmd },
    1371 #endif
    1372     { BUILTIN_SPEC_REG      "times", timescmd },
    1373     { BUILTIN_SPEC_REG      "trap", trapcmd },
    1374     { BUILTIN_REGULAR       "true", truecmd },
    1375     { BUILTIN_NOSPEC        "type", typecmd },
    1376     { BUILTIN_NOSPEC        "ulimit", ulimitcmd },
    1377     { BUILTIN_REGULAR       "umask", umaskcmd },
    1378 #ifdef CONFIG_ASH_ALIAS
    1379     { BUILTIN_REGULAR       "unalias", unaliascmd },
    1380 #endif
    1381     { BUILTIN_SPEC_REG      "unset", unsetcmd },
    1382     { BUILTIN_REGULAR       "wait", waitcmd },
    1383 };
    1384 
    1385 #define NUMBUILTINS  (sizeof (builtincmd) / sizeof (struct builtincmd) )
    1386 
    1387 
    1388 
    1389 struct cmdentry {
    1390     int cmdtype;
    1391     union param {
    1392         int index;
    1393         const struct builtincmd *cmd;
    1394         struct funcnode *func;
    1395     } u;
    1396 };
    1397 
    1398 
    1399 /* action to find_command() */
    1400 #define DO_ERR          0x01    /* prints errors */
    1401 #define DO_ABS          0x02    /* checks absolute paths */
    1402 #define DO_NOFUNC       0x04    /* don't return shell functions, for command */
    1403 #define DO_ALTPATH      0x08    /* using alternate path */
    1404 #define DO_ALTBLTIN     0x20    /* %builtin in alt. path */
    1405 
    1406 static const char *pathopt;     /* set by padvance */
    1407 
    1408 static void shellexec(char **, const char *, int)
    1409     ATTRIBUTE_NORETURN;
    1410 static char *padvance(const char **, const char *);
    1411 static void find_command(char *, struct cmdentry *, int, const char *);
    1412 static struct builtincmd *find_builtin(const char *);
    1413 static void hashcd(void);
    1414 static void changepath(const char *);
    1415 static void defun(char *, union node *);
    1416 static void unsetfunc(const char *);
    1417 
    1418 #ifdef CONFIG_ASH_MATH_SUPPORT_64
    1419 typedef int64_t arith_t;
    1420 #define arith_t_type (long long)
    1421 #else
    1422 typedef long arith_t;
    1423 #define arith_t_type (long)
    1424 #endif
    1425 
    1426 #ifdef CONFIG_ASH_MATH_SUPPORT
    1427 static arith_t dash_arith(const char *);
    1428 static arith_t arith(const char *expr, int *perrcode);
    1429 #endif
    1430 
    1431 #ifdef CONFIG_ASH_RANDOM_SUPPORT
    1432 static unsigned long rseed;
    1433 static void change_random(const char *);
    1434 # ifndef DYNAMIC_VAR
    1435 #  define DYNAMIC_VAR
    1436 # endif
    1437 #endif
    1438 
    1439 /*      init.h        */
    1440 
    1441 static void reset(void);
    1442 
    1443 /*      var.h     */
    1444 
    1445 /*
    1446  * Shell variables.
    1447  */
    1448 
    1449 /* flags */
    1450 #define VEXPORT         0x01    /* variable is exported */
    1451 #define VREADONLY       0x02    /* variable cannot be modified */
    1452 #define VSTRFIXED       0x04    /* variable struct is statically allocated */
    1453 #define VTEXTFIXED      0x08    /* text is statically allocated */
    1454 #define VSTACK          0x10    /* text is allocated on the stack */
    1455 #define VUNSET          0x20    /* the variable is not set */
    1456 #define VNOFUNC         0x40    /* don't call the callback function */
    1457 #define VNOSET          0x80    /* do not set variable - just readonly test */
    1458 #define VNOSAVE         0x100   /* when text is on the heap before setvareq */
    1459 #ifdef DYNAMIC_VAR
    1460 # define VDYNAMIC        0x200   /* dynamic variable */
    1461 # else
    1462 # define VDYNAMIC        0
    1463 #endif
    1464 
    1465 struct var {
    1466     struct var *next;               /* next entry in hash list */
    1467     int flags;                      /* flags are defined above */
    1468     const char *text;               /* name=value */
    1469     void (*func)(const char *);     /* function to be called when  */
    1470                     /* the variable gets set/unset */
    1471 };
    1472 
    1473 struct localvar {
    1474     struct localvar *next;          /* next local variable in list */
    1475     struct var *vp;                 /* the variable that was made local */
    1476     int flags;                      /* saved flags */
    1477     const char *text;               /* saved text */
    1478 };
    1479 
    1480 
    1481 static struct localvar *localvars;
    1482 
    1483 /*
    1484  * Shell variables.
    1485  */
    1486 
    1487 #ifdef CONFIG_ASH_GETOPTS
    1488 static void getoptsreset(const char *);
    1489 #endif
    1490 
    1491 #ifdef CONFIG_LOCALE_SUPPORT
    1492 #include <locale.h>
    1493 static void change_lc_all(const char *value);
    1494 static void change_lc_ctype(const char *value);
    1495 #endif
    1496 
    1497 
    1498 #define VTABSIZE 39
    1499 
    1500 static const char defpathvar[] = "PATH=/usr/local/bin:/usr/bin:/sbin:/bin";
    1501 #ifdef IFS_BROKEN
    1502 static const char defifsvar[] = "IFS= \t\n";
    1503 #define defifs (defifsvar + 4)
    1504 #else
    1505 static const char defifs[] = " \t\n";
    1506 #endif
    1507 
    1508 
    1509 static struct var varinit[] = {
    1510 #ifdef IFS_BROKEN
    1511     { 0,    VSTRFIXED|VTEXTFIXED,           defifsvar,      0 },
    1512 #else
    1513     { 0,    VSTRFIXED|VTEXTFIXED|VUNSET,    "IFS\0",        0 },
    1514 #endif
    1515 
    1516 #ifdef CONFIG_ASH_MAIL
    1517     { 0,    VSTRFIXED|VTEXTFIXED|VUNSET,    "MAIL\0",       changemail },
    1518     { 0,    VSTRFIXED|VTEXTFIXED|VUNSET,    "MAILPATH\0",   changemail },
    1519 #endif
    1520 
    1521     { 0,    VSTRFIXED|VTEXTFIXED,           defpathvar,     changepath },
    1522     { 0,    VSTRFIXED|VTEXTFIXED,           "PS1=$ ",       0          },
    1523     { 0,    VSTRFIXED|VTEXTFIXED,           "PS2=> ",       0          },
    1524     { 0,    VSTRFIXED|VTEXTFIXED,           "PS4=+ ",       0          },
    1525 #ifdef CONFIG_ASH_GETOPTS
    1526     { 0,    VSTRFIXED|VTEXTFIXED,           "OPTIND=1",     getoptsreset },
    1527 #endif
    1528 #ifdef CONFIG_ASH_RANDOM_SUPPORT
    1529     {0, VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random },
    1530 #endif
    1531 #ifdef CONFIG_LOCALE_SUPPORT
    1532     {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL\0", change_lc_all },
    1533     {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE\0", change_lc_ctype },
    1534 #endif
    1535 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
    1536     {0, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE\0", NULL },
    1537 #endif
    1538 };
    1539 
    1540 #define vifs varinit[0]
    1541 #ifdef CONFIG_ASH_MAIL
    1542 #define vmail (&vifs)[1]
    1543 #define vmpath (&vmail)[1]
    1544 #else
    1545 #define vmpath vifs
    1546 #endif
    1547 #define vpath (&vmpath)[1]
    1548 #define vps1 (&vpath)[1]
    1549 #define vps2 (&vps1)[1]
    1550 #define vps4 (&vps2)[1]
    1551 #define voptind (&vps4)[1]
    1552 #ifdef CONFIG_ASH_GETOPTS
    1553 #define vrandom (&voptind)[1]
    1554 #else
    1555 #define vrandom (&vps4)[1]
    1556 #endif
    1557 #define defpath (defpathvar + 5)
    1558 
    1559 /*
    1560  * The following macros access the values of the above variables.
    1561  * They have to skip over the name.  They return the null string
    1562  * for unset variables.
    1563  */
    1564 
    1565 #define ifsval()        (vifs.text + 4)
    1566 #define ifsset()        ((vifs.flags & VUNSET) == 0)
    1567 #define mailval()       (vmail.text + 5)
    1568 #define mpathval()      (vmpath.text + 9)
    1569 #define pathval()       (vpath.text + 5)
    1570 #define ps1val()        (vps1.text + 4)
    1571 #define ps2val()        (vps2.text + 4)
    1572 #define ps4val()        (vps4.text + 4)
    1573 #define optindval()     (voptind.text + 7)
    1574 
    1575 #define mpathset()      ((vmpath.flags & VUNSET) == 0)
    1576 
    1577 static void setvar(const char *, const char *, int);
    1578 static void setvareq(char *, int);
    1579 static void listsetvar(struct strlist *, int);
    1580 static char *lookupvar(const char *);
    1581 static char *bltinlookup(const char *);
    1582 static char **listvars(int, int, char ***);
    1583 #define environment() listvars(VEXPORT, VUNSET, 0)
    1584 static int showvars(const char *, int, int);
    1585 static void poplocalvars(void);
    1586 static int unsetvar(const char *);
    1587 #ifdef CONFIG_ASH_GETOPTS
    1588 static int setvarsafe(const char *, const char *, int);
    1589 #endif
    1590 static int varcmp(const char *, const char *);
    1591 static struct var **hashvar(const char *);
    1592 
    1593 
    1594 static inline int varequal(const char *a, const char *b) {
    1595     return !varcmp(a, b);
    1596 }
    1597 
    1598 
    1599 static int loopnest;            /* current loop nesting level */
    1600 
    1601 /*
    1602  * The parsefile structure pointed to by the global variable parsefile
    1603  * contains information about the current file being read.
    1604  */
    1605 
    1606 
    1607 struct redirtab {
    1608     struct redirtab *next;
    1609     int renamed[10];
    1610     int nullredirs;
    1611 };
    1612 
    1613 static struct redirtab *redirlist;
    1614 static int nullredirs;
    1615 
    1616 extern char **environ;
    1617 
    1618 /*      output.h     */
    1619 
    1620 
    1621 static void outstr(const char *, FILE *);
    1622 static void outcslow(int, FILE *);
    1623 static void flushall(void);
    1624 static void flusherr(void);
    1625 static int  out1fmt(const char *, ...)
    1626     __attribute__((__format__(__printf__,1,2)));
    1627 static int fmtstr(char *, size_t, const char *, ...)
    1628     __attribute__((__format__(__printf__,3,4)));
    1629 
    1630 static int preverrout_fd;   /* save fd2 before print debug if xflag is set. */
    1631 
    1632 
    1633 static void out1str(const char *p)
    1634 {
    1635     outstr(p, stdout);
    1636 }
    1637 
    1638 static void out2str(const char *p)
    1639 {
    1640     outstr(p, stderr);
    1641     flusherr();
    1642 }
    1643 
    1644 /*
    1645  * Initialization code.
    1646  */
    1647 
    1648 /*
    1649  * This routine initializes the builtin variables.
    1650  */
    1651 
    1652 static inline void
    1653 initvar(void)
    1654 {
    1655     struct var *vp;
    1656     struct var *end;
    1657     struct var **vpp;
    1658 
    1659     /*
    1660      * PS1 depends on uid
    1661      */
    1662 #if defined(CONFIG_FEATURE_COMMAND_EDITING) && defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
    1663     vps1.text = "PS1=\\w \\$ ";
    1664 #else
    1665     if (!geteuid())
    1666         vps1.text = "PS1=# ";
    1667 #endif
    1668     vp = varinit;
    1669     end = vp + sizeof(varinit) / sizeof(varinit[0]);
    1670     do {
    1671         vpp = hashvar(vp->text);
    1672         vp->next = *vpp;
    1673         *vpp = vp;
    1674     } while (++vp < end);
    1675 }
    1676 
    1677 static inline void
    1678 init(void)
    1679 {
    1680 
    1681       /* from input.c: */
    1682       {
    1683           basepf.nextc = basepf.buf = basebuf;
    1684       }
    1685 
    1686       /* from trap.c: */
    1687       {
    1688           signal(SIGCHLD, SIG_DFL);
    1689       }
    1690 
    1691       /* from var.c: */
    1692       {
    1693           char **envp;
    1694           char ppid[32];
    1695           const char *p;
    1696           struct stat st1, st2;
    1697 
    1698           initvar();
    1699           for (envp = environ ; envp && *envp ; envp++) {
    1700               if (strchr(*envp, '=')) {
    1701                   setvareq(*envp, VEXPORT|VTEXTFIXED);
    1702               }
    1703           }
    1704 
    1705           snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
    1706           setvar("PPID", ppid, 0);
    1707 
    1708           p = lookupvar("PWD");
    1709           if (p)
    1710           if (*p != '/' || stat(p, &st1) || stat(".", &st2) ||
    1711           st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
    1712               p = 0;
    1713           setpwd(p, 0);
    1714       }
    1715 }
    1716 
    1717 /* PEOF (the end of file marker) */
    1718 
    1719 enum {
    1720     INPUT_PUSH_FILE = 1,
    1721     INPUT_NOFILE_OK = 2,
    1722 };
    1723 
    1724 /*
    1725  * The input line number.  Input.c just defines this variable, and saves
    1726  * and restores it when files are pushed and popped.  The user of this
    1727  * package must set its value.
    1728  */
    1729 
    1730 static int pgetc(void);
    1731 static int pgetc2(void);
    1732 static int preadbuffer(void);
    1733 static void pungetc(void);
    1734 static void pushstring(char *, void *);
    1735 static void popstring(void);
    1736 static void setinputfd(int, int);
    1737 static void setinputstring(char *);
    1738 static void popfile(void);
    1739 static void popallfiles(void);
    1740 static void closescript(void);
    1741 
    1742 
    1743 /*      jobs.h    */
    1744 
     2914static struct alias *atab[ATABSIZE];
     2915
     2916static struct alias **
     2917__lookupalias(const char *name) {
     2918    unsigned int hashval;
     2919    struct alias **app;
     2920    const char *p;
     2921    unsigned int ch;
     2922
     2923    p = name;
     2924
     2925    ch = (unsigned char)*p;
     2926    hashval = ch << 4;
     2927    while (ch) {
     2928        hashval += ch;
     2929        ch = (unsigned char)*++p;
     2930    }
     2931    app = &atab[hashval % ATABSIZE];
     2932
     2933    for (; *app; app = &(*app)->next) {
     2934        if (strcmp(name, (*app)->name) == 0) {
     2935            break;
     2936        }
     2937    }
     2938
     2939    return app;
     2940}
     2941
     2942static struct alias *
     2943lookupalias(const char *name, int check)
     2944{
     2945    struct alias *ap = *__lookupalias(name);
     2946
     2947    if (check && ap && (ap->flag & ALIASINUSE))
     2948        return NULL;
     2949    return ap;
     2950}
     2951
     2952static struct alias *
     2953freealias(struct alias *ap)
     2954{
     2955    struct alias *next;
     2956
     2957    if (ap->flag & ALIASINUSE) {
     2958        ap->flag |= ALIASDEAD;
     2959        return ap;
     2960    }
     2961
     2962    next = ap->next;
     2963    free(ap->name);
     2964    free(ap->val);
     2965    free(ap);
     2966    return next;
     2967}
     2968
     2969static void
     2970setalias(const char *name, const char *val)
     2971{
     2972    struct alias *ap, **app;
     2973
     2974    app = __lookupalias(name);
     2975    ap = *app;
     2976    INT_OFF;
     2977    if (ap) {
     2978        if (!(ap->flag & ALIASINUSE)) {
     2979            free(ap->val);
     2980        }
     2981        ap->val = ckstrdup(val);
     2982        ap->flag &= ~ALIASDEAD;
     2983    } else {
     2984        /* not found */
     2985        ap = ckmalloc(sizeof(struct alias));
     2986        ap->name = ckstrdup(name);
     2987        ap->val = ckstrdup(val);
     2988        ap->flag = 0;
     2989        ap->next = 0;
     2990        *app = ap;
     2991    }
     2992    INT_ON;
     2993}
     2994
     2995static int
     2996unalias(const char *name)
     2997{
     2998    struct alias **app;
     2999
     3000    app = __lookupalias(name);
     3001
     3002    if (*app) {
     3003        INT_OFF;
     3004        *app = freealias(*app);
     3005        INT_ON;
     3006        return 0;
     3007    }
     3008
     3009    return 1;
     3010}
     3011
     3012static void
     3013rmaliases(void)
     3014{
     3015    struct alias *ap, **app;
     3016    int i;
     3017
     3018    INT_OFF;
     3019    for (i = 0; i < ATABSIZE; i++) {
     3020        app = &atab[i];
     3021        for (ap = *app; ap; ap = *app) {
     3022            *app = freealias(*app);
     3023            if (ap == *app) {
     3024                app = &ap->next;
     3025            }
     3026        }
     3027    }
     3028    INT_ON;
     3029}
     3030
     3031static void
     3032printalias(const struct alias *ap)
     3033{
     3034    out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
     3035}
     3036
     3037/*
     3038 * TODO - sort output
     3039 */
     3040static int
     3041aliascmd(int argc, char **argv)
     3042{
     3043    char *n, *v;
     3044    int ret = 0;
     3045    struct alias *ap;
     3046
     3047    if (argc == 1) {
     3048        int i;
     3049
     3050        for (i = 0; i < ATABSIZE; i++)
     3051            for (ap = atab[i]; ap; ap = ap->next) {
     3052                printalias(ap);
     3053            }
     3054        return 0;
     3055    }
     3056    while ((n = *++argv) != NULL) {
     3057        v = strchr(n+1, '=');
     3058        if (v == NULL) { /* n+1: funny ksh stuff */
     3059            ap = *__lookupalias(n);
     3060            if (ap == NULL) {
     3061                fprintf(stderr, "%s: %s not found\n", "alias", n);
     3062                ret = 1;
     3063            } else
     3064                printalias(ap);
     3065        } else {
     3066            *v++ = '\0';
     3067            setalias(n, v);
     3068        }
     3069    }
     3070
     3071    return ret;
     3072}
     3073
     3074static int
     3075unaliascmd(int argc, char **argv)
     3076{
     3077    int i;
     3078
     3079    while ((i = nextopt("a")) != '\0') {
     3080        if (i == 'a') {
     3081            rmaliases();
     3082            return 0;
     3083        }
     3084    }
     3085    for (i = 0; *argptr; argptr++) {
     3086        if (unalias(*argptr)) {
     3087            fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
     3088            i = 1;
     3089        }
     3090    }
     3091
     3092    return i;
     3093}
     3094
     3095#endif /* ASH_ALIAS */
     3096
     3097
     3098/* ============ jobs.c */
    17453099
    17463100/* Mode argument to forkshell.  Don't change FORK_FG or FORK_BG. */
     
    17533107#define SHOW_PID        0x04    /* include process pid */
    17543108#define SHOW_CHANGED    0x08    /* only jobs whose state has changed */
    1755 
    17563109
    17573110/*
     
    17913144
    17923145static pid_t backgndpid;        /* pid of last background process */
    1793 static int job_warning;         /* user was warned about stopped jobs */
    1794 #if JOBS
    1795 static int jobctl;              /* true if doing job control */
    1796 #endif
     3146static smallint job_warning;    /* user was warned about stopped jobs (can be 2, 1 or 0). */
    17973147
    17983148static struct job *makejob(union node *, int);
    17993149static int forkshell(struct job *, union node *, int);
    18003150static int waitforjob(struct job *);
    1801 static int stoppedjobs(void);
    1802 
    1803 #if ! JOBS
    1804 #define setjobctl(on)   /* do nothing */
     3151
     3152#if !JOBS
     3153enum { jobctl = 0 };
     3154#define setjobctl(on) do {} while (0)
    18053155#else
     3156static smallint jobctl;              /* true if doing job control */
    18063157static void setjobctl(int);
    1807 static void showjobs(FILE *, int);
    1808 #endif
    1809 
    1810 /*      main.h        */
    1811 
    1812 
    1813 /* pid of main shell */
    1814 static int rootpid;
    1815 /* shell level: 0 for the main shell, 1 for its children, and so on */
    1816 static int shlvl;
    1817 #define rootshell (!shlvl)
    1818 
    1819 static void readcmdfile(char *);
    1820 static int cmdloop(int);
    1821 
    1822 /*      memalloc.h        */
    1823 
    1824 
    1825 struct stackmark {
    1826     struct stack_block *stackp;
    1827     char *stacknxt;
    1828     size_t stacknleft;
    1829     struct stackmark *marknext;
    1830 };
    1831 
    1832 /* minimum size of a block */
    1833 #define MINSIZE SHELL_ALIGN(504)
    1834 
    1835 struct stack_block {
    1836     struct stack_block *prev;
    1837     char space[MINSIZE];
    1838 };
    1839 
    1840 static struct stack_block stackbase;
    1841 static struct stack_block *stackp = &stackbase;
    1842 static struct stackmark *markp;
    1843 static char *stacknxt = stackbase.space;
    1844 static size_t stacknleft = MINSIZE;
    1845 static char *sstrend = stackbase.space + MINSIZE;
    1846 static int herefd = -1;
    1847 
    1848 
    1849 static pointer ckmalloc(size_t);
    1850 static pointer ckrealloc(pointer, size_t);
    1851 static char *savestr(const char *);
    1852 static pointer stalloc(size_t);
    1853 static void stunalloc(pointer);
    1854 static void setstackmark(struct stackmark *);
    1855 static void popstackmark(struct stackmark *);
    1856 static void growstackblock(void);
    1857 static void *growstackstr(void);
    1858 static char *makestrspace(size_t, char *);
    1859 static char *stnputs(const char *, size_t, char *);
    1860 static char *stputs(const char *, char *);
    1861 
    1862 
    1863 static inline char *_STPUTC(int c, char *p) {
    1864     if (p == sstrend)
    1865         p = growstackstr();
    1866     *p++ = c;
    1867     return p;
    1868 }
    1869 
    1870 #define stackblock() ((void *)stacknxt)
    1871 #define stackblocksize() stacknleft
    1872 #define STARTSTACKSTR(p) ((p) = stackblock())
    1873 #define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
    1874 #define CHECKSTRSPACE(n, p) \
    1875     ({ \
    1876         char *q = (p); \
    1877         size_t l = (n); \
    1878         size_t m = sstrend - q; \
    1879         if (l > m) \
    1880             (p) = makestrspace(l, q); \
    1881         0; \
    1882     })
    1883 #define USTPUTC(c, p)   (*p++ = (c))
    1884 #define STACKSTRNUL(p)  ((p) == sstrend? (p = growstackstr(), *p = '\0') : (*p = '\0'))
    1885 #define STUNPUTC(p)     (--p)
    1886 #define STTOPC(p)       p[-1]
    1887 #define STADJUST(amount, p)     (p += (amount))
    1888 
    1889 #define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
    1890 #define ungrabstackstr(s, p) stunalloc((s))
    1891 #define stackstrend() ((void *)sstrend)
    1892 
    1893 #define ckfree(p)       free((pointer)(p))
    1894 
    1895 /*      mystring.h   */
    1896 
    1897 
    1898 #define DOLATSTRLEN 4
    1899 
    1900 static char *prefix(const char *, const char *);
    1901 static int number(const char *);
    1902 static int is_number(const char *);
    1903 static char *single_quote(const char *);
    1904 static char *sstrdup(const char *);
    1905 
    1906 #define equal(s1, s2)   (strcmp(s1, s2) == 0)
    1907 #define scopy(s1, s2)   ((void)strcpy(s2, s1))
    1908 
    1909 /*      options.h */
    1910 
    1911 struct shparam {
    1912     int nparam;             /* # of positional parameters (without $0) */
    1913     unsigned char malloc;   /* if parameter list dynamically allocated */
    1914     char **p;               /* parameter list */
    1915 #ifdef CONFIG_ASH_GETOPTS
    1916     int optind;             /* next parameter to be processed by getopts */
    1917     int optoff;             /* used by getopts */
    1918 #endif
    1919 };
    1920 
    1921 
    1922 #define eflag optlist[0]
    1923 #define fflag optlist[1]
    1924 #define Iflag optlist[2]
    1925 #define iflag optlist[3]
    1926 #define mflag optlist[4]
    1927 #define nflag optlist[5]
    1928 #define sflag optlist[6]
    1929 #define xflag optlist[7]
    1930 #define vflag optlist[8]
    1931 #define Cflag optlist[9]
    1932 #define aflag optlist[10]
    1933 #define bflag optlist[11]
    1934 #define uflag optlist[12]
    1935 #define viflag optlist[13]
    1936 
    1937 #ifdef DEBUG
    1938 #define nolog optlist[14]
    1939 #define debug optlist[15]
    1940 #endif
    1941 
    1942 #ifndef CONFIG_FEATURE_COMMAND_EDITING_VI
    1943 #define setvimode(on) viflag = 0   /* forcibly keep the option off */
    1944 #endif
    1945 
    1946 /*      options.c */
    1947 
    1948 
    1949 static const char *const optletters_optnames[] = {
    1950     "e"   "errexit",
    1951     "f"   "noglob",
    1952     "I"   "ignoreeof",
    1953     "i"   "interactive",
    1954     "m"   "monitor",
    1955     "n"   "noexec",
    1956     "s"   "stdin",
    1957     "x"   "xtrace",
    1958     "v"   "verbose",
    1959     "C"   "noclobber",
    1960     "a"   "allexport",
    1961     "b"   "notify",
    1962     "u"   "nounset",
    1963     "\0"  "vi",
    1964 #ifdef DEBUG
    1965     "\0"  "nolog",
    1966     "\0"  "debug",
    1967 #endif
    1968 };
    1969 
    1970 #define optletters(n) optletters_optnames[(n)][0]
    1971 #define optnames(n) (&optletters_optnames[(n)][1])
    1972 
    1973 #define NOPTS (sizeof(optletters_optnames)/sizeof(optletters_optnames[0]))
    1974 
    1975 static char optlist[NOPTS];
    1976 
    1977 
    1978 static char *arg0;                     /* value of $0 */
    1979 static struct shparam shellparam;      /* $@ current positional parameters */
    1980 static char **argptr;                  /* argument list for builtin commands */
    1981 static char *optionarg;                /* set by nextopt (like getopt) */
    1982 static char *optptr;                   /* used by nextopt */
    1983 
    1984 static char *minusc;                   /* argument to -c option */
    1985 
    1986 
    1987 static void procargs(int, char **);
    1988 static void optschanged(void);
    1989 static void setparam(char **);
    1990 static void freeparam(volatile struct shparam *);
    1991 static int shiftcmd(int, char **);
    1992 static int setcmd(int, char **);
    1993 static int nextopt(const char *);
    1994 
    1995 /*      redir.h      */
    1996 
    1997 /* flags passed to redirect */
    1998 #define REDIR_PUSH 01           /* save previous values of file descriptors */
    1999 #define REDIR_SAVEFD2 03       /* set preverrout */
    2000 
    2001 union node;
    2002 static void redirect(union node *, int);
    2003 static void popredir(int);
    2004 static void clearredir(int);
    2005 static int copyfd(int, int);
    2006 static int redirectsafe(union node *, int);
    2007 
    2008 /*      show.h     */
    2009 
    2010 
    2011 #ifdef DEBUG
    2012 static void showtree(union node *);
    2013 static void trace(const char *, ...);
    2014 static void tracev(const char *, va_list);
    2015 static void trargs(char **);
    2016 static void trputc(int);
    2017 static void trputs(const char *);
    2018 static void opentrace(void);
    2019 #endif
    2020 
    2021 /*      trap.h       */
    2022 
    2023 
    2024 /* trap handler commands */
    2025 static char *trap[NSIG];
    2026 /* current value of signal */
    2027 static char sigmode[NSIG - 1];
    2028 /* indicates specified signal received */
    2029 static char gotsig[NSIG - 1];
    2030 
    2031 static void clear_traps(void);
    2032 static void setsignal(int);
    2033 static void ignoresig(int);
    2034 static void onsig(int);
    2035 static int dotrap(void);
    2036 static void setinteractive(int);
    2037 static void exitshell(void) ATTRIBUTE_NORETURN;
    2038 static int decode_signal(const char *, int);
    2039 
    2040 /*
    2041  * This routine is called when an error or an interrupt occurs in an
    2042  * interactive shell and control is returned to the main command loop.
    2043  */
    2044 
    2045 static void
    2046 reset(void)
    2047 {
    2048       /* from eval.c: */
    2049       {
    2050           evalskip = 0;
    2051           loopnest = 0;
    2052       }
    2053 
    2054       /* from input.c: */
    2055       {
    2056           parselleft = parsenleft = 0;      /* clear input buffer */
    2057           popallfiles();
    2058       }
    2059 
    2060       /* from parser.c: */
    2061       {
    2062           tokpushback = 0;
    2063           checkkwd = 0;
    2064       }
    2065 
    2066       /* from redir.c: */
    2067       {
    2068           clearredir(0);
    2069       }
    2070 
    2071 }
    2072 
    2073 #ifdef CONFIG_ASH_ALIAS
    2074 static struct alias *atab[ATABSIZE];
    2075 
    2076 static void setalias(const char *, const char *);
    2077 static struct alias *freealias(struct alias *);
    2078 static struct alias **__lookupalias(const char *);
    2079 
    2080 static void
    2081 setalias(const char *name, const char *val)
    2082 {
    2083     struct alias *ap, **app;
    2084 
    2085     app = __lookupalias(name);
    2086     ap = *app;
    2087     INTOFF;
    2088     if (ap) {
    2089         if (!(ap->flag & ALIASINUSE)) {
    2090             ckfree(ap->val);
    2091         }
    2092         ap->val = savestr(val);
    2093         ap->flag &= ~ALIASDEAD;
    2094     } else {
    2095         /* not found */
    2096         ap = ckmalloc(sizeof (struct alias));
    2097         ap->name = savestr(name);
    2098         ap->val = savestr(val);
    2099         ap->flag = 0;
    2100         ap->next = 0;
    2101         *app = ap;
    2102     }
    2103     INTON;
    2104 }
    2105 
    2106 static int
    2107 unalias(const char *name)
    2108 {
    2109     struct alias **app;
    2110 
    2111     app = __lookupalias(name);
    2112 
    2113     if (*app) {
    2114         INTOFF;
    2115         *app = freealias(*app);
    2116         INTON;
    2117         return (0);
    2118     }
    2119 
    2120     return (1);
    2121 }
    2122 
    2123 static void
    2124 rmaliases(void)
    2125 {
    2126     struct alias *ap, **app;
    2127     int i;
    2128 
    2129     INTOFF;
    2130     for (i = 0; i < ATABSIZE; i++) {
    2131         app = &atab[i];
    2132         for (ap = *app; ap; ap = *app) {
    2133             *app = freealias(*app);
    2134             if (ap == *app) {
    2135                 app = &ap->next;
    2136             }
    2137         }
    2138     }
    2139     INTON;
    2140 }
    2141 
    2142 static struct alias *
    2143 lookupalias(const char *name, int check)
    2144 {
    2145     struct alias *ap = *__lookupalias(name);
    2146 
    2147     if (check && ap && (ap->flag & ALIASINUSE))
    2148         return (NULL);
    2149     return (ap);
    2150 }
    2151 
    2152 /*
    2153  * TODO - sort output
    2154  */
    2155 static int
    2156 aliascmd(int argc, char **argv)
    2157 {
    2158     char *n, *v;
    2159     int ret = 0;
    2160     struct alias *ap;
    2161 
    2162     if (argc == 1) {
    2163         int i;
    2164 
    2165         for (i = 0; i < ATABSIZE; i++)
    2166             for (ap = atab[i]; ap; ap = ap->next) {
    2167                 printalias(ap);
    2168             }
    2169         return (0);
    2170     }
    2171     while ((n = *++argv) != NULL) {
    2172         if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
    2173             if ((ap = *__lookupalias(n)) == NULL) {
    2174                 fprintf(stderr, "%s: %s not found\n", "alias", n);
    2175                 ret = 1;
     3158#endif
     3159
     3160/*
     3161 * Set the signal handler for the specified signal.  The routine figures
     3162 * out what it should be set to.
     3163 */
     3164static void
     3165setsignal(int signo)
     3166{
     3167    int action;
     3168    char *t, tsig;
     3169    struct sigaction act;
     3170
     3171    t = trap[signo];
     3172    if (t == NULL)
     3173        action = S_DFL;
     3174    else if (*t != '\0')
     3175        action = S_CATCH;
     3176    else
     3177        action = S_IGN;
     3178    if (rootshell && action == S_DFL) {
     3179        switch (signo) {
     3180        case SIGINT:
     3181            if (iflag || minusc || sflag == 0)
     3182                action = S_CATCH;
     3183            break;
     3184        case SIGQUIT:
     3185#if DEBUG
     3186            if (debug)
     3187                break;
     3188#endif
     3189            /* FALLTHROUGH */
     3190        case SIGTERM:
     3191            if (iflag)
     3192                action = S_IGN;
     3193            break;
     3194#if JOBS
     3195        case SIGTSTP:
     3196        case SIGTTOU:
     3197            if (mflag)
     3198                action = S_IGN;
     3199            break;
     3200#endif
     3201        }
     3202    }
     3203
     3204    t = &sigmode[signo - 1];
     3205    tsig = *t;
     3206    if (tsig == 0) {
     3207        /*
     3208         * current setting unknown
     3209         */
     3210        if (sigaction(signo, 0, &act) == -1) {
     3211            /*
     3212             * Pretend it worked; maybe we should give a warning
     3213             * here, but other shells don't. We don't alter
     3214             * sigmode, so that we retry every time.
     3215             */
     3216            return;
     3217        }
     3218        if (act.sa_handler == SIG_IGN) {
     3219            if (mflag
     3220             && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
     3221            ) {
     3222                tsig = S_IGN;   /* don't hard ignore these */
    21763223            } else
    2177                 printalias(ap);
     3224                tsig = S_HARD_IGN;
    21783225        } else {
    2179             *v++ = '\0';
    2180             setalias(n, v);
    2181         }
    2182     }
    2183 
    2184     return (ret);
    2185 }
    2186 
    2187 static int
    2188 unaliascmd(int argc, char **argv)
    2189 {
    2190     int i;
    2191 
    2192     while ((i = nextopt("a")) != '\0') {
    2193         if (i == 'a') {
    2194             rmaliases();
    2195             return (0);
    2196         }
    2197     }
    2198     for (i = 0; *argptr; argptr++) {
    2199         if (unalias(*argptr)) {
    2200             fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
    2201             i = 1;
    2202         }
    2203     }
    2204 
    2205     return (i);
    2206 }
    2207 
    2208 static struct alias *
    2209 freealias(struct alias *ap) {
    2210     struct alias *next;
    2211 
    2212     if (ap->flag & ALIASINUSE) {
    2213         ap->flag |= ALIASDEAD;
    2214         return ap;
    2215     }
    2216 
    2217     next = ap->next;
    2218     ckfree(ap->name);
    2219     ckfree(ap->val);
    2220     ckfree(ap);
    2221     return next;
    2222 }
    2223 
    2224 static void
    2225 printalias(const struct alias *ap) {
    2226     out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
    2227 }
    2228 
    2229 static struct alias **
    2230 __lookupalias(const char *name) {
    2231     unsigned int hashval;
    2232     struct alias **app;
    2233     const char *p;
    2234     unsigned int ch;
    2235 
    2236     p = name;
    2237 
    2238     ch = (unsigned char)*p;
    2239     hashval = ch << 4;
    2240     while (ch) {
    2241         hashval += ch;
    2242         ch = (unsigned char)*++p;
    2243     }
    2244     app = &atab[hashval % ATABSIZE];
    2245 
    2246     for (; *app; app = &(*app)->next) {
    2247         if (equal(name, (*app)->name)) {
    2248             break;
    2249         }
    2250     }
    2251 
    2252     return app;
    2253 }
    2254 #endif /* CONFIG_ASH_ALIAS */
    2255 
    2256 
    2257 /*      cd.c      */
    2258 
    2259 /*
    2260  * The cd and pwd commands.
    2261  */
    2262 
    2263 #define CD_PHYSICAL 1
    2264 #define CD_PRINT 2
    2265 
    2266 static int docd(const char *, int);
    2267 static int cdopt(void);
    2268 
    2269 static char *curdir = nullstr;          /* current working directory */
    2270 static char *physdir = nullstr;         /* physical working directory */
    2271 
    2272 static int
    2273 cdopt(void)
    2274 {
    2275     int flags = 0;
    2276     int i, j;
    2277 
    2278     j = 'L';
    2279     while ((i = nextopt("LP"))) {
    2280         if (i != j) {
    2281             flags ^= CD_PHYSICAL;
    2282             j = i;
    2283         }
    2284     }
    2285 
    2286     return flags;
    2287 }
    2288 
    2289 static int
    2290 cdcmd(int argc, char **argv)
    2291 {
    2292     const char *dest;
    2293     const char *path;
    2294     const char *p;
    2295     char c;
    2296     struct stat statb;
    2297     int flags;
    2298 
    2299     flags = cdopt();
    2300     dest = *argptr;
    2301     if (!dest)
    2302         dest = bltinlookup(homestr);
    2303     else if (dest[0] == '-' && dest[1] == '\0') {
    2304         dest = bltinlookup("OLDPWD");
    2305         flags |= CD_PRINT;
    2306     }
    2307     if (!dest)
    2308         dest = nullstr;
    2309     if (*dest == '/')
    2310         goto step7;
    2311     if (*dest == '.') {
    2312         c = dest[1];
    2313 dotdot:
    2314         switch (c) {
    2315         case '\0':
    2316         case '/':
    2317             goto step6;
    2318         case '.':
    2319             c = dest[2];
    2320             if (c != '.')
    2321                 goto dotdot;
    2322         }
    2323     }
    2324     if (!*dest)
    2325         dest = ".";
    2326     if (!(path = bltinlookup("CDPATH"))) {
    2327 step6:
    2328 step7:
    2329         p = dest;
    2330         goto docd;
    2331     }
    2332     do {
    2333         c = *path;
    2334         p = padvance(&path, dest);
    2335         if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
    2336             if (c && c != ':')
    2337                 flags |= CD_PRINT;
    2338 docd:
    2339             if (!docd(p, flags))
    2340                 goto out;
    2341             break;
    2342         }
    2343     } while (path);
    2344     sh_error("can't cd to %s", dest);
    2345     /* NOTREACHED */
    2346 out:
    2347     if (flags & CD_PRINT)
    2348         out1fmt(snlfmt, curdir);
    2349     return 0;
    2350 }
    2351 
    2352 
    2353 /*
    2354  * Update curdir (the name of the current directory) in response to a
    2355  * cd command.
    2356  */
    2357 
    2358 static inline const char *
    2359 updatepwd(const char *dir)
    2360 {
    2361     char *new;
    2362     char *p;
    2363     char *cdcomppath;
    2364     const char *lim;
    2365 
    2366     cdcomppath = sstrdup(dir);
    2367     STARTSTACKSTR(new);
    2368     if (*dir != '/') {
    2369         if (curdir == nullstr)
    2370             return 0;
    2371         new = stputs(curdir, new);
    2372     }
    2373     new = makestrspace(strlen(dir) + 2, new);
    2374     lim = stackblock() + 1;
    2375     if (*dir != '/') {
    2376         if (new[-1] != '/')
    2377             USTPUTC('/', new);
    2378         if (new > lim && *lim == '/')
    2379             lim++;
    2380     } else {
    2381         USTPUTC('/', new);
    2382         cdcomppath++;
    2383         if (dir[1] == '/' && dir[2] != '/') {
    2384             USTPUTC('/', new);
    2385             cdcomppath++;
    2386             lim++;
    2387         }
    2388     }
    2389     p = strtok(cdcomppath, "/");
    2390     while (p) {
    2391         switch(*p) {
    2392         case '.':
    2393             if (p[1] == '.' && p[2] == '\0') {
    2394                 while (new > lim) {
    2395                     STUNPUTC(new);
    2396                     if (new[-1] == '/')
    2397                         break;
    2398                 }
    2399                 break;
    2400             } else if (p[1] == '\0')
    2401                 break;
    2402             /* fall through */
    2403         default:
    2404             new = stputs(p, new);
    2405             USTPUTC('/', new);
    2406         }
    2407         p = strtok(0, "/");
    2408     }
    2409     if (new > lim)
    2410         STUNPUTC(new);
    2411     *new = 0;
    2412     return stackblock();
    2413 }
    2414 
    2415 /*
    2416  * Actually do the chdir.  We also call hashcd to let the routines in exec.c
    2417  * know that the current directory has changed.
    2418  */
    2419 
    2420 static int
    2421 docd(const char *dest, int flags)
    2422 {
    2423     const char *dir = 0;
    2424     int err;
    2425 
    2426     TRACE(("docd(\"%s\", %d) called\n", dest, flags));
    2427 
    2428     INTOFF;
    2429     if (!(flags & CD_PHYSICAL)) {
    2430         dir = updatepwd(dest);
    2431         if (dir)
    2432             dest = dir;
    2433     }
    2434     err = chdir(dest);
    2435     if (err)
    2436         goto out;
    2437     setpwd(dir, 1);
    2438     hashcd();
    2439 out:
    2440     INTON;
    2441     return err;
    2442 }
    2443 
    2444 /*
    2445  * Find out what the current directory is. If we already know the current
    2446  * directory, this routine returns immediately.
    2447  */
    2448 static inline char *
    2449 getpwd(void)
    2450 {
    2451     char *dir = getcwd(0, 0);
    2452     return dir ? dir : nullstr;
    2453 }
    2454 
    2455 static int
    2456 pwdcmd(int argc, char **argv)
    2457 {
    2458     int flags;
    2459     const char *dir = curdir;
    2460 
    2461     flags = cdopt();
    2462     if (flags) {
    2463         if (physdir == nullstr)
    2464             setpwd(dir, 0);
    2465         dir = physdir;
    2466     }
    2467     out1fmt(snlfmt, dir);
    2468     return 0;
    2469 }
    2470 
    2471 static void
    2472 setpwd(const char *val, int setold)
    2473 {
    2474     char *oldcur, *dir;
    2475 
    2476     oldcur = dir = curdir;
    2477 
    2478     if (setold) {
    2479         setvar("OLDPWD", oldcur, VEXPORT);
    2480     }
    2481     INTOFF;
    2482     if (physdir != nullstr) {
    2483         if (physdir != oldcur)
    2484             free(physdir);
    2485         physdir = nullstr;
    2486     }
    2487     if (oldcur == val || !val) {
    2488         char *s = getpwd();
    2489         physdir = s;
    2490         if (!val)
    2491             dir = s;
    2492     } else
    2493         dir = savestr(val);
    2494     if (oldcur != dir && oldcur != nullstr) {
    2495         free(oldcur);
    2496     }
    2497     curdir = dir;
    2498     INTON;
    2499     setvar("PWD", dir, VEXPORT);
    2500 }
    2501 
    2502 /*      error.c   */
    2503 
    2504 /*
    2505  * Errors and exceptions.
    2506  */
    2507 
    2508 /*
    2509  * Code to handle exceptions in C.
    2510  */
    2511 
    2512 
    2513 
    2514 static void exverror(int, const char *, va_list)
    2515     ATTRIBUTE_NORETURN;
    2516 
    2517 /*
    2518  * Called to raise an exception.  Since C doesn't include exceptions, we
    2519  * just do a longjmp to the exception handler.  The type of exception is
    2520  * stored in the global variable "exception".
    2521  */
    2522 
    2523 static void
    2524 exraise(int e)
    2525 {
    2526 #ifdef DEBUG
    2527     if (handler == NULL)
    2528         abort();
    2529 #endif
    2530     INTOFF;
    2531 
    2532     exception = e;
    2533     longjmp(handler->loc, 1);
    2534 }
    2535 
    2536 
    2537 /*
    2538  * Called from trap.c when a SIGINT is received.  (If the user specifies
    2539  * that SIGINT is to be trapped or ignored using the trap builtin, then
    2540  * this routine is not called.)  Suppressint is nonzero when interrupts
    2541  * are held using the INTOFF macro.  (The test for iflag is just
    2542  * defensive programming.)
    2543  */
    2544 
    2545 static void
    2546 onint(void) {
    2547     int i;
    2548 
    2549     intpending = 0;
    2550 #if 0
    2551     /* comment by vodz: its strange for me, this programm don`t use other
    2552        signal block */
    2553     sigsetmask(0);
    2554 #endif
    2555     i = EXSIG;
    2556     if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
    2557         if (!(rootshell && iflag)) {
    2558             signal(SIGINT, SIG_DFL);
    2559             raise(SIGINT);
    2560         }
    2561         i = EXINT;
    2562     }
    2563     exraise(i);
    2564     /* NOTREACHED */
    2565 }
    2566 
    2567 static void
    2568 exvwarning(const char *msg, va_list ap)
    2569 {
    2570      FILE *errs;
    2571 
    2572      errs = stderr;
    2573      fprintf(errs, "%s: ", arg0);
    2574      if (commandname) {
    2575          const char *fmt = (!iflag || parsefile->fd) ?
    2576                     "%s: %d: " : "%s: ";
    2577          fprintf(errs, fmt, commandname, startlinno);
    2578      }
    2579      vfprintf(errs, msg, ap);
    2580      outcslow('\n', errs);
    2581 }
    2582 
    2583 /*
    2584  * Exverror is called to raise the error exception.  If the second argument
    2585  * is not NULL then error prints an error message using printf style
    2586  * formatting.  It then raises the error exception.
    2587  */
    2588 static void
    2589 exverror(int cond, const char *msg, va_list ap)
    2590 {
    2591 #ifdef DEBUG
    2592     if (msg) {
    2593         TRACE(("exverror(%d, \"", cond));
    2594         TRACEV((msg, ap));
    2595         TRACE(("\") pid=%d\n", getpid()));
    2596     } else
    2597         TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
    2598     if (msg)
    2599 #endif
    2600         exvwarning(msg, ap);
    2601 
    2602     flushall();
    2603     exraise(cond);
    2604     /* NOTREACHED */
    2605 }
    2606 
    2607 
    2608 static void
    2609 sh_error(const char *msg, ...)
    2610 {
    2611     va_list ap;
    2612 
    2613     va_start(ap, msg);
    2614     exverror(EXERROR, msg, ap);
    2615     /* NOTREACHED */
    2616     va_end(ap);
    2617 }
    2618 
    2619 
    2620 static void
    2621 exerror(int cond, const char *msg, ...)
    2622 {
    2623     va_list ap;
    2624 
    2625     va_start(ap, msg);
    2626     exverror(cond, msg, ap);
    2627     /* NOTREACHED */
    2628     va_end(ap);
    2629 }
    2630 
    2631 /*
    2632  * error/warning routines for external builtins
    2633  */
    2634 
    2635 static void
    2636 sh_warnx(const char *fmt, ...)
    2637 {
    2638     va_list ap;
    2639 
    2640     va_start(ap, fmt);
    2641     exvwarning(fmt, ap);
    2642     va_end(ap);
    2643 }
    2644 
    2645 
    2646 /*
    2647  * Return a string describing an error.  The returned string may be a
    2648  * pointer to a static buffer that will be overwritten on the next call.
    2649  * Action describes the operation that got the error.
    2650  */
    2651 
    2652 static const char *
    2653 errmsg(int e, const char *em)
    2654 {
    2655     if(e == ENOENT || e == ENOTDIR) {
    2656 
    2657         return em;
    2658     }
    2659     return strerror(e);
    2660 }
    2661 
    2662 
    2663 /*      eval.c  */
    2664 
    2665 /*
    2666  * Evaluate a command.
    2667  */
    2668 
    2669 /* flags in argument to evaltree */
    2670 #define EV_EXIT 01              /* exit after evaluating tree */
    2671 #define EV_TESTED 02            /* exit status is checked; ignore -e flag */
    2672 #define EV_BACKCMD 04           /* command executing within back quotes */
    2673 
    2674 
    2675 static void evalloop(union node *, int);
    2676 static void evalfor(union node *, int);
    2677 static void evalcase(union node *, int);
    2678 static void evalsubshell(union node *, int);
    2679 static void expredir(union node *);
    2680 static void evalpipe(union node *, int);
    2681 static void evalcommand(union node *, int);
    2682 static int evalbltin(const struct builtincmd *, int, char **);
    2683 static int evalfun(struct funcnode *, int, char **, int);
    2684 static void prehash(union node *);
    2685 static int bltincmd(int, char **);
    2686 
    2687 
    2688 static const struct builtincmd bltin = {
    2689     "\0\0", bltincmd
    2690 };
    2691 
    2692 
    2693 /*
    2694  * Called to reset things after an exception.
    2695  */
    2696 
    2697 /*
    2698  * The eval command.
    2699  */
    2700 
    2701 static int
    2702 evalcmd(int argc, char **argv)
    2703 {
    2704     char *p;
    2705     char *concat;
    2706     char **ap;
    2707 
    2708     if (argc > 1) {
    2709         p = argv[1];
    2710         if (argc > 2) {
    2711             STARTSTACKSTR(concat);
    2712             ap = argv + 2;
    2713             for (;;) {
    2714                 concat = stputs(p, concat);
    2715                 if ((p = *ap++) == NULL)
    2716                     break;
    2717                 STPUTC(' ', concat);
    2718             }
    2719             STPUTC('\0', concat);
    2720             p = grabstackstr(concat);
    2721         }
    2722         evalstring(p, ~SKIPEVAL);
    2723 
    2724     }
    2725     return exitstatus;
    2726 }
    2727 
    2728 
    2729 /*
    2730  * Execute a command or commands contained in a string.
    2731  */
    2732 
    2733 static int
    2734 evalstring(char *s, int mask)
    2735 {
    2736     union node *n;
    2737     struct stackmark smark;
    2738     int skip;
    2739 
    2740     setinputstring(s);
    2741     setstackmark(&smark);
    2742 
    2743     skip = 0;
    2744     while ((n = parsecmd(0)) != NEOF) {
    2745         evaltree(n, 0);
    2746         popstackmark(&smark);
    2747         skip = evalskip;
    2748         if (skip)
    2749             break;
    2750     }
    2751     popfile();
    2752 
    2753     skip &= mask;
    2754     evalskip = skip;
    2755     return skip;
    2756 }
    2757 
    2758 
    2759 
    2760 /*
    2761  * Evaluate a parse tree.  The value is left in the global variable
    2762  * exitstatus.
    2763  */
    2764 
    2765 static void
    2766 evaltree(union node *n, int flags)
    2767 {
    2768     int checkexit = 0;
    2769     void (*evalfn)(union node *, int);
    2770     unsigned isor;
    2771     int status;
    2772     if (n == NULL) {
    2773         TRACE(("evaltree(NULL) called\n"));
    2774         goto out;
    2775     }
    2776     TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
    2777         getpid(), n, n->type, flags));
    2778     switch (n->type) {
    2779     default:
    2780 #ifdef DEBUG
    2781         out1fmt("Node type = %d\n", n->type);
    2782         fflush(stdout);
     3226            tsig = S_RESET; /* force to be set */
     3227        }
     3228    }
     3229    if (tsig == S_HARD_IGN || tsig == action)
     3230        return;
     3231    switch (action) {
     3232    case S_CATCH:
     3233        act.sa_handler = onsig;
    27833234        break;
    2784 #endif
    2785     case NNOT:
    2786         evaltree(n->nnot.com, EV_TESTED);
    2787         status = !exitstatus;
    2788         goto setstatus;
    2789     case NREDIR:
    2790         expredir(n->nredir.redirect);
    2791         status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
    2792         if (!status) {
    2793             evaltree(n->nredir.n, flags & EV_TESTED);
    2794             status = exitstatus;
    2795         }
    2796         popredir(0);
    2797         goto setstatus;
    2798     case NCMD:
    2799         evalfn = evalcommand;
    2800 checkexit:
    2801         if (eflag && !(flags & EV_TESTED))
    2802             checkexit = ~0;
    2803         goto calleval;
    2804     case NFOR:
    2805         evalfn = evalfor;
    2806         goto calleval;
    2807     case NWHILE:
    2808     case NUNTIL:
    2809         evalfn = evalloop;
    2810         goto calleval;
    2811     case NSUBSHELL:
    2812     case NBACKGND:
    2813         evalfn = evalsubshell;
    2814         goto calleval;
    2815     case NPIPE:
    2816         evalfn = evalpipe;
    2817         goto checkexit;
    2818     case NCASE:
    2819         evalfn = evalcase;
    2820         goto calleval;
    2821     case NAND:
    2822     case NOR:
    2823     case NSEMI:
    2824 #if NAND + 1 != NOR
    2825 #error NAND + 1 != NOR
    2826 #endif
    2827 #if NOR + 1 != NSEMI
    2828 #error NOR + 1 != NSEMI
    2829 #endif
    2830         isor = n->type - NAND;
    2831         evaltree(
    2832             n->nbinary.ch1,
    2833             (flags | ((isor >> 1) - 1)) & EV_TESTED
    2834         );
    2835         if (!exitstatus == isor)
    2836             break;
    2837         if (!evalskip) {
    2838             n = n->nbinary.ch2;
    2839 evaln:
    2840             evalfn = evaltree;
    2841 calleval:
    2842             evalfn(n, flags);
    2843             break;
    2844         }
    2845         break;
    2846     case NIF:
    2847         evaltree(n->nif.test, EV_TESTED);
    2848         if (evalskip)
    2849             break;
    2850         if (exitstatus == 0) {
    2851             n = n->nif.ifpart;
    2852             goto evaln;
    2853         } else if (n->nif.elsepart) {
    2854             n = n->nif.elsepart;
    2855             goto evaln;
    2856         }
    2857         goto success;
    2858     case NDEFUN:
    2859         defun(n->narg.text, n->narg.next);
    2860 success:
    2861         status = 0;
    2862 setstatus:
    2863         exitstatus = status;
    2864         break;
    2865     }
    2866 out:
    2867     if ((checkexit & exitstatus))
    2868         evalskip |= SKIPEVAL;
    2869     else if (pendingsigs && dotrap())
    2870         goto exexit;
    2871 
    2872     if (flags & EV_EXIT) {
    2873 exexit:
    2874         exraise(EXEXIT);
    2875     }
    2876 }
    2877 
    2878 
    2879 #if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
    2880 static
    2881 #endif
    2882 void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
    2883 
    2884 
    2885 static void
    2886 evalloop(union node *n, int flags)
    2887 {
    2888     int status;
    2889 
    2890     loopnest++;
    2891     status = 0;
    2892     flags &= EV_TESTED;
    2893     for (;;) {
    2894         int i;
    2895 
    2896         evaltree(n->nbinary.ch1, EV_TESTED);
    2897         if (evalskip) {
    2898 skipping:         if (evalskip == SKIPCONT && --skipcount <= 0) {
    2899                 evalskip = 0;
    2900                 continue;
    2901             }
    2902             if (evalskip == SKIPBREAK && --skipcount <= 0)
    2903                 evalskip = 0;
    2904             break;
    2905         }
    2906         i = exitstatus;
    2907         if (n->type != NWHILE)
    2908             i = !i;
    2909         if (i != 0)
    2910             break;
    2911         evaltree(n->nbinary.ch2, flags);
    2912         status = exitstatus;
    2913         if (evalskip)
    2914             goto skipping;
    2915     }
    2916     loopnest--;
    2917     exitstatus = status;
    2918 }
    2919 
    2920 
    2921 
    2922 static void
    2923 evalfor(union node *n, int flags)
    2924 {
    2925     struct arglist arglist;
    2926     union node *argp;
    2927     struct strlist *sp;
    2928     struct stackmark smark;
    2929 
    2930     setstackmark(&smark);
    2931     arglist.lastp = &arglist.list;
    2932     for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
    2933         expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
    2934         /* XXX */
    2935         if (evalskip)
    2936             goto out;
    2937     }
    2938     *arglist.lastp = NULL;
    2939 
    2940     exitstatus = 0;
    2941     loopnest++;
    2942     flags &= EV_TESTED;
    2943     for (sp = arglist.list ; sp ; sp = sp->next) {
    2944         setvar(n->nfor.var, sp->text, 0);
    2945         evaltree(n->nfor.body, flags);
    2946         if (evalskip) {
    2947             if (evalskip == SKIPCONT && --skipcount <= 0) {
    2948                 evalskip = 0;
    2949                 continue;
    2950             }
    2951             if (evalskip == SKIPBREAK && --skipcount <= 0)
    2952                 evalskip = 0;
    2953             break;
    2954         }
    2955     }
    2956     loopnest--;
    2957 out:
    2958     popstackmark(&smark);
    2959 }
    2960 
    2961 
    2962 
    2963 static void
    2964 evalcase(union node *n, int flags)
    2965 {
    2966     union node *cp;
    2967     union node *patp;
    2968     struct arglist arglist;
    2969     struct stackmark smark;
    2970 
    2971     setstackmark(&smark);
    2972     arglist.lastp = &arglist.list;
    2973     expandarg(n->ncase.expr, &arglist, EXP_TILDE);
    2974     exitstatus = 0;
    2975     for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
    2976         for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
    2977             if (casematch(patp, arglist.list->text)) {
    2978                 if (evalskip == 0) {
    2979                     evaltree(cp->nclist.body, flags);
    2980                 }
    2981                 goto out;
    2982             }
    2983         }
    2984     }
    2985 out:
    2986     popstackmark(&smark);
    2987 }
    2988 
    2989 
    2990 
    2991 /*
    2992  * Kick off a subshell to evaluate a tree.
    2993  */
    2994 
    2995 static void
    2996 evalsubshell(union node *n, int flags)
    2997 {
    2998     struct job *jp;
    2999     int backgnd = (n->type == NBACKGND);
    3000     int status;
    3001 
    3002     expredir(n->nredir.redirect);
    3003     if (!backgnd && flags & EV_EXIT && !trap[0])
    3004         goto nofork;
    3005     INTOFF;
    3006     jp = makejob(n, 1);
    3007     if (forkshell(jp, n, backgnd) == 0) {
    3008         INTON;
    3009         flags |= EV_EXIT;
    3010         if (backgnd)
    3011             flags &=~ EV_TESTED;
    3012 nofork:
    3013         redirect(n->nredir.redirect, 0);
    3014         evaltreenr(n->nredir.n, flags);
    3015         /* never returns */
    3016     }
    3017     status = 0;
    3018     if (! backgnd)
    3019         status = waitforjob(jp);
    3020     exitstatus = status;
    3021     INTON;
    3022 }
    3023 
    3024 
    3025 
    3026 /*
    3027  * Compute the names of the files in a redirection list.
    3028  */
    3029 
    3030 static void
    3031 expredir(union node *n)
    3032 {
    3033     union node *redir;
    3034 
    3035     for (redir = n ; redir ; redir = redir->nfile.next) {
    3036         struct arglist fn;
    3037         fn.lastp = &fn.list;
    3038         switch (redir->type) {
    3039         case NFROMTO:
    3040         case NFROM:
    3041         case NTO:
    3042         case NCLOBBER:
    3043         case NAPPEND:
    3044             expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
    3045             redir->nfile.expfname = fn.list->text;
    3046             break;
    3047         case NFROMFD:
    3048         case NTOFD:
    3049             if (redir->ndup.vname) {
    3050                 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
    3051                 fixredir(redir, fn.list->text, 1);
    3052             }
    3053             break;
    3054         }
    3055     }
    3056 }
    3057 
    3058 
    3059 
    3060 /*
    3061  * Evaluate a pipeline.  All the processes in the pipeline are children
    3062  * of the process creating the pipeline.  (This differs from some versions
    3063  * of the shell, which make the last process in a pipeline the parent
    3064  * of all the rest.)
    3065  */
    3066 
    3067 static void
    3068 evalpipe(union node *n, int flags)
    3069 {
    3070     struct job *jp;
    3071     struct nodelist *lp;
    3072     int pipelen;
    3073     int prevfd;
    3074     int pip[2];
    3075 
    3076     TRACE(("evalpipe(0x%lx) called\n", (long)n));
    3077     pipelen = 0;
    3078     for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
    3079         pipelen++;
    3080     flags |= EV_EXIT;
    3081     INTOFF;
    3082     jp = makejob(n, pipelen);
    3083     prevfd = -1;
    3084     for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
    3085         prehash(lp->n);
    3086         pip[1] = -1;
    3087         if (lp->next) {
    3088             if (pipe(pip) < 0) {
    3089                 close(prevfd);
    3090                 sh_error("Pipe call failed");
    3091             }
    3092         }
    3093         if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
    3094             INTON;
    3095             if (pip[1] >= 0) {
    3096                 close(pip[0]);
    3097             }
    3098             if (prevfd > 0) {
    3099                 dup2(prevfd, 0);
    3100                 close(prevfd);
    3101             }
    3102             if (pip[1] > 1) {
    3103                 dup2(pip[1], 1);
    3104                 close(pip[1]);
    3105             }
    3106             evaltreenr(lp->n, flags);
    3107             /* never returns */
    3108         }
    3109         if (prevfd >= 0)
    3110             close(prevfd);
    3111         prevfd = pip[0];
    3112         close(pip[1]);
    3113     }
    3114     if (n->npipe.backgnd == 0) {
    3115         exitstatus = waitforjob(jp);
    3116         TRACE(("evalpipe:  job done exit status %d\n", exitstatus));
    3117     }
    3118     INTON;
    3119 }
    3120 
    3121 
    3122 
    3123 /*
    3124  * Execute a command inside back quotes.  If it's a builtin command, we
    3125  * want to save its output in a block obtained from malloc.  Otherwise
    3126  * we fork off a subprocess and get the output of the command via a pipe.
    3127  * Should be called with interrupts off.
    3128  */
    3129 
    3130 static void
    3131 evalbackcmd(union node *n, struct backcmd *result)
    3132 {
    3133     int saveherefd;
    3134 
    3135     result->fd = -1;
    3136     result->buf = NULL;
    3137     result->nleft = 0;
    3138     result->jp = NULL;
    3139     if (n == NULL) {
    3140         goto out;
    3141     }
    3142 
    3143     saveherefd = herefd;
    3144     herefd = -1;
    3145 
    3146     {
    3147         int pip[2];
    3148         struct job *jp;
    3149 
    3150         if (pipe(pip) < 0)
    3151             sh_error("Pipe call failed");
    3152         jp = makejob(n, 1);
    3153         if (forkshell(jp, n, FORK_NOJOB) == 0) {
    3154             FORCEINTON;
    3155             close(pip[0]);
    3156             if (pip[1] != 1) {
    3157                 close(1);
    3158                 copyfd(pip[1], 1);
    3159                 close(pip[1]);
    3160             }
    3161             eflag = 0;
    3162             evaltreenr(n, EV_EXIT);
    3163             /* NOTREACHED */
    3164         }
    3165         close(pip[1]);
    3166         result->fd = pip[0];
    3167         result->jp = jp;
    3168     }
    3169     herefd = saveherefd;
    3170 out:
    3171     TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
    3172         result->fd, result->buf, result->nleft, result->jp));
    3173 }
    3174 
    3175 #ifdef CONFIG_ASH_CMDCMD
    3176 static inline char **
    3177 parse_command_args(char **argv, const char **path)
    3178 {
    3179     char *cp, c;
    3180 
    3181     for (;;) {
    3182         cp = *++argv;
    3183         if (!cp)
    3184             return 0;
    3185         if (*cp++ != '-')
    3186             break;
    3187         if (!(c = *cp++))
    3188             break;
    3189         if (c == '-' && !*cp) {
    3190             argv++;
    3191             break;
    3192         }
    3193         do {
    3194             switch (c) {
    3195             case 'p':
    3196                 *path = defpath;
    3197                 break;
    3198             default:
    3199                 /* run 'typecmd' for other options */
    3200                 return 0;
    3201             }
    3202         } while ((c = *cp++));
    3203     }
    3204     return argv;
    3205 }
    3206 #endif
    3207 
    3208 static inline int
    3209 isassignment(const char *p)
    3210 {
    3211     const char *q = endofname(p);
    3212     if (p == q)
    3213         return 0;
    3214     return *q == '=';
    3215 }
    3216 
    3217 #ifdef CONFIG_ASH_EXPAND_PRMT
    3218 static const char *expandstr(const char *ps);
    3219 #else
    3220 #define expandstr(s) s
    3221 #endif
    3222 
    3223 /*
    3224  * Execute a simple command.
    3225  */
    3226 
    3227 static void
    3228 evalcommand(union node *cmd, int flags)
    3229 {
    3230     struct stackmark smark;
    3231     union node *argp;
    3232     struct arglist arglist;
    3233     struct arglist varlist;
    3234     char **argv;
    3235     int argc;
    3236     const struct strlist *sp;
    3237     struct cmdentry cmdentry;
    3238     struct job *jp;
    3239     char *lastarg;
    3240     const char *path;
    3241     int spclbltin;
    3242     int cmd_is_exec;
    3243     int status;
    3244     char **nargv;
    3245     struct builtincmd *bcmd;
    3246     int pseudovarflag = 0;
    3247 
    3248     /* First expand the arguments. */
    3249     TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
    3250     setstackmark(&smark);
    3251     back_exitstatus = 0;
    3252 
    3253     cmdentry.cmdtype = CMDBUILTIN;
    3254     cmdentry.u.cmd = &bltin;
    3255     varlist.lastp = &varlist.list;
    3256     *varlist.lastp = NULL;
    3257     arglist.lastp = &arglist.list;
    3258     *arglist.lastp = NULL;
    3259 
    3260     argc = 0;
    3261     if (cmd->ncmd.args)
    3262     {
    3263         bcmd = find_builtin(cmd->ncmd.args->narg.text);
    3264         pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
    3265     }
    3266 
    3267     for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
    3268         struct strlist **spp;
    3269 
    3270         spp = arglist.lastp;
    3271         if (pseudovarflag && isassignment(argp->narg.text))
    3272             expandarg(argp, &arglist, EXP_VARTILDE);
    3273         else
    3274             expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
    3275 
    3276         for (sp = *spp; sp; sp = sp->next)
    3277             argc++;
    3278     }
    3279 
    3280     argv = nargv = stalloc(sizeof (char *) * (argc + 1));
    3281     for (sp = arglist.list ; sp ; sp = sp->next) {
    3282         TRACE(("evalcommand arg: %s\n", sp->text));
    3283         *nargv++ = sp->text;
    3284     }
    3285     *nargv = NULL;
    3286 
    3287     lastarg = NULL;
    3288     if (iflag && funcnest == 0 && argc > 0)
    3289         lastarg = nargv[-1];
    3290 
    3291     preverrout_fd = 2;
    3292     expredir(cmd->ncmd.redirect);
    3293     status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH|REDIR_SAVEFD2);
    3294 
    3295     path = vpath.text;
    3296     for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
    3297         struct strlist **spp;
    3298         char *p;
    3299 
    3300         spp = varlist.lastp;
    3301         expandarg(argp, &varlist, EXP_VARTILDE);
    3302 
    3303         /*
    3304          * Modify the command lookup path, if a PATH= assignment
    3305          * is present
    3306          */
    3307         p = (*spp)->text;
    3308         if (varequal(p, path))
    3309             path = p;
    3310     }
    3311 
    3312     /* Print the command if xflag is set. */
    3313     if (xflag) {
    3314         int n;
    3315         const char *p = " %s";
    3316 
    3317         p++;
    3318         dprintf(preverrout_fd, p, expandstr(ps4val()));
    3319 
    3320         sp = varlist.list;
    3321         for(n = 0; n < 2; n++) {
    3322             while (sp) {
    3323                 dprintf(preverrout_fd, p, sp->text);
    3324                 sp = sp->next;
    3325                 if(*p == '%') {
    3326                     p--;
    3327                 }
    3328             }
    3329             sp = arglist.list;
    3330         }
    3331         bb_full_write(preverrout_fd, "\n", 1);
    3332     }
    3333 
    3334     cmd_is_exec = 0;
    3335     spclbltin = -1;
    3336 
    3337     /* Now locate the command. */
    3338     if (argc) {
    3339         const char *oldpath;
    3340         int cmd_flag = DO_ERR;
    3341 
    3342         path += 5;
    3343         oldpath = path;
    3344         for (;;) {
    3345             find_command(argv[0], &cmdentry, cmd_flag, path);
    3346             if (cmdentry.cmdtype == CMDUNKNOWN) {
    3347                 status = 127;
    3348                 flusherr();
    3349                 goto bail;
    3350             }
    3351 
    3352             /* implement bltin and command here */
    3353             if (cmdentry.cmdtype != CMDBUILTIN)
    3354                 break;
    3355             if (spclbltin < 0)
    3356                 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
    3357             if (cmdentry.u.cmd == EXECCMD)
    3358                 cmd_is_exec++;
    3359 #ifdef CONFIG_ASH_CMDCMD
    3360             if (cmdentry.u.cmd == COMMANDCMD) {
    3361 
    3362                 path = oldpath;
    3363                 nargv = parse_command_args(argv, &path);
    3364                 if (!nargv)
    3365                     break;
    3366                 argc -= nargv - argv;
    3367                 argv = nargv;
    3368                 cmd_flag |= DO_NOFUNC;
    3369             } else
    3370 #endif
    3371                 break;
    3372         }
    3373     }
    3374 
    3375     if (status) {
    3376         /* We have a redirection error. */
    3377         if (spclbltin > 0)
    3378             exraise(EXERROR);
    3379 bail:
    3380         exitstatus = status;
    3381         goto out;
    3382     }
    3383 
    3384     /* Execute the command. */
    3385     switch (cmdentry.cmdtype) {
    3386     default:
    3387         /* Fork off a child process if necessary. */
    3388         if (!(flags & EV_EXIT) || trap[0]) {
    3389             INTOFF;
    3390             jp = makejob(cmd, 1);
    3391             if (forkshell(jp, cmd, FORK_FG) != 0) {
    3392                 exitstatus = waitforjob(jp);
    3393                 INTON;
    3394                 break;
    3395             }
    3396             FORCEINTON;
    3397         }
    3398         listsetvar(varlist.list, VEXPORT|VSTACK);
    3399         shellexec(argv, path, cmdentry.u.index);
    3400         /* NOTREACHED */
    3401 
    3402     case CMDBUILTIN:
    3403         cmdenviron = varlist.list;
    3404         if (cmdenviron) {
    3405             struct strlist *list = cmdenviron;
    3406             int i = VNOSET;
    3407             if (spclbltin > 0 || argc == 0) {
    3408                 i = 0;
    3409                 if (cmd_is_exec && argc > 1)
    3410                     i = VEXPORT;
    3411             }
    3412             listsetvar(list, i);
    3413         }
    3414         if (evalbltin(cmdentry.u.cmd, argc, argv)) {
    3415             int exit_status;
    3416             int i, j;
    3417 
    3418             i = exception;
    3419             if (i == EXEXIT)
    3420                 goto raise;
    3421 
    3422             exit_status = 2;
    3423             j = 0;
    3424             if (i == EXINT)
    3425                 j = SIGINT;
    3426             if (i == EXSIG)
    3427                 j = pendingsigs;
    3428             if (j)
    3429                 exit_status = j + 128;
    3430             exitstatus = exit_status;
    3431 
    3432             if (i == EXINT || spclbltin > 0) {
    3433 raise:
    3434                 longjmp(handler->loc, 1);
    3435             }
    3436             FORCEINTON;
    3437         }
    3438         break;
    3439 
    3440     case CMDFUNCTION:
    3441         listsetvar(varlist.list, 0);
    3442         if (evalfun(cmdentry.u.func, argc, argv, flags))
    3443             goto raise;
    3444         break;
    3445     }
    3446 
    3447 out:
    3448     popredir(cmd_is_exec);
    3449     if (lastarg)
    3450         /* dsl: I think this is intended to be used to support
    3451          * '_' in 'vi' command mode during line editing...
    3452          * However I implemented that within libedit itself.
    3453          */
    3454         setvar("_", lastarg, 0);
    3455     popstackmark(&smark);
    3456 }
    3457 
    3458 static int
    3459 evalbltin(const struct builtincmd *cmd, int argc, char **argv) {
    3460     char *volatile savecmdname;
    3461     struct jmploc *volatile savehandler;
    3462     struct jmploc jmploc;
    3463     int i;
    3464 
    3465     savecmdname = commandname;
    3466     if ((i = setjmp(jmploc.loc)))
    3467         goto cmddone;
    3468     savehandler = handler;
    3469     handler = &jmploc;
    3470     commandname = argv[0];
    3471     argptr = argv + 1;
    3472     optptr = NULL;                  /* initialize nextopt */
    3473     exitstatus = (*cmd->builtin)(argc, argv);
    3474     flushall();
    3475 cmddone:
    3476     exitstatus |= ferror(stdout);
    3477     clearerr(stdout);
    3478     commandname = savecmdname;
    3479     exsig = 0;
    3480     handler = savehandler;
    3481 
    3482     return i;
    3483 }
    3484 
    3485 static int
    3486 evalfun(struct funcnode *func, int argc, char **argv, int flags)
    3487 {
    3488     volatile struct shparam saveparam;
    3489     struct localvar *volatile savelocalvars;
    3490     struct jmploc *volatile savehandler;
    3491     struct jmploc jmploc;
    3492     int e;
    3493 
    3494     saveparam = shellparam;
    3495     savelocalvars = localvars;
    3496     if ((e = setjmp(jmploc.loc))) {
    3497         goto funcdone;
    3498     }
    3499     INTOFF;
    3500     savehandler = handler;
    3501     handler = &jmploc;
    3502     localvars = NULL;
    3503     shellparam.malloc = 0;
    3504     func->count++;
    3505     funcnest++;
    3506     INTON;
    3507     shellparam.nparam = argc - 1;
    3508     shellparam.p = argv + 1;
    3509 #ifdef CONFIG_ASH_GETOPTS
    3510     shellparam.optind = 1;
    3511     shellparam.optoff = -1;
    3512 #endif
    3513     evaltree(&func->n, flags & EV_TESTED);
    3514 funcdone:
    3515     INTOFF;
    3516     funcnest--;
    3517     freefunc(func);
    3518     poplocalvars();
    3519     localvars = savelocalvars;
    3520     freeparam(&shellparam);
    3521     shellparam = saveparam;
    3522     handler = savehandler;
    3523     INTON;
    3524     evalskip &= ~SKIPFUNC;
    3525     return e;
    3526 }
    3527 
    3528 
    3529 static inline int
    3530 goodname(const char *p)
    3531 {
    3532     return !*endofname(p);
    3533 }
    3534 
    3535 /*
    3536  * Search for a command.  This is called before we fork so that the
    3537  * location of the command will be available in the parent as well as
    3538  * the child.  The check for "goodname" is an overly conservative
    3539  * check that the name will not be subject to expansion.
    3540  */
    3541 
    3542 static void
    3543 prehash(union node *n)
    3544 {
    3545     struct cmdentry entry;
    3546 
    3547     if (n->type == NCMD && n->ncmd.args)
    3548         if (goodname(n->ncmd.args->narg.text))
    3549             find_command(n->ncmd.args->narg.text, &entry, 0,
    3550                      pathval());
    3551 }
    3552 
    3553 
    3554 
    3555 /*
    3556  * Builtin commands.  Builtin commands whose functions are closely
    3557  * tied to evaluation are implemented here.
    3558  */
    3559 
    3560 /*
    3561  * No command given.
    3562  */
    3563 
    3564 static int
    3565 bltincmd(int argc, char **argv)
    3566 {
    3567     /*
    3568      * Preserve exitstatus of a previous possible redirection
    3569      * as POSIX mandates
    3570      */
    3571     return back_exitstatus;
    3572 }
    3573 
    3574 
    3575 /*
    3576  * Handle break and continue commands.  Break, continue, and return are
    3577  * all handled by setting the evalskip flag.  The evaluation routines
    3578  * above all check this flag, and if it is set they start skipping
    3579  * commands rather than executing them.  The variable skipcount is
    3580  * the number of loops to break/continue, or the number of function
    3581  * levels to return.  (The latter is always 1.)  It should probably
    3582  * be an error to break out of more loops than exist, but it isn't
    3583  * in the standard shell so we don't make it one here.
    3584  */
    3585 
    3586 static int
    3587 breakcmd(int argc, char **argv)
    3588 {
    3589     int n = argc > 1 ? number(argv[1]) : 1;
    3590 
    3591     if (n <= 0)
    3592         sh_error(illnum, argv[1]);
    3593     if (n > loopnest)
    3594         n = loopnest;
    3595     if (n > 0) {
    3596         evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
    3597         skipcount = n;
    3598     }
    3599     return 0;
    3600 }
    3601 
    3602 
    3603 /*
    3604  * The return command.
    3605  */
    3606 
    3607 static int
    3608 returncmd(int argc, char **argv)
    3609 {
    3610     /*
    3611      * If called outside a function, do what ksh does;
    3612      * skip the rest of the file.
    3613      */
    3614     evalskip = funcnest ? SKIPFUNC : SKIPFILE;
    3615     return argv[1] ? number(argv[1]) : exitstatus;
    3616 }
    3617 
    3618 
    3619 static int
    3620 falsecmd(int argc, char **argv)
    3621 {
    3622     return 1;
    3623 }
    3624 
    3625 
    3626 static int
    3627 truecmd(int argc, char **argv)
    3628 {
    3629     return 0;
    3630 }
    3631 
    3632 
    3633 static int
    3634 execcmd(int argc, char **argv)
    3635 {
    3636     if (argc > 1) {
    3637         iflag = 0;              /* exit on error */
    3638         mflag = 0;
    3639         optschanged();
    3640         shellexec(argv + 1, pathval(), 0);
    3641     }
    3642     return 0;
    3643 }
    3644 
    3645 
    3646 /*      exec.c    */
    3647 
    3648 /*
    3649  * When commands are first encountered, they are entered in a hash table.
    3650  * This ensures that a full path search will not have to be done for them
    3651  * on each invocation.
    3652  *
    3653  * We should investigate converting to a linear search, even though that
    3654  * would make the command name "hash" a misnomer.
    3655  */
    3656 
    3657 #define CMDTABLESIZE 31         /* should be prime */
    3658 #define ARB 1                   /* actual size determined at run time */
    3659 
    3660 
    3661 
    3662 struct tblentry {
    3663     struct tblentry *next;  /* next entry in hash chain */
    3664     union param param;      /* definition of builtin function */
    3665     short cmdtype;          /* index identifying command */
    3666     char rehash;            /* if set, cd done since entry created */
    3667     char cmdname[ARB];      /* name of command */
    3668 };
    3669 
    3670 
    3671 static struct tblentry *cmdtable[CMDTABLESIZE];
    3672 static int builtinloc = -1;             /* index in path of %builtin, or -1 */
    3673 
    3674 
    3675 static void tryexec(char *, char **, char **);
    3676 static void clearcmdentry(int);
    3677 static struct tblentry *cmdlookup(const char *, int);
    3678 static void delete_cmd_entry(void);
    3679 
    3680 
    3681 /*
    3682  * Exec a program.  Never returns.  If you change this routine, you may
    3683  * have to change the find_command routine as well.
    3684  */
    3685 
    3686 static void
    3687 shellexec(char **argv, const char *path, int idx)
    3688 {
    3689     char *cmdname;
    3690     int e;
    3691     char **envp;
    3692     int exerrno;
    3693 
    3694     clearredir(1);
    3695     envp = environment();
    3696     if (strchr(argv[0], '/') != NULL
    3697 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
    3698         || find_applet_by_name(argv[0])
    3699 #endif
    3700                         ) {
    3701         tryexec(argv[0], argv, envp);
    3702         e = errno;
    3703     } else {
    3704         e = ENOENT;
    3705         while ((cmdname = padvance(&path, argv[0])) != NULL) {
    3706             if (--idx < 0 && pathopt == NULL) {
    3707                 tryexec(cmdname, argv, envp);
    3708                 if (errno != ENOENT && errno != ENOTDIR)
    3709                     e = errno;
    3710             }
    3711             stunalloc(cmdname);
    3712         }
    3713     }
    3714 
    3715     /* Map to POSIX errors */
    3716     switch (e) {
    3717     case EACCES:
    3718         exerrno = 126;
    3719         break;
    3720     case ENOENT:
    3721         exerrno = 127;
     3235    case S_IGN:
     3236        act.sa_handler = SIG_IGN;
    37223237        break;
    37233238    default:
    3724         exerrno = 2;
    3725         break;
    3726     }
    3727     exitstatus = exerrno;
    3728     TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
    3729         argv[0], e, suppressint ));
    3730     exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
    3731     /* NOTREACHED */
    3732 }
    3733 
    3734 
    3735 static void
    3736 tryexec(char *cmd, char **argv, char **envp)
    3737 {
    3738     int repeated = 0;
    3739 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
    3740     if(find_applet_by_name(cmd) != NULL) {
    3741         /* re-exec ourselves with the new arguments */
    3742         execve(CONFIG_BUSYBOX_EXEC_PATH,argv,envp);
    3743         /* If they called chroot or otherwise made the binary no longer
    3744          * executable, fall through */
    3745     }
    3746 #endif
    3747 
    3748 repeat:
    3749 #ifdef SYSV
    3750     do {
    3751         execve(cmd, argv, envp);
    3752     } while (errno == EINTR);
    3753 #else
    3754     execve(cmd, argv, envp);
    3755 #endif
    3756     if (repeated++) {
    3757         ckfree(argv);
    3758     } else if (errno == ENOEXEC) {
    3759         char **ap;
    3760         char **new;
    3761 
    3762         for (ap = argv; *ap; ap++)
    3763             ;
    3764         ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
    3765         ap[1] = cmd;
    3766         *ap = cmd = (char *)DEFAULT_SHELL;
    3767         ap += 2;
    3768         argv++;
    3769         while ((*ap++ = *argv++))
    3770             ;
    3771         argv = new;
    3772         goto repeat;
    3773     }
    3774 }
    3775 
    3776 
    3777 
    3778 /*
    3779  * Do a path search.  The variable path (passed by reference) should be
    3780  * set to the start of the path before the first call; padvance will update
    3781  * this value as it proceeds.  Successive calls to padvance will return
    3782  * the possible path expansions in sequence.  If an option (indicated by
    3783  * a percent sign) appears in the path entry then the global variable
    3784  * pathopt will be set to point to it; otherwise pathopt will be set to
    3785  * NULL.
    3786  */
    3787 
    3788 static char *
    3789 padvance(const char **path, const char *name)
    3790 {
    3791     const char *p;
    3792     char *q;
    3793     const char *start;
    3794     size_t len;
    3795 
    3796     if (*path == NULL)
    3797         return NULL;
    3798     start = *path;
    3799     for (p = start ; *p && *p != ':' && *p != '%' ; p++);
    3800     len = p - start + strlen(name) + 2;     /* "2" is for '/' and '\0' */
    3801     while (stackblocksize() < len)
    3802         growstackblock();
    3803     q = stackblock();
    3804     if (p != start) {
    3805         memcpy(q, start, p - start);
    3806         q += p - start;
    3807         *q++ = '/';
    3808     }
    3809     strcpy(q, name);
    3810     pathopt = NULL;
    3811     if (*p == '%') {
    3812         pathopt = ++p;
    3813         while (*p && *p != ':')  p++;
    3814     }
    3815     if (*p == ':')
    3816         *path = p + 1;
    3817     else
    3818         *path = NULL;
    3819     return stalloc(len);
    3820 }
    3821 
    3822 
    3823 /*** Command hashing code ***/
    3824 
    3825 static void
    3826 printentry(struct tblentry *cmdp)
    3827 {
    3828     int idx;
    3829     const char *path;
    3830     char *name;
    3831 
    3832     idx = cmdp->param.index;
    3833     path = pathval();
    3834     do {
    3835         name = padvance(&path, cmdp->cmdname);
    3836         stunalloc(name);
    3837     } while (--idx >= 0);
    3838     out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
    3839 }
    3840 
    3841 
    3842 static int
    3843 hashcmd(int argc, char **argv)
    3844 {
    3845     struct tblentry **pp;
    3846     struct tblentry *cmdp;
    3847     int c;
    3848     struct cmdentry entry;
    3849     char *name;
    3850 
    3851     while ((c = nextopt("r")) != '\0') {
    3852         clearcmdentry(0);
    3853         return 0;
    3854     }
    3855     if (*argptr == NULL) {
    3856         for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
    3857             for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
    3858                 if (cmdp->cmdtype == CMDNORMAL)
    3859                     printentry(cmdp);
    3860             }
    3861         }
    3862         return 0;
    3863     }
    3864     c = 0;
    3865     while ((name = *argptr) != NULL) {
    3866         if ((cmdp = cmdlookup(name, 0)) != NULL
    3867          && (cmdp->cmdtype == CMDNORMAL
    3868              || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
    3869             delete_cmd_entry();
    3870         find_command(name, &entry, DO_ERR, pathval());
    3871         if (entry.cmdtype == CMDUNKNOWN)
    3872             c = 1;
    3873         argptr++;
    3874     }
    3875     return c;
    3876 }
    3877 
    3878 
    3879 /*
    3880  * Resolve a command name.  If you change this routine, you may have to
    3881  * change the shellexec routine as well.
    3882  */
    3883 
    3884 static void
    3885 find_command(char *name, struct cmdentry *entry, int act, const char *path)
    3886 {
    3887     struct tblentry *cmdp;
    3888     int idx;
    3889     int prev;
    3890     char *fullname;
    3891     struct stat statb;
    3892     int e;
    3893     int updatetbl;
    3894     struct builtincmd *bcmd;
    3895 
    3896     /* If name contains a slash, don't use PATH or hash table */
    3897     if (strchr(name, '/') != NULL) {
    3898         entry->u.index = -1;
    3899         if (act & DO_ABS) {
    3900             while (stat(name, &statb) < 0) {
    3901 #ifdef SYSV
    3902                 if (errno == EINTR)
    3903                     continue;
    3904 #endif
    3905                 entry->cmdtype = CMDUNKNOWN;
    3906                 return;
    3907             }
    3908         }
    3909         entry->cmdtype = CMDNORMAL;
    3910         return;
    3911     }
    3912 
    3913 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
    3914     if (find_applet_by_name(name)) {
    3915         entry->cmdtype = CMDNORMAL;
    3916         entry->u.index = -1;
    3917         return;
    3918     }
    3919 #endif
    3920 
    3921     updatetbl = (path == pathval());
    3922     if (!updatetbl) {
    3923         act |= DO_ALTPATH;
    3924         if (strstr(path, "%builtin") != NULL)
    3925             act |= DO_ALTBLTIN;
    3926     }
    3927 
    3928     /* If name is in the table, check answer will be ok */
    3929     if ((cmdp = cmdlookup(name, 0)) != NULL) {
    3930         int bit;
    3931 
    3932         switch (cmdp->cmdtype) {
    3933         default:
    3934 #if DEBUG
    3935             abort();
    3936 #endif
    3937         case CMDNORMAL:
    3938             bit = DO_ALTPATH;
    3939             break;
    3940         case CMDFUNCTION:
    3941             bit = DO_NOFUNC;
    3942             break;
    3943         case CMDBUILTIN:
    3944             bit = DO_ALTBLTIN;
    3945             break;
    3946         }
    3947         if (act & bit) {
    3948             updatetbl = 0;
    3949             cmdp = NULL;
    3950         } else if (cmdp->rehash == 0)
    3951             /* if not invalidated by cd, we're done */
    3952             goto success;
    3953     }
    3954 
    3955     /* If %builtin not in path, check for builtin next */
    3956     bcmd = find_builtin(name);
    3957     if (bcmd && (IS_BUILTIN_REGULAR(bcmd) || (
    3958         act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc <= 0
    3959     )))
    3960         goto builtin_success;
    3961 
    3962     /* We have to search path. */
    3963     prev = -1;              /* where to start */
    3964     if (cmdp && cmdp->rehash) {     /* doing a rehash */
    3965         if (cmdp->cmdtype == CMDBUILTIN)
    3966             prev = builtinloc;
    3967         else
    3968             prev = cmdp->param.index;
    3969     }
    3970 
    3971     e = ENOENT;
    3972     idx = -1;
    3973 loop:
    3974     while ((fullname = padvance(&path, name)) != NULL) {
    3975         stunalloc(fullname);
    3976         idx++;
    3977         if (pathopt) {
    3978             if (prefix(pathopt, "builtin")) {
    3979                 if (bcmd)
    3980                     goto builtin_success;
    3981                 continue;
    3982             } else if (!(act & DO_NOFUNC) &&
    3983                    prefix(pathopt, "func")) {
    3984                 /* handled below */
    3985             } else {
    3986                 /* ignore unimplemented options */
    3987                 continue;
    3988             }
    3989         }
    3990         /* if rehash, don't redo absolute path names */
    3991         if (fullname[0] == '/' && idx <= prev) {
    3992             if (idx < prev)
    3993                 continue;
    3994             TRACE(("searchexec \"%s\": no change\n", name));
    3995             goto success;
    3996         }
    3997         while (stat(fullname, &statb) < 0) {
    3998 #ifdef SYSV
    3999             if (errno == EINTR)
    4000                 continue;
    4001 #endif
    4002             if (errno != ENOENT && errno != ENOTDIR)
    4003                 e = errno;
    4004             goto loop;
    4005         }
    4006         e = EACCES;     /* if we fail, this will be the error */
    4007         if (!S_ISREG(statb.st_mode))
    4008             continue;
    4009         if (pathopt) {          /* this is a %func directory */
    4010             stalloc(strlen(fullname) + 1);
    4011             readcmdfile(fullname);
    4012             if ((cmdp = cmdlookup(name, 0)) == NULL ||
    4013                 cmdp->cmdtype != CMDFUNCTION)
    4014                 sh_error("%s not defined in %s", name, fullname);
    4015             stunalloc(fullname);
    4016             goto success;
    4017         }
    4018         TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
    4019         if (!updatetbl) {
    4020             entry->cmdtype = CMDNORMAL;
    4021             entry->u.index = idx;
    4022             return;
    4023         }
    4024         INTOFF;
    4025         cmdp = cmdlookup(name, 1);
    4026         cmdp->cmdtype = CMDNORMAL;
    4027         cmdp->param.index = idx;
    4028         INTON;
    4029         goto success;
    4030     }
    4031 
    4032     /* We failed.  If there was an entry for this command, delete it */
    4033     if (cmdp && updatetbl)
    4034         delete_cmd_entry();
    4035     if (act & DO_ERR)
    4036         sh_warnx("%s: %s", name, errmsg(e, E_EXEC));
    4037     entry->cmdtype = CMDUNKNOWN;
    4038     return;
    4039 
    4040 builtin_success:
    4041     if (!updatetbl) {
    4042         entry->cmdtype = CMDBUILTIN;
    4043         entry->u.cmd = bcmd;
    4044         return;
    4045     }
    4046     INTOFF;
    4047     cmdp = cmdlookup(name, 1);
    4048     cmdp->cmdtype = CMDBUILTIN;
    4049     cmdp->param.cmd = bcmd;
    4050     INTON;
    4051 success:
    4052     cmdp->rehash = 0;
    4053     entry->cmdtype = cmdp->cmdtype;
    4054     entry->u = cmdp->param;
    4055 }
    4056 
    4057 
    4058 /*
    4059  * Wrapper around strcmp for qsort/bsearch/...
    4060  */
    4061 static int pstrcmp(const void *a, const void *b)
    4062 {
    4063     return strcmp((const char *) a, (*(const char *const *) b) + 1);
    4064 }
    4065 
    4066 /*
    4067  * Search the table of builtin commands.
    4068  */
    4069 
    4070 static struct builtincmd *
    4071 find_builtin(const char *name)
    4072 {
    4073     struct builtincmd *bp;
    4074 
    4075     bp = bsearch(
    4076         name, builtincmd, NUMBUILTINS, sizeof(struct builtincmd),
    4077         pstrcmp
    4078     );
    4079     return bp;
    4080 }
    4081 
    4082 
    4083 
    4084 /*
    4085  * Called when a cd is done.  Marks all commands so the next time they
    4086  * are executed they will be rehashed.
    4087  */
    4088 
    4089 static void
    4090 hashcd(void)
    4091 {
    4092     struct tblentry **pp;
    4093     struct tblentry *cmdp;
    4094 
    4095     for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
    4096         for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
    4097             if (cmdp->cmdtype == CMDNORMAL || (
    4098                 cmdp->cmdtype == CMDBUILTIN &&
    4099                 !(IS_BUILTIN_REGULAR(cmdp->param.cmd)) &&
    4100                 builtinloc > 0
    4101             ))
    4102                 cmdp->rehash = 1;
    4103         }
    4104     }
    4105 }
    4106 
    4107 
    4108 
    4109 /*
    4110  * Fix command hash table when PATH changed.
    4111  * Called before PATH is changed.  The argument is the new value of PATH;
    4112  * pathval() still returns the old value at this point.
    4113  * Called with interrupts off.
    4114  */
    4115 
    4116 static void
    4117 changepath(const char *newval)
    4118 {
    4119     const char *old, *new;
    4120     int idx;
    4121     int firstchange;
    4122     int idx_bltin;
    4123 
    4124     old = pathval();
    4125     new = newval;
    4126     firstchange = 9999;     /* assume no change */
    4127     idx = 0;
    4128     idx_bltin = -1;
    4129     for (;;) {
    4130         if (*old != *new) {
    4131             firstchange = idx;
    4132             if ((*old == '\0' && *new == ':')
    4133              || (*old == ':' && *new == '\0'))
    4134                 firstchange++;
    4135             old = new;      /* ignore subsequent differences */
    4136         }
    4137         if (*new == '\0')
    4138             break;
    4139         if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
    4140             idx_bltin = idx;
    4141         if (*new == ':') {
    4142             idx++;
    4143         }
    4144         new++, old++;
    4145     }
    4146     if (builtinloc < 0 && idx_bltin >= 0)
    4147         builtinloc = idx_bltin;             /* zap builtins */
    4148     if (builtinloc >= 0 && idx_bltin < 0)
    4149         firstchange = 0;
    4150     clearcmdentry(firstchange);
    4151     builtinloc = idx_bltin;
    4152 }
    4153 
    4154 
    4155 /*
    4156  * Clear out command entries.  The argument specifies the first entry in
    4157  * PATH which has changed.
    4158  */
    4159 
    4160 static void
    4161 clearcmdentry(int firstchange)
    4162 {
    4163     struct tblentry **tblp;
    4164     struct tblentry **pp;
    4165     struct tblentry *cmdp;
    4166 
    4167     INTOFF;
    4168     for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
    4169         pp = tblp;
    4170         while ((cmdp = *pp) != NULL) {
    4171             if ((cmdp->cmdtype == CMDNORMAL &&
    4172                  cmdp->param.index >= firstchange)
    4173              || (cmdp->cmdtype == CMDBUILTIN &&
    4174                  builtinloc >= firstchange)) {
    4175                 *pp = cmdp->next;
    4176                 ckfree(cmdp);
    4177             } else {
    4178                 pp = &cmdp->next;
    4179             }
    4180         }
    4181     }
    4182     INTON;
    4183 }
    4184 
    4185 
    4186 
    4187 /*
    4188  * Locate a command in the command hash table.  If "add" is nonzero,
    4189  * add the command to the table if it is not already present.  The
    4190  * variable "lastcmdentry" is set to point to the address of the link
    4191  * pointing to the entry, so that delete_cmd_entry can delete the
    4192  * entry.
    4193  *
    4194  * Interrupts must be off if called with add != 0.
    4195  */
    4196 
    4197 static struct tblentry **lastcmdentry;
    4198 
    4199 
    4200 static struct tblentry *
    4201 cmdlookup(const char *name, int add)
    4202 {
    4203     unsigned int hashval;
    4204     const char *p;
    4205     struct tblentry *cmdp;
    4206     struct tblentry **pp;
    4207 
    4208     p = name;
    4209     hashval = (unsigned char)*p << 4;
    4210     while (*p)
    4211         hashval += (unsigned char)*p++;
    4212     hashval &= 0x7FFF;
    4213     pp = &cmdtable[hashval % CMDTABLESIZE];
    4214     for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
    4215         if (equal(cmdp->cmdname, name))
    4216             break;
    4217         pp = &cmdp->next;
    4218     }
    4219     if (add && cmdp == NULL) {
    4220         cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
    4221                     + strlen(name) + 1);
    4222         cmdp->next = NULL;
    4223         cmdp->cmdtype = CMDUNKNOWN;
    4224         strcpy(cmdp->cmdname, name);
    4225     }
    4226     lastcmdentry = pp;
    4227     return cmdp;
    4228 }
    4229 
    4230 /*
    4231  * Delete the command entry returned on the last lookup.
    4232  */
    4233 
    4234 static void
    4235 delete_cmd_entry(void)
    4236 {
    4237     struct tblentry *cmdp;
    4238 
    4239     INTOFF;
    4240     cmdp = *lastcmdentry;
    4241     *lastcmdentry = cmdp->next;
    4242     if (cmdp->cmdtype == CMDFUNCTION)
    4243         freefunc(cmdp->param.func);
    4244     ckfree(cmdp);
    4245     INTON;
    4246 }
    4247 
    4248 
    4249 /*
    4250  * Add a new command entry, replacing any existing command entry for
    4251  * the same name - except special builtins.
    4252  */
    4253 
    4254 static inline void
    4255 addcmdentry(char *name, struct cmdentry *entry)
    4256 {
    4257     struct tblentry *cmdp;
    4258 
    4259     cmdp = cmdlookup(name, 1);
    4260     if (cmdp->cmdtype == CMDFUNCTION) {
    4261         freefunc(cmdp->param.func);
    4262     }
    4263     cmdp->cmdtype = entry->cmdtype;
    4264     cmdp->param = entry->u;
    4265     cmdp->rehash = 0;
    4266 }
    4267 
    4268 /*
    4269  * Make a copy of a parse tree.
    4270  */
    4271 
    4272 static inline struct funcnode *
    4273 copyfunc(union node *n)
    4274 {
    4275     struct funcnode *f;
    4276     size_t blocksize;
    4277 
    4278     funcblocksize = offsetof(struct funcnode, n);
    4279     funcstringsize = 0;
    4280     calcsize(n);
    4281     blocksize = funcblocksize;
    4282     f = ckmalloc(blocksize + funcstringsize);
    4283     funcblock = (char *) f + offsetof(struct funcnode, n);
    4284     funcstring = (char *) f + blocksize;
    4285     copynode(n);
    4286     f->count = 0;
    4287     return f;
    4288 }
    4289 
    4290 /*
    4291  * Define a shell function.
    4292  */
    4293 
    4294 static void
    4295 defun(char *name, union node *func)
    4296 {
    4297     struct cmdentry entry;
    4298 
    4299     INTOFF;
    4300     entry.cmdtype = CMDFUNCTION;
    4301     entry.u.func = copyfunc(func);
    4302     addcmdentry(name, &entry);
    4303     INTON;
    4304 }
    4305 
    4306 
    4307 /*
    4308  * Delete a function if it exists.
    4309  */
    4310 
    4311 static void
    4312 unsetfunc(const char *name)
    4313 {
    4314     struct tblentry *cmdp;
    4315 
    4316     if ((cmdp = cmdlookup(name, 0)) != NULL &&
    4317         cmdp->cmdtype == CMDFUNCTION)
    4318         delete_cmd_entry();
    4319 }
    4320 
    4321 /*
    4322  * Locate and print what a word is...
    4323  */
    4324 
    4325 
    4326 #ifdef CONFIG_ASH_CMDCMD
    4327 static int
    4328 describe_command(char *command, int describe_command_verbose)
    4329 #else
    4330 #define describe_command_verbose 1
    4331 static int
    4332 describe_command(char *command)
    4333 #endif
    4334 {
    4335     struct cmdentry entry;
    4336     struct tblentry *cmdp;
    4337 #ifdef CONFIG_ASH_ALIAS
    4338     const struct alias *ap;
    4339 #endif
    4340     const char *path = pathval();
    4341 
    4342     if (describe_command_verbose) {
    4343         out1str(command);
    4344     }
    4345 
    4346     /* First look at the keywords */
    4347     if (findkwd(command)) {
    4348         out1str(describe_command_verbose ? " is a shell keyword" : command);
    4349         goto out;
    4350     }
    4351 
    4352 #ifdef CONFIG_ASH_ALIAS
    4353     /* Then look at the aliases */
    4354     if ((ap = lookupalias(command, 0)) != NULL) {
    4355         if (describe_command_verbose) {
    4356             out1fmt(" is an alias for %s", ap->val);
    4357         } else {
    4358             out1str("alias ");
    4359             printalias(ap);
    4360             return 0;
    4361         }
    4362         goto out;
    4363     }
    4364 #endif
    4365     /* Then check if it is a tracked alias */
    4366     if ((cmdp = cmdlookup(command, 0)) != NULL) {
    4367         entry.cmdtype = cmdp->cmdtype;
    4368         entry.u = cmdp->param;
    4369     } else {
    4370         /* Finally use brute force */
    4371         find_command(command, &entry, DO_ABS, path);
    4372     }
    4373 
    4374     switch (entry.cmdtype) {
    4375     case CMDNORMAL: {
    4376         int j = entry.u.index;
    4377         char *p;
    4378         if (j == -1) {
    4379             p = command;
    4380         } else {
    4381             do {
    4382                 p = padvance(&path, command);
    4383                 stunalloc(p);
    4384             } while (--j >= 0);
    4385         }
    4386         if (describe_command_verbose) {
    4387             out1fmt(" is%s %s",
    4388                 (cmdp ? " a tracked alias for" : nullstr), p
    4389             );
    4390         } else {
    4391             out1str(p);
    4392         }
    4393         break;
    4394     }
    4395 
    4396     case CMDFUNCTION:
    4397         if (describe_command_verbose) {
    4398             out1str(" is a shell function");
    4399         } else {
    4400             out1str(command);
    4401         }
    4402         break;
    4403 
    4404     case CMDBUILTIN:
    4405         if (describe_command_verbose) {
    4406             out1fmt(" is a %sshell builtin",
    4407                 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
    4408                     "special " : nullstr
    4409             );
    4410         } else {
    4411             out1str(command);
    4412         }
    4413         break;
    4414 
    4415     default:
    4416         if (describe_command_verbose) {
    4417             out1str(": not found\n");
    4418         }
    4419         return 127;
    4420     }
    4421 
    4422 out:
    4423     outstr("\n", stdout);
    4424     return 0;
    4425 }
    4426 
    4427 static int
    4428 typecmd(int argc, char **argv)
    4429 {
    4430     int i;
    4431     int err = 0;
    4432 
    4433     for (i = 1; i < argc; i++) {
    4434 #ifdef CONFIG_ASH_CMDCMD
    4435         err |= describe_command(argv[i], 1);
    4436 #else
    4437         err |= describe_command(argv[i]);
    4438 #endif
    4439     }
    4440     return err;
    4441 }
    4442 
    4443 #ifdef CONFIG_ASH_CMDCMD
    4444 static int
    4445 commandcmd(int argc, char **argv)
    4446 {
    4447     int c;
    4448     enum {
    4449         VERIFY_BRIEF = 1,
    4450         VERIFY_VERBOSE = 2,
    4451     } verify = 0;
    4452 
    4453     while ((c = nextopt("pvV")) != '\0')
    4454         if (c == 'V')
    4455             verify |= VERIFY_VERBOSE;
    4456         else if (c == 'v')
    4457             verify |= VERIFY_BRIEF;
    4458 #ifdef DEBUG
    4459         else if (c != 'p')
    4460             abort();
    4461 #endif
    4462     if (verify)
    4463         return describe_command(*argptr, verify - VERIFY_BRIEF);
    4464 
    4465     return 0;
    4466 }
    4467 #endif
    4468 
    4469 /*      expand.c     */
    4470 
    4471 /*
    4472  * Routines to expand arguments to commands.  We have to deal with
    4473  * backquotes, shell variables, and file metacharacters.
    4474  */
    4475 
    4476 /*
    4477  * _rmescape() flags
    4478  */
    4479 #define RMESCAPE_ALLOC  0x1     /* Allocate a new string */
    4480 #define RMESCAPE_GLOB   0x2     /* Add backslashes for glob */
    4481 #define RMESCAPE_QUOTED 0x4     /* Remove CTLESC unless in quotes */
    4482 #define RMESCAPE_GROW   0x8     /* Grow strings instead of stalloc */
    4483 #define RMESCAPE_HEAP   0x10    /* Malloc strings instead of stalloc */
    4484 
    4485 /*
    4486  * Structure specifying which parts of the string should be searched
    4487  * for IFS characters.
    4488  */
    4489 
    4490 struct ifsregion {
    4491     struct ifsregion *next; /* next region in list */
    4492     int begoff;             /* offset of start of region */
    4493     int endoff;             /* offset of end of region */
    4494     int nulonly;            /* search for nul bytes only */
    4495 };
    4496 
    4497 /* output of current string */
    4498 static char *expdest;
    4499 /* list of back quote expressions */
    4500 static struct nodelist *argbackq;
    4501 /* first struct in list of ifs regions */
    4502 static struct ifsregion ifsfirst;
    4503 /* last struct in list */
    4504 static struct ifsregion *ifslastp;
    4505 /* holds expanded arg list */
    4506 static struct arglist exparg;
    4507 
    4508 static void argstr(char *, int);
    4509 static char *exptilde(char *, char *, int);
    4510 static void expbackq(union node *, int, int);
    4511 static const char *subevalvar(char *, char *, int, int, int, int, int);
    4512 static char *evalvar(char *, int);
    4513 static void strtodest(const char *, int, int);
    4514 static void memtodest(const char *p, size_t len, int syntax, int quotes);
    4515 static ssize_t varvalue(char *, int, int);
    4516 static void recordregion(int, int, int);
    4517 static void removerecordregions(int);
    4518 static void ifsbreakup(char *, struct arglist *);
    4519 static void ifsfree(void);
    4520 static void expandmeta(struct strlist *, int);
    4521 static int patmatch(char *, const char *);
    4522 
    4523 static int cvtnum(arith_t);
    4524 static size_t esclen(const char *, const char *);
    4525 static char *scanleft(char *, char *, char *, char *, int, int);
    4526 static char *scanright(char *, char *, char *, char *, int, int);
    4527 static void varunset(const char *, const char *, const char *, int)
    4528     ATTRIBUTE_NORETURN;
    4529 
    4530 
    4531 #define pmatch(a, b) !fnmatch((a), (b), 0)
    4532 /*
    4533  * Prepare a pattern for a expmeta (internal glob(3)) call.
    4534  *
    4535  * Returns an stalloced string.
    4536  */
    4537 
    4538 static inline char *
    4539 preglob(const char *pattern, int quoted, int flag) {
    4540     flag |= RMESCAPE_GLOB;
    4541     if (quoted) {
    4542         flag |= RMESCAPE_QUOTED;
    4543     }
    4544     return _rmescapes((char *)pattern, flag);
    4545 }
    4546 
    4547 
    4548 static size_t
    4549 esclen(const char *start, const char *p) {
    4550     size_t esc = 0;
    4551 
    4552     while (p > start && *--p == CTLESC) {
    4553         esc++;
    4554     }
    4555     return esc;
    4556 }
    4557 
    4558 
    4559 /*
    4560  * Expand shell variables and backquotes inside a here document.
    4561  */
    4562 
    4563 static inline void
    4564 expandhere(union node *arg, int fd)
    4565 {
    4566     herefd = fd;
    4567     expandarg(arg, (struct arglist *)NULL, 0);
    4568     bb_full_write(fd, stackblock(), expdest - (char *)stackblock());
    4569 }
    4570 
    4571 
    4572 /*
    4573  * Perform variable substitution and command substitution on an argument,
    4574  * placing the resulting list of arguments in arglist.  If EXP_FULL is true,
    4575  * perform splitting and file name expansion.  When arglist is NULL, perform
    4576  * here document expansion.
    4577  */
    4578 
    4579 void
    4580 expandarg(union node *arg, struct arglist *arglist, int flag)
    4581 {
    4582     struct strlist *sp;
    4583     char *p;
    4584 
    4585     argbackq = arg->narg.backquote;
    4586     STARTSTACKSTR(expdest);
    4587     ifsfirst.next = NULL;
    4588     ifslastp = NULL;
    4589     argstr(arg->narg.text, flag);
    4590     p = _STPUTC('\0', expdest);
    4591     expdest = p - 1;
    4592     if (arglist == NULL) {
    4593         return;                 /* here document expanded */
    4594     }
    4595     p = grabstackstr(p);
    4596     exparg.lastp = &exparg.list;
    4597     /*
    4598      * TODO - EXP_REDIR
    4599      */
    4600     if (flag & EXP_FULL) {
    4601         ifsbreakup(p, &exparg);
    4602         *exparg.lastp = NULL;
    4603         exparg.lastp = &exparg.list;
    4604         expandmeta(exparg.list, flag);
    4605     } else {
    4606         if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
    4607             rmescapes(p);
    4608         sp = (struct strlist *)stalloc(sizeof (struct strlist));
    4609         sp->text = p;
    4610         *exparg.lastp = sp;
    4611         exparg.lastp = &sp->next;
    4612     }
    4613     if (ifsfirst.next)
    4614         ifsfree();
    4615     *exparg.lastp = NULL;
    4616     if (exparg.list) {
    4617         *arglist->lastp = exparg.list;
    4618         arglist->lastp = exparg.lastp;
    4619     }
    4620 }
    4621 
    4622 
    4623 /*
    4624  * Perform variable and command substitution.  If EXP_FULL is set, output CTLESC
    4625  * characters to allow for further processing.  Otherwise treat
    4626  * $@ like $* since no splitting will be performed.
    4627  */
    4628 
    4629 static void
    4630 argstr(char *p, int flag)
    4631 {
    4632     static const char spclchars[] = {
    4633         '=',
    4634         ':',
    4635         CTLQUOTEMARK,
    4636         CTLENDVAR,
    4637         CTLESC,
    4638         CTLVAR,
    4639         CTLBACKQ,
    4640         CTLBACKQ | CTLQUOTE,
    4641 #ifdef CONFIG_ASH_MATH_SUPPORT
    4642         CTLENDARI,
    4643 #endif
    4644         0
    4645     };
    4646     const char *reject = spclchars;
    4647     int c;
    4648     int quotes = flag & (EXP_FULL | EXP_CASE);      /* do CTLESC */
    4649     int breakall = flag & EXP_WORD;
    4650     int inquotes;
    4651     size_t length;
    4652     int startloc;
    4653 
    4654     if (!(flag & EXP_VARTILDE)) {
    4655         reject += 2;
    4656     } else if (flag & EXP_VARTILDE2) {
    4657         reject++;
    4658     }
    4659     inquotes = 0;
    4660     length = 0;
    4661     if (flag & EXP_TILDE) {
    4662         char *q;
    4663 
    4664         flag &= ~EXP_TILDE;
    4665 tilde:
    4666         q = p;
    4667         if (*q == CTLESC && (flag & EXP_QWORD))
    4668             q++;
    4669         if (*q == '~')
    4670             p = exptilde(p, q, flag);
    4671     }
    4672 start:
    4673     startloc = expdest - (char *)stackblock();
    4674     for (;;) {
    4675         length += strcspn(p + length, reject);
    4676         c = p[length];
    4677         if (c && (!(c & 0x80)
    4678 #ifdef CONFIG_ASH_MATH_SUPPORT
    4679                     || c == CTLENDARI
    4680 #endif
    4681            )) {
    4682             /* c == '=' || c == ':' || c == CTLENDARI */
    4683             length++;
    4684         }
    4685         if (length > 0) {
    4686             int newloc;
    4687             expdest = stnputs(p, length, expdest);
    4688             newloc = expdest - (char *)stackblock();
    4689             if (breakall && !inquotes && newloc > startloc) {
    4690                 recordregion(startloc, newloc, 0);
    4691             }
    4692             startloc = newloc;
    4693         }
    4694         p += length + 1;
    4695         length = 0;
    4696 
    4697         switch (c) {
    4698         case '\0':
    4699             goto breakloop;
    4700         case '=':
    4701             if (flag & EXP_VARTILDE2) {
    4702                 p--;
    4703                 continue;
    4704             }
    4705             flag |= EXP_VARTILDE2;
    4706             reject++;
    4707             /* fall through */
    4708         case ':':
    4709             /*
    4710              * sort of a hack - expand tildes in variable
    4711              * assignments (after the first '=' and after ':'s).
    4712              */
    4713             if (*--p == '~') {
    4714                 goto tilde;
    4715             }
    4716             continue;
    4717         }
    4718 
    4719         switch (c) {
    4720         case CTLENDVAR: /* ??? */
    4721             goto breakloop;
    4722         case CTLQUOTEMARK:
    4723             /* "$@" syntax adherence hack */
    4724             if (
    4725                 !inquotes &&
    4726                 !memcmp(p, dolatstr, DOLATSTRLEN) &&
    4727                 (p[4] == CTLQUOTEMARK || (
    4728                     p[4] == CTLENDVAR &&
    4729                     p[5] == CTLQUOTEMARK
    4730                 ))
    4731             ) {
    4732                 p = evalvar(p + 1, flag) + 1;
    4733                 goto start;
    4734             }
    4735             inquotes = !inquotes;
    4736 addquote:
    4737             if (quotes) {
    4738                 p--;
    4739                 length++;
    4740                 startloc++;
    4741             }
    4742             break;
    4743         case CTLESC:
    4744             startloc++;
    4745             length++;
    4746             goto addquote;
    4747         case CTLVAR:
    4748             p = evalvar(p, flag);
    4749             goto start;
    4750         case CTLBACKQ:
    4751             c = 0;
    4752         case CTLBACKQ|CTLQUOTE:
    4753             expbackq(argbackq->n, c, quotes);
    4754             argbackq = argbackq->next;
    4755             goto start;
    4756 #ifdef CONFIG_ASH_MATH_SUPPORT
    4757         case CTLENDARI:
    4758             p--;
    4759             expari(quotes);
    4760             goto start;
    4761 #endif
    4762         }
    4763     }
    4764 breakloop:
    4765     ;
    4766 }
    4767 
    4768 static char *
    4769 exptilde(char *startp, char *p, int flag)
    4770 {
    4771     char c;
    4772     char *name;
    4773     struct passwd *pw;
    4774     const char *home;
    4775     int quotes = flag & (EXP_FULL | EXP_CASE);
    4776     int startloc;
    4777 
    4778     name = p + 1;
    4779 
    4780     while ((c = *++p) != '\0') {
    4781         switch(c) {
    4782         case CTLESC:
    4783             return (startp);
    4784         case CTLQUOTEMARK:
    4785             return (startp);
    4786         case ':':
    4787             if (flag & EXP_VARTILDE)
    4788                 goto done;
    4789             break;
    4790         case '/':
    4791         case CTLENDVAR:
    4792             goto done;
    4793         }
    4794     }
    4795 done:
    4796     *p = '\0';
    4797     if (*name == '\0') {
    4798         home = lookupvar(homestr);
    4799     } else {
    4800         if ((pw = getpwnam(name)) == NULL)
    4801             goto lose;
    4802         home = pw->pw_dir;
    4803     }
    4804     if (!home || !*home)
    4805         goto lose;
    4806     *p = c;
    4807     startloc = expdest - (char *)stackblock();
    4808     strtodest(home, SQSYNTAX, quotes);
    4809     recordregion(startloc, expdest - (char *)stackblock(), 0);
    4810     return (p);
    4811 lose:
    4812     *p = c;
    4813     return (startp);
    4814 }
    4815 
    4816 
    4817 static void
    4818 removerecordregions(int endoff)
    4819 {
    4820     if (ifslastp == NULL)
    4821         return;
    4822 
    4823     if (ifsfirst.endoff > endoff) {
    4824         while (ifsfirst.next != NULL) {
    4825             struct ifsregion *ifsp;
    4826             INTOFF;
    4827             ifsp = ifsfirst.next->next;
    4828             ckfree(ifsfirst.next);
    4829             ifsfirst.next = ifsp;
    4830             INTON;
    4831         }
    4832         if (ifsfirst.begoff > endoff)
    4833             ifslastp = NULL;
    4834         else {
    4835             ifslastp = &ifsfirst;
    4836             ifsfirst.endoff = endoff;
    4837         }
    4838         return;
    4839     }
    4840 
    4841     ifslastp = &ifsfirst;
    4842     while (ifslastp->next && ifslastp->next->begoff < endoff)
    4843         ifslastp=ifslastp->next;
    4844     while (ifslastp->next != NULL) {
    4845         struct ifsregion *ifsp;
    4846         INTOFF;
    4847         ifsp = ifslastp->next->next;
    4848         ckfree(ifslastp->next);
    4849         ifslastp->next = ifsp;
    4850         INTON;
    4851     }
    4852     if (ifslastp->endoff > endoff)
    4853         ifslastp->endoff = endoff;
    4854 }
    4855 
    4856 
    4857 #ifdef CONFIG_ASH_MATH_SUPPORT
    4858 /*
    4859  * Expand arithmetic expression.  Backup to start of expression,
    4860  * evaluate, place result in (backed up) result, adjust string position.
    4861  */
    4862 void
    4863 expari(int quotes)
    4864 {
    4865     char *p, *start;
    4866     int begoff;
    4867     int flag;
    4868     int len;
    4869 
    4870     /*      ifsfree(); */
    4871 
    4872     /*
    4873      * This routine is slightly over-complicated for
    4874      * efficiency.  Next we scan backwards looking for the
    4875      * start of arithmetic.
    4876      */
    4877     start = stackblock();
    4878     p = expdest - 1;
    4879     *p = '\0';
    4880     p--;
    4881     do {
    4882         int esc;
    4883 
    4884         while (*p != CTLARI) {
    4885             p--;
    4886 #ifdef DEBUG
    4887             if (p < start) {
    4888                 sh_error("missing CTLARI (shouldn't happen)");
    4889             }
    4890 #endif
    4891         }
    4892 
    4893         esc = esclen(start, p);
    4894         if (!(esc % 2)) {
    4895             break;
    4896         }
    4897 
    4898         p -= esc + 1;
    4899     } while (1);
    4900 
    4901     begoff = p - start;
    4902 
    4903     removerecordregions(begoff);
    4904 
    4905     flag = p[1];
    4906 
    4907     expdest = p;
    4908 
    4909     if (quotes)
    4910         rmescapes(p + 2);
    4911 
    4912     len = cvtnum(dash_arith(p + 2));
    4913 
    4914     if (flag != '"')
    4915         recordregion(begoff, begoff + len, 0);
    4916 }
    4917 #endif
    4918 
    4919 /*
    4920  * Expand stuff in backwards quotes.
    4921  */
    4922 
    4923 static void
    4924 expbackq(union node *cmd, int quoted, int quotes)
    4925 {
    4926     struct backcmd in;
    4927     int i;
    4928     char buf[128];
    4929     char *p;
    4930     char *dest;
    4931     int startloc;
    4932     int syntax = quoted? DQSYNTAX : BASESYNTAX;
    4933     struct stackmark smark;
    4934 
    4935     INTOFF;
    4936     setstackmark(&smark);
    4937     dest = expdest;
    4938     startloc = dest - (char *)stackblock();
    4939     grabstackstr(dest);
    4940     evalbackcmd(cmd, (struct backcmd *) &in);
    4941     popstackmark(&smark);
    4942 
    4943     p = in.buf;
    4944     i = in.nleft;
    4945     if (i == 0)
    4946         goto read;
    4947     for (;;) {
    4948         memtodest(p, i, syntax, quotes);
    4949 read:
    4950         if (in.fd < 0)
    4951             break;
    4952         i = safe_read(in.fd, buf, sizeof buf);
    4953         TRACE(("expbackq: read returns %d\n", i));
    4954         if (i <= 0)
    4955             break;
    4956         p = buf;
    4957     }
    4958 
    4959     if (in.buf)
    4960         ckfree(in.buf);
    4961     if (in.fd >= 0) {
    4962         close(in.fd);
    4963         back_exitstatus = waitforjob(in.jp);
    4964     }
    4965     INTON;
    4966 
    4967     /* Eat all trailing newlines */
    4968     dest = expdest;
    4969     for (; dest > (char *)stackblock() && dest[-1] == '\n';)
    4970         STUNPUTC(dest);
    4971     expdest = dest;
    4972 
    4973     if (quoted == 0)
    4974         recordregion(startloc, dest - (char *)stackblock(), 0);
    4975     TRACE(("evalbackq: size=%d: \"%.*s\"\n",
    4976         (dest - (char *)stackblock()) - startloc,
    4977         (dest - (char *)stackblock()) - startloc,
    4978         stackblock() + startloc));
    4979 }
    4980 
    4981 
    4982 static char *
    4983 scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
    4984     int zero)
    4985 {
    4986     char *loc;
    4987     char *loc2;
    4988     char c;
    4989 
    4990     loc = startp;
    4991     loc2 = rmesc;
    4992     do {
    4993         int match;
    4994         const char *s = loc2;
    4995         c = *loc2;
    4996         if (zero) {
    4997             *loc2 = '\0';
    4998             s = rmesc;
    4999         }
    5000         match = pmatch(str, s);
    5001         *loc2 = c;
    5002         if (match)
    5003             return loc;
    5004         if (quotes && *loc == CTLESC)
    5005             loc++;
    5006         loc++;
    5007         loc2++;
    5008     } while (c);
    5009     return 0;
    5010 }
    5011 
    5012 
    5013 static char *
    5014 scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
    5015     int zero)
    5016 {
    5017     int esc = 0;
    5018     char *loc;
    5019     char *loc2;
    5020 
    5021     for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
    5022         int match;
    5023         char c = *loc2;
    5024         const char *s = loc2;
    5025         if (zero) {
    5026             *loc2 = '\0';
    5027             s = rmesc;
    5028         }
    5029         match = pmatch(str, s);
    5030         *loc2 = c;
    5031         if (match)
    5032             return loc;
    5033         loc--;
    5034         if (quotes) {
    5035             if (--esc < 0) {
    5036                 esc = esclen(startp, loc);
    5037             }
    5038             if (esc % 2) {
    5039                 esc--;
    5040                 loc--;
    5041             }
    5042         }
    5043     }
    5044     return 0;
    5045 }
    5046 
    5047 static const char *
    5048 subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
    5049 {
    5050     char *startp;
    5051     char *loc;
    5052     int saveherefd = herefd;
    5053     struct nodelist *saveargbackq = argbackq;
    5054     int amount;
    5055     char *rmesc, *rmescend;
    5056     int zero;
    5057     char *(*scan)(char *, char *, char *, char *, int , int);
    5058 
    5059     herefd = -1;
    5060     argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
    5061     STPUTC('\0', expdest);
    5062     herefd = saveherefd;
    5063     argbackq = saveargbackq;
    5064     startp = stackblock() + startloc;
    5065 
    5066     switch (subtype) {
    5067     case VSASSIGN:
    5068         setvar(str, startp, 0);
    5069         amount = startp - expdest;
    5070         STADJUST(amount, expdest);
    5071         return startp;
    5072 
    5073     case VSQUESTION:
    5074         varunset(p, str, startp, varflags);
    5075         /* NOTREACHED */
    5076     }
    5077 
    5078     subtype -= VSTRIMRIGHT;
    5079 #ifdef DEBUG
    5080     if (subtype < 0 || subtype > 3)
    5081         abort();
    5082 #endif
    5083 
    5084     rmesc = startp;
    5085     rmescend = stackblock() + strloc;
    5086     if (quotes) {
    5087         rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
    5088         if (rmesc != startp) {
    5089             rmescend = expdest;
    5090             startp = stackblock() + startloc;
    5091         }
    5092     }
    5093     rmescend--;
    5094     str = stackblock() + strloc;
    5095     preglob(str, varflags & VSQUOTE, 0);
    5096 
    5097     /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
    5098     zero = subtype >> 1;
    5099     /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
    5100     scan = (subtype & 1) ^ zero ? scanleft : scanright;
    5101 
    5102     loc = scan(startp, rmesc, rmescend, str, quotes, zero);
    5103     if (loc) {
    5104         if (zero) {
    5105             memmove(startp, loc, str - loc);
    5106             loc = startp + (str - loc) - 1;
    5107         }
    5108         *loc = '\0';
    5109         amount = loc - expdest;
    5110         STADJUST(amount, expdest);
    5111     }
    5112     return loc;
    5113 }
    5114 
    5115 
    5116 /*
    5117  * Expand a variable, and return a pointer to the next character in the
    5118  * input string.
    5119  */
    5120 static char *
    5121 evalvar(char *p, int flag)
    5122 {
    5123     int subtype;
    5124     int varflags;
    5125     char *var;
    5126     int patloc;
    5127     int c;
    5128     int startloc;
    5129     ssize_t varlen;
    5130     int easy;
    5131     int quotes;
    5132     int quoted;
    5133 
    5134     quotes = flag & (EXP_FULL | EXP_CASE);
    5135     varflags = *p++;
    5136     subtype = varflags & VSTYPE;
    5137     quoted = varflags & VSQUOTE;
    5138     var = p;
    5139     easy = (!quoted || (*var == '@' && shellparam.nparam));
    5140     startloc = expdest - (char *)stackblock();
    5141     p = strchr(p, '=') + 1;
    5142 
    5143 again:
    5144     varlen = varvalue(var, varflags, flag);
    5145     if (varflags & VSNUL)
    5146         varlen--;
    5147 
    5148     if (subtype == VSPLUS) {
    5149         varlen = -1 - varlen;
    5150         goto vsplus;
    5151     }
    5152 
    5153     if (subtype == VSMINUS) {
    5154 vsplus:
    5155         if (varlen < 0) {
    5156             argstr(
    5157                 p, flag | EXP_TILDE |
    5158                     (quoted ?  EXP_QWORD : EXP_WORD)
    5159             );
    5160             goto end;
    5161         }
    5162         if (easy)
    5163             goto record;
    5164         goto end;
    5165     }
    5166 
    5167     if (subtype == VSASSIGN || subtype == VSQUESTION) {
    5168         if (varlen < 0) {
    5169             if (subevalvar(p, var, 0, subtype, startloc,
    5170                        varflags, 0)) {
    5171                 varflags &= ~VSNUL;
    5172                 /*
    5173                  * Remove any recorded regions beyond
    5174                  * start of variable
    5175                  */
    5176                 removerecordregions(startloc);
    5177                 goto again;
    5178             }
    5179             goto end;
    5180         }
    5181         if (easy)
    5182             goto record;
    5183         goto end;
    5184     }
    5185 
    5186     if (varlen < 0 && uflag)
    5187         varunset(p, var, 0, 0);
    5188 
    5189     if (subtype == VSLENGTH) {
    5190         cvtnum(varlen > 0 ? varlen : 0);
    5191         goto record;
    5192     }
    5193 
    5194     if (subtype == VSNORMAL) {
    5195         if (!easy)
    5196             goto end;
    5197 record:
    5198         recordregion(startloc, expdest - (char *)stackblock(), quoted);
    5199         goto end;
    5200     }
    5201 
    5202 #ifdef DEBUG
    5203     switch (subtype) {
    5204     case VSTRIMLEFT:
    5205     case VSTRIMLEFTMAX:
    5206     case VSTRIMRIGHT:
    5207     case VSTRIMRIGHTMAX:
    5208         break;
    5209     default:
    5210         abort();
    5211     }
    5212 #endif
    5213 
    5214     if (varlen >= 0) {
    5215         /*
    5216          * Terminate the string and start recording the pattern
    5217          * right after it
    5218          */
    5219         STPUTC('\0', expdest);
    5220         patloc = expdest - (char *)stackblock();
    5221         if (subevalvar(p, NULL, patloc, subtype,
    5222                    startloc, varflags, quotes) == 0) {
    5223             int amount = expdest - (
    5224                 (char *)stackblock() + patloc - 1
    5225             );
    5226             STADJUST(-amount, expdest);
    5227         }
    5228         /* Remove any recorded regions beyond start of variable */
    5229         removerecordregions(startloc);
    5230         goto record;
    5231     }
    5232 
    5233 end:
    5234     if (subtype != VSNORMAL) {      /* skip to end of alternative */
    5235         int nesting = 1;
    5236         for (;;) {
    5237             if ((c = *p++) == CTLESC)
    5238                 p++;
    5239             else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
    5240                 if (varlen >= 0)
    5241                     argbackq = argbackq->next;
    5242             } else if (c == CTLVAR) {
    5243                 if ((*p++ & VSTYPE) != VSNORMAL)
    5244                     nesting++;
    5245             } else if (c == CTLENDVAR) {
    5246                 if (--nesting == 0)
    5247                     break;
    5248             }
    5249         }
    5250     }
    5251     return p;
    5252 }
    5253 
    5254 
    5255 /*
    5256  * Put a string on the stack.
    5257  */
    5258 
    5259 static void
    5260 memtodest(const char *p, size_t len, int syntax, int quotes) {
    5261     char *q = expdest;
    5262 
    5263     q = makestrspace(len * 2, q);
    5264 
    5265     while (len--) {
    5266         int c = SC2INT(*p++);
    5267         if (!c)
    5268             continue;
    5269         if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
    5270             USTPUTC(CTLESC, q);
    5271         USTPUTC(c, q);
    5272     }
    5273 
    5274     expdest = q;
    5275 }
    5276 
    5277 
    5278 static void
    5279 strtodest(const char *p, int syntax, int quotes)
    5280 {
    5281     memtodest(p, strlen(p), syntax, quotes);
    5282 }
    5283 
    5284 
    5285 /*
    5286  * Add the value of a specialized variable to the stack string.
    5287  */
    5288 
    5289 static ssize_t
    5290 varvalue(char *name, int varflags, int flags)
    5291 {
    5292     int num;
    5293     char *p;
    5294     int i;
    5295     int sep = 0;
    5296     int sepq = 0;
    5297     ssize_t len = 0;
    5298     char **ap;
    5299     int syntax;
    5300     int quoted = varflags & VSQUOTE;
    5301     int subtype = varflags & VSTYPE;
    5302     int quotes = flags & (EXP_FULL | EXP_CASE);
    5303 
    5304     if (quoted && (flags & EXP_FULL))
    5305         sep = 1 << CHAR_BIT;
    5306 
    5307     syntax = quoted ? DQSYNTAX : BASESYNTAX;
    5308     switch (*name) {
    5309     case '$':
    5310         num = rootpid;
    5311         goto numvar;
    5312     case '?':
    5313         num = exitstatus;
    5314         goto numvar;
    5315     case '#':
    5316         num = shellparam.nparam;
    5317         goto numvar;
    5318     case '!':
    5319         num = backgndpid;
    5320         if (num == 0)
    5321             return -1;
    5322 numvar:
    5323         len = cvtnum(num);
    5324         break;
    5325     case '-':
    5326         p = makestrspace(NOPTS, expdest);
    5327         for (i = NOPTS - 1; i >= 0; i--) {
    5328             if (optlist[i]) {
    5329                 USTPUTC(optletters(i), p);
    5330                 len++;
    5331             }
    5332         }
    5333         expdest = p;
    5334         break;
    5335     case '@':
    5336         if (sep)
    5337             goto param;
    5338         /* fall through */
    5339     case '*':
    5340         sep = ifsset() ? SC2INT(ifsval()[0]) : ' ';
    5341         if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))
    5342             sepq = 1;
    5343 param:
    5344         if (!(ap = shellparam.p))
    5345             return -1;
    5346         while ((p = *ap++)) {
    5347             size_t partlen;
    5348 
    5349             partlen = strlen(p);
    5350             len += partlen;
    5351 
    5352             if (!(subtype == VSPLUS || subtype == VSLENGTH))
    5353                 memtodest(p, partlen, syntax, quotes);
    5354 
    5355             if (*ap && sep) {
    5356                 char *q;
    5357 
    5358                 len++;
    5359                 if (subtype == VSPLUS || subtype == VSLENGTH) {
    5360                     continue;
    5361                 }
    5362                 q = expdest;
    5363                 if (sepq)
    5364                     STPUTC(CTLESC, q);
    5365                 STPUTC(sep, q);
    5366                 expdest = q;
    5367             }
    5368         }
    5369         return len;
    5370     case '0':
    5371     case '1':
    5372     case '2':
    5373     case '3':
    5374     case '4':
    5375     case '5':
    5376     case '6':
    5377     case '7':
    5378     case '8':
    5379     case '9':
    5380         num = atoi(name);
    5381         if (num < 0 || num > shellparam.nparam)
    5382             return -1;
    5383         p = num ? shellparam.p[num - 1] : arg0;
    5384         goto value;
    5385     default:
    5386         p = lookupvar(name);
    5387 value:
    5388         if (!p)
    5389             return -1;
    5390 
    5391         len = strlen(p);
    5392         if (!(subtype == VSPLUS || subtype == VSLENGTH))
    5393             memtodest(p, len, syntax, quotes);
    5394         return len;
    5395     }
    5396 
    5397     if (subtype == VSPLUS || subtype == VSLENGTH)
    5398         STADJUST(-len, expdest);
    5399     return len;
    5400 }
    5401 
    5402 
    5403 /*
    5404  * Record the fact that we have to scan this region of the
    5405  * string for IFS characters.
    5406  */
    5407 
    5408 static void
    5409 recordregion(int start, int end, int nulonly)
    5410 {
    5411     struct ifsregion *ifsp;
    5412 
    5413     if (ifslastp == NULL) {
    5414         ifsp = &ifsfirst;
    5415     } else {
    5416         INTOFF;
    5417         ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
    5418         ifsp->next = NULL;
    5419         ifslastp->next = ifsp;
    5420         INTON;
    5421     }
    5422     ifslastp = ifsp;
    5423     ifslastp->begoff = start;
    5424     ifslastp->endoff = end;
    5425     ifslastp->nulonly = nulonly;
    5426 }
    5427 
    5428 
    5429 /*
    5430  * Break the argument string into pieces based upon IFS and add the
    5431  * strings to the argument list.  The regions of the string to be
    5432  * searched for IFS characters have been stored by recordregion.
    5433  */
    5434 static void
    5435 ifsbreakup(char *string, struct arglist *arglist)
    5436 {
    5437     struct ifsregion *ifsp;
    5438     struct strlist *sp;
    5439     char *start;
    5440     char *p;
    5441     char *q;
    5442     const char *ifs, *realifs;
    5443     int ifsspc;
    5444     int nulonly;
    5445 
    5446 
    5447     start = string;
    5448     if (ifslastp != NULL) {
    5449         ifsspc = 0;
    5450         nulonly = 0;
    5451         realifs = ifsset() ? ifsval() : defifs;
    5452         ifsp = &ifsfirst;
    5453         do {
    5454             p = string + ifsp->begoff;
    5455             nulonly = ifsp->nulonly;
    5456             ifs = nulonly ? nullstr : realifs;
    5457             ifsspc = 0;
    5458             while (p < string + ifsp->endoff) {
    5459                 q = p;
    5460                 if (*p == CTLESC)
    5461                     p++;
    5462                 if (strchr(ifs, *p)) {
    5463                     if (!nulonly)
    5464                         ifsspc = (strchr(defifs, *p) != NULL);
    5465                     /* Ignore IFS whitespace at start */
    5466                     if (q == start && ifsspc) {
    5467                         p++;
    5468                         start = p;
    5469                         continue;
    5470                     }
    5471                     *q = '\0';
    5472                     sp = (struct strlist *)stalloc(sizeof *sp);
    5473                     sp->text = start;
    5474                     *arglist->lastp = sp;
    5475                     arglist->lastp = &sp->next;
    5476                     p++;
    5477                     if (!nulonly) {
    5478                         for (;;) {
    5479                             if (p >= string + ifsp->endoff) {
    5480                                 break;
    5481                             }
    5482                             q = p;
    5483                             if (*p == CTLESC)
    5484                                 p++;
    5485                             if (strchr(ifs, *p) == NULL ) {
    5486                                 p = q;
    5487                                 break;
    5488                             } else if (strchr(defifs, *p) == NULL) {
    5489                                 if (ifsspc) {
    5490                                     p++;
    5491                                     ifsspc = 0;
    5492                                 } else {
    5493                                     p = q;
    5494                                     break;
    5495                                 }
    5496                             } else
    5497                                 p++;
    5498                         }
    5499                     }
    5500                     start = p;
    5501                 } else
    5502                     p++;
    5503             }
    5504         } while ((ifsp = ifsp->next) != NULL);
    5505         if (nulonly)
    5506             goto add;
    5507     }
    5508 
    5509     if (!*start)
    5510         return;
    5511 
    5512 add:
    5513     sp = (struct strlist *)stalloc(sizeof *sp);
    5514     sp->text = start;
    5515     *arglist->lastp = sp;
    5516     arglist->lastp = &sp->next;
    5517 }
    5518 
    5519 static void
    5520 ifsfree(void)
    5521 {
    5522     struct ifsregion *p;
    5523 
    5524     INTOFF;
    5525     p = ifsfirst.next;
    5526     do {
    5527         struct ifsregion *ifsp;
    5528         ifsp = p->next;
    5529         ckfree(p);
    5530         p = ifsp;
    5531     } while (p);
    5532     ifslastp = NULL;
    5533     ifsfirst.next = NULL;
    5534     INTON;
    5535 }
    5536 
    5537 static void expmeta(char *, char *);
    5538 static struct strlist *expsort(struct strlist *);
    5539 static struct strlist *msort(struct strlist *, int);
    5540 
    5541 static char *expdir;
    5542 
    5543 
    5544 static void
    5545 expandmeta(struct strlist *str, int flag)
    5546 {
    5547     static const char metachars[] = {
    5548         '*', '?', '[', 0
    5549     };
    5550     /* TODO - EXP_REDIR */
    5551 
    5552     while (str) {
    5553         struct strlist **savelastp;
    5554         struct strlist *sp;
    5555         char *p;
    5556 
    5557         if (fflag)
    5558             goto nometa;
    5559         if (!strpbrk(str->text, metachars))
    5560             goto nometa;
    5561         savelastp = exparg.lastp;
    5562 
    5563         INTOFF;
    5564         p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
    5565         {
    5566             int i = strlen(str->text);
    5567             expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
    5568         }
    5569 
    5570         expmeta(expdir, p);
    5571         ckfree(expdir);
    5572         if (p != str->text)
    5573             ckfree(p);
    5574         INTON;
    5575         if (exparg.lastp == savelastp) {
    5576             /*
    5577              * no matches
    5578              */
    5579 nometa:
    5580             *exparg.lastp = str;
    5581             rmescapes(str->text);
    5582             exparg.lastp = &str->next;
    5583         } else {
    5584             *exparg.lastp = NULL;
    5585             *savelastp = sp = expsort(*savelastp);
    5586             while (sp->next != NULL)
    5587                 sp = sp->next;
    5588             exparg.lastp = &sp->next;
    5589         }
    5590         str = str->next;
    5591     }
    5592 }
    5593 
    5594 /*
    5595  * Add a file name to the list.
    5596  */
    5597 
    5598 static void
    5599 addfname(const char *name)
    5600 {
    5601     struct strlist *sp;
    5602 
    5603     sp = (struct strlist *)stalloc(sizeof *sp);
    5604     sp->text = sstrdup(name);
    5605     *exparg.lastp = sp;
    5606     exparg.lastp = &sp->next;
    5607 }
    5608 
    5609 
    5610 /*
    5611  * Do metacharacter (i.e. *, ?, [...]) expansion.
    5612  */
    5613 
    5614 static void
    5615 expmeta(char *enddir, char *name)
    5616 {
    5617     char *p;
    5618     const char *cp;
    5619     char *start;
    5620     char *endname;
    5621     int metaflag;
    5622     struct stat statb;
    5623     DIR *dirp;
    5624     struct dirent *dp;
    5625     int atend;
    5626     int matchdot;
    5627 
    5628     metaflag = 0;
    5629     start = name;
    5630     for (p = name; *p; p++) {
    5631         if (*p == '*' || *p == '?')
    5632             metaflag = 1;
    5633         else if (*p == '[') {
    5634             char *q = p + 1;
    5635             if (*q == '!')
    5636                 q++;
    5637             for (;;) {
    5638                 if (*q == '\\')
    5639                     q++;
    5640                 if (*q == '/' || *q == '\0')
    5641                     break;
    5642                 if (*++q == ']') {
    5643                     metaflag = 1;
    5644                     break;
    5645                 }
    5646             }
    5647         } else if (*p == '\\')
    5648             p++;
    5649         else if (*p == '/') {
    5650             if (metaflag)
    5651                 goto out;
    5652             start = p + 1;
    5653         }
    5654     }
    5655 out:
    5656     if (metaflag == 0) {    /* we've reached the end of the file name */
    5657         if (enddir != expdir)
    5658             metaflag++;
    5659         p = name;
    5660         do {
    5661             if (*p == '\\')
    5662                 p++;
    5663             *enddir++ = *p;
    5664         } while (*p++);
    5665         if (metaflag == 0 || lstat(expdir, &statb) >= 0)
    5666             addfname(expdir);
    5667         return;
    5668     }
    5669     endname = p;
    5670     if (name < start) {
    5671         p = name;
    5672         do {
    5673             if (*p == '\\')
    5674                 p++;
    5675             *enddir++ = *p++;
    5676         } while (p < start);
    5677     }
    5678     if (enddir == expdir) {
    5679         cp = ".";
    5680     } else if (enddir == expdir + 1 && *expdir == '/') {
    5681         cp = "/";
    5682     } else {
    5683         cp = expdir;
    5684         enddir[-1] = '\0';
    5685     }
    5686     if ((dirp = opendir(cp)) == NULL)
    5687         return;
    5688     if (enddir != expdir)
    5689         enddir[-1] = '/';
    5690     if (*endname == 0) {
    5691         atend = 1;
    5692     } else {
    5693         atend = 0;
    5694         *endname++ = '\0';
    5695     }
    5696     matchdot = 0;
    5697     p = start;
    5698     if (*p == '\\')
    5699         p++;
    5700     if (*p == '.')
    5701         matchdot++;
    5702     while (! intpending && (dp = readdir(dirp)) != NULL) {
    5703         if (dp->d_name[0] == '.' && ! matchdot)
    5704             continue;
    5705         if (pmatch(start, dp->d_name)) {
    5706             if (atend) {
    5707                 scopy(dp->d_name, enddir);
    5708                 addfname(expdir);
    5709             } else {
    5710                 for (p = enddir, cp = dp->d_name;
    5711                      (*p++ = *cp++) != '\0';)
    5712                     continue;
    5713                 p[-1] = '/';
    5714                 expmeta(p, endname);
    5715             }
    5716         }
    5717     }
    5718     closedir(dirp);
    5719     if (! atend)
    5720         endname[-1] = '/';
    5721 }
    5722 
    5723 /*
    5724  * Sort the results of file name expansion.  It calculates the number of
    5725  * strings to sort and then calls msort (short for merge sort) to do the
    5726  * work.
    5727  */
    5728 
    5729 static struct strlist *
    5730 expsort(struct strlist *str)
    5731 {
    5732     int len;
    5733     struct strlist *sp;
    5734 
    5735     len = 0;
    5736     for (sp = str ; sp ; sp = sp->next)
    5737         len++;
    5738     return msort(str, len);
    5739 }
    5740 
    5741 
    5742 static struct strlist *
    5743 msort(struct strlist *list, int len)
    5744 {
    5745     struct strlist *p, *q = NULL;
    5746     struct strlist **lpp;
    5747     int half;
    5748     int n;
    5749 
    5750     if (len <= 1)
    5751         return list;
    5752     half = len >> 1;
    5753     p = list;
    5754     for (n = half ; --n >= 0 ; ) {
    5755         q = p;
    5756         p = p->next;
    5757     }
    5758     q->next = NULL;                 /* terminate first half of list */
    5759     q = msort(list, half);          /* sort first half of list */
    5760     p = msort(p, len - half);               /* sort second half */
    5761     lpp = &list;
    5762     for (;;) {
    5763 #ifdef CONFIG_LOCALE_SUPPORT
    5764         if (strcoll(p->text, q->text) < 0)
    5765 #else
    5766         if (strcmp(p->text, q->text) < 0)
    5767 #endif
    5768                         {
    5769             *lpp = p;
    5770             lpp = &p->next;
    5771             if ((p = *lpp) == NULL) {
    5772                 *lpp = q;
    5773                 break;
    5774             }
    5775         } else {
    5776             *lpp = q;
    5777             lpp = &q->next;
    5778             if ((q = *lpp) == NULL) {
    5779                 *lpp = p;
    5780                 break;
    5781             }
    5782         }
    5783     }
    5784     return list;
    5785 }
    5786 
    5787 
    5788 /*
    5789  * Returns true if the pattern matches the string.
    5790  */
    5791 
    5792 static inline int
    5793 patmatch(char *pattern, const char *string)
    5794 {
    5795     return pmatch(preglob(pattern, 0, 0), string);
    5796 }
    5797 
    5798 
    5799 /*
    5800  * Remove any CTLESC characters from a string.
    5801  */
    5802 
    5803 static char *
    5804 _rmescapes(char *str, int flag)
    5805 {
    5806     char *p, *q, *r;
    5807     static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
    5808     unsigned inquotes;
    5809     int notescaped;
    5810     int globbing;
    5811 
    5812     p = strpbrk(str, qchars);
    5813     if (!p) {
    5814         return str;
    5815     }
    5816     q = p;
    5817     r = str;
    5818     if (flag & RMESCAPE_ALLOC) {
    5819         size_t len = p - str;
    5820         size_t fulllen = len + strlen(p) + 1;
    5821 
    5822         if (flag & RMESCAPE_GROW) {
    5823             r = makestrspace(fulllen, expdest);
    5824         } else if (flag & RMESCAPE_HEAP) {
    5825             r = ckmalloc(fulllen);
    5826         } else {
    5827             r = stalloc(fulllen);
    5828         }
    5829         q = r;
    5830         if (len > 0) {
    5831             q = mempcpy(q, str, len);
    5832         }
    5833     }
    5834     inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
    5835     globbing = flag & RMESCAPE_GLOB;
    5836     notescaped = globbing;
    5837     while (*p) {
    5838         if (*p == CTLQUOTEMARK) {
    5839             inquotes = ~inquotes;
    5840             p++;
    5841             notescaped = globbing;
    5842             continue;
    5843         }
    5844         if (*p == '\\') {
    5845             /* naked back slash */
    5846             notescaped = 0;
    5847             goto copy;
    5848         }
    5849         if (*p == CTLESC) {
    5850             p++;
    5851             if (notescaped && inquotes && *p != '/') {
    5852                 *q++ = '\\';
    5853             }
    5854         }
    5855         notescaped = globbing;
    5856 copy:
    5857         *q++ = *p++;
    5858     }
    5859     *q = '\0';
    5860     if (flag & RMESCAPE_GROW) {
    5861         expdest = r;
    5862         STADJUST(q - r + 1, expdest);
    5863     }
    5864     return r;
    5865 }
    5866 
    5867 
    5868 /*
    5869  * See if a pattern matches in a case statement.
    5870  */
    5871 
    5872 int
    5873 casematch(union node *pattern, char *val)
    5874 {
    5875     struct stackmark smark;
    5876     int result;
    5877 
    5878     setstackmark(&smark);
    5879     argbackq = pattern->narg.backquote;
    5880     STARTSTACKSTR(expdest);
    5881     ifslastp = NULL;
    5882     argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
    5883     STACKSTRNUL(expdest);
    5884     result = patmatch(stackblock(), val);
    5885     popstackmark(&smark);
    5886     return result;
    5887 }
    5888 
    5889 /*
    5890  * Our own itoa().
    5891  */
    5892 
    5893 static int
    5894 cvtnum(arith_t num)
    5895 {
    5896     int len;
    5897 
    5898     expdest = makestrspace(32, expdest);
    5899 #ifdef CONFIG_ASH_MATH_SUPPORT_64
    5900     len = fmtstr(expdest, 32, "%lld", (long long) num);
    5901 #else
    5902     len = fmtstr(expdest, 32, "%ld", num);
    5903 #endif
    5904     STADJUST(len, expdest);
    5905     return len;
    5906 }
    5907 
    5908 static void
    5909 varunset(const char *end, const char *var, const char *umsg, int varflags)
    5910 {
    5911     const char *msg;
    5912     const char *tail;
    5913 
    5914     tail = nullstr;
    5915     msg = "parameter not set";
    5916     if (umsg) {
    5917         if (*end == CTLENDVAR) {
    5918             if (varflags & VSNUL)
    5919                 tail = " or null";
    5920         } else
    5921             msg = umsg;
    5922     }
    5923     sh_error("%.*s: %s%s", end - var - 1, var, msg, tail);
    5924 }
    5925 
    5926 
    5927 /*      input.c      */
    5928 
    5929 /*
    5930  * This implements the input routines used by the parser.
    5931  */
    5932 
    5933 #define EOF_NLEFT -99           /* value of parsenleft when EOF pushed back */
    5934 
    5935 static void pushfile(void);
    5936 
    5937 /*
    5938  * Read a character from the script, returning PEOF on end of file.
    5939  * Nul characters in the input are silently discarded.
    5940  */
    5941 
    5942 
    5943 #define pgetc_as_macro()   (--parsenleft >= 0? SC2INT(*parsenextc++) : preadbuffer())
    5944 
    5945 #ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
    5946 #define pgetc_macro() pgetc()
    5947 static int
    5948 pgetc(void)
    5949 {
    5950     return pgetc_as_macro();
    5951 }
    5952 #else
    5953 #define pgetc_macro()   pgetc_as_macro()
    5954 static int
    5955 pgetc(void)
    5956 {
    5957     return pgetc_macro();
    5958 }
    5959 #endif
    5960 
    5961 
    5962 /*
    5963  * Same as pgetc(), but ignores PEOA.
    5964  */
    5965 #ifdef CONFIG_ASH_ALIAS
    5966 static int pgetc2(void)
    5967 {
    5968     int c;
    5969 
    5970     do {
    5971         c = pgetc_macro();
    5972     } while (c == PEOA);
    5973     return c;
    5974 }
    5975 #else
    5976 static inline int pgetc2(void)
    5977 {
    5978     return pgetc_macro();
    5979 }
    5980 #endif
    5981 
    5982 /*
    5983  * Read a line from the script.
    5984  */
    5985 
    5986 static inline char *
    5987 pfgets(char *line, int len)
    5988 {
    5989     char *p = line;
    5990     int nleft = len;
    5991     int c;
    5992 
    5993     while (--nleft > 0) {
    5994         c = pgetc2();
    5995         if (c == PEOF) {
    5996             if (p == line)
    5997                 return NULL;
    5998             break;
    5999         }
    6000         *p++ = c;
    6001         if (c == '\n')
    6002             break;
    6003     }
    6004     *p = '\0';
    6005     return line;
    6006 }
    6007 
    6008 
    6009 
    6010 #ifdef CONFIG_FEATURE_COMMAND_EDITING
    6011 #ifdef CONFIG_ASH_EXPAND_PRMT
    6012 static char *cmdedit_prompt;
    6013 #else
    6014 static const char *cmdedit_prompt;
    6015 #endif
    6016 static inline void putprompt(const char *s)
    6017 {
    6018 #ifdef CONFIG_ASH_EXPAND_PRMT
    6019     free(cmdedit_prompt);
    6020     cmdedit_prompt = bb_xstrdup(s);
    6021 #else
    6022     cmdedit_prompt = s;
    6023 #endif
    6024 }
    6025 #else
    6026 static inline void putprompt(const char *s)
    6027 {
    6028     out2str(s);
    6029 }
    6030 #endif
    6031 
    6032 static inline int
    6033 preadfd(void)
    6034 {
    6035     int nr;
    6036     char *buf =  parsefile->buf;
    6037     parsenextc = buf;
    6038 
    6039 retry:
    6040 #ifdef CONFIG_FEATURE_COMMAND_EDITING
    6041     if (!iflag || parsefile->fd)
    6042         nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
    6043     else {
    6044 #ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
    6045         cmdedit_path_lookup = pathval();
    6046 #endif
    6047         nr = cmdedit_read_input((char *) cmdedit_prompt, buf);
    6048         if(nr == 0) {
    6049             /* Ctrl+C presend */
    6050             if(trap[SIGINT]) {
    6051                 buf[0] = '\n';
    6052                 buf[1] = 0;
    6053                 raise(SIGINT);
    6054                 return 1;
    6055             }
    6056             goto retry;
    6057         }
    6058         if(nr < 0 && errno == 0) {
    6059             /* Ctrl+D presend */
    6060             nr = 0;
    6061         }
    6062     }
    6063 #else
    6064     nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
    6065 #endif
    6066 
    6067     if (nr < 0) {
    6068         if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
    6069             int flags = fcntl(0, F_GETFL, 0);
    6070             if (flags >= 0 && flags & O_NONBLOCK) {
    6071                 flags &=~ O_NONBLOCK;
    6072                 if (fcntl(0, F_SETFL, flags) >= 0) {
    6073                     out2str("sh: turning off NDELAY mode\n");
    6074                     goto retry;
    6075                 }
    6076             }
    6077         }
    6078     }
    6079     return nr;
    6080 }
    6081 
    6082 /*
    6083  * Refill the input buffer and return the next input character:
    6084  *
    6085  * 1) If a string was pushed back on the input, pop it;
    6086  * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
    6087  *    from a string so we can't refill the buffer, return EOF.
    6088  * 3) If the is more stuff in this buffer, use it else call read to fill it.
    6089  * 4) Process input up to the next newline, deleting nul characters.
    6090  */
    6091 
    6092 int
    6093 preadbuffer(void)
    6094 {
    6095     char *q;
    6096     int more;
    6097     char savec;
    6098 
    6099     while (parsefile->strpush) {
    6100 #ifdef CONFIG_ASH_ALIAS
    6101         if (parsenleft == -1 && parsefile->strpush->ap &&
    6102             parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
    6103             return PEOA;
    6104         }
    6105 #endif
    6106         popstring();
    6107         if (--parsenleft >= 0)
    6108             return SC2INT(*parsenextc++);
    6109     }
    6110     if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
    6111         return PEOF;
    6112     flushall();
    6113 
    6114     more = parselleft;
    6115     if (more <= 0) {
    6116 again:
    6117         if ((more = preadfd()) <= 0) {
    6118             parselleft = parsenleft = EOF_NLEFT;
    6119             return PEOF;
    6120         }
    6121     }
    6122 
    6123     q = parsenextc;
    6124 
    6125     /* delete nul characters */
    6126     for (;;) {
    6127         int c;
    6128 
    6129         more--;
    6130         c = *q;
    6131 
    6132         if (!c)
    6133             memmove(q, q + 1, more);
    6134         else {
    6135             q++;
    6136             if (c == '\n') {
    6137                 parsenleft = q - parsenextc - 1;
    6138                 break;
    6139             }
    6140         }
    6141 
    6142         if (more <= 0) {
    6143             parsenleft = q - parsenextc - 1;
    6144             if (parsenleft < 0)
    6145                 goto again;
    6146             break;
    6147         }
    6148     }
    6149     parselleft = more;
    6150 
    6151     savec = *q;
    6152     *q = '\0';
    6153 
    6154     if (vflag) {
    6155         out2str(parsenextc);
    6156     }
    6157 
    6158     *q = savec;
    6159 
    6160     return SC2INT(*parsenextc++);
    6161 }
    6162 
    6163 /*
    6164  * Undo the last call to pgetc.  Only one character may be pushed back.
    6165  * PEOF may be pushed back.
    6166  */
    6167 
    6168 void
    6169 pungetc(void)
    6170 {
    6171     parsenleft++;
    6172     parsenextc--;
    6173 }
    6174 
    6175 /*
    6176  * Push a string back onto the input at this current parsefile level.
    6177  * We handle aliases this way.
    6178  */
    6179 void
    6180 pushstring(char *s, void *ap)
    6181 {
    6182     struct strpush *sp;
    6183     size_t len;
    6184 
    6185     len = strlen(s);
    6186     INTOFF;
    6187 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
    6188     if (parsefile->strpush) {
    6189         sp = ckmalloc(sizeof (struct strpush));
    6190         sp->prev = parsefile->strpush;
    6191         parsefile->strpush = sp;
    6192     } else
    6193         sp = parsefile->strpush = &(parsefile->basestrpush);
    6194     sp->prevstring = parsenextc;
    6195     sp->prevnleft = parsenleft;
    6196 #ifdef CONFIG_ASH_ALIAS
    6197     sp->ap = (struct alias *)ap;
    6198     if (ap) {
    6199         ((struct alias *)ap)->flag |= ALIASINUSE;
    6200         sp->string = s;
    6201     }
    6202 #endif
    6203     parsenextc = s;
    6204     parsenleft = len;
    6205     INTON;
    6206 }
    6207 
    6208 void
    6209 popstring(void)
    6210 {
    6211     struct strpush *sp = parsefile->strpush;
    6212 
    6213     INTOFF;
    6214 #ifdef CONFIG_ASH_ALIAS
    6215     if (sp->ap) {
    6216         if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
    6217             checkkwd |= CHKALIAS;
    6218         }
    6219         if (sp->string != sp->ap->val) {
    6220             ckfree(sp->string);
    6221         }
    6222         sp->ap->flag &= ~ALIASINUSE;
    6223         if (sp->ap->flag & ALIASDEAD) {
    6224             unalias(sp->ap->name);
    6225         }
    6226     }
    6227 #endif
    6228     parsenextc = sp->prevstring;
    6229     parsenleft = sp->prevnleft;
    6230 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
    6231     parsefile->strpush = sp->prev;
    6232     if (sp != &(parsefile->basestrpush))
    6233         ckfree(sp);
    6234     INTON;
    6235 }
    6236 
    6237 /*
    6238  * Set the input to take input from a file.  If push is set, push the
    6239  * old input onto the stack first.
    6240  */
    6241 
    6242 static int
    6243 setinputfile(const char *fname, int flags)
    6244 {
    6245     int fd;
    6246     int fd2;
    6247 
    6248     INTOFF;
    6249     if ((fd = open(fname, O_RDONLY)) < 0) {
    6250         if (flags & INPUT_NOFILE_OK)
    6251             goto out;
    6252         sh_error("Can't open %s", fname);
    6253     }
    6254     if (fd < 10) {
    6255         fd2 = copyfd(fd, 10);
    6256         close(fd);
    6257         if (fd2 < 0)
    6258             sh_error("Out of file descriptors");
    6259         fd = fd2;
    6260     }
    6261     setinputfd(fd, flags & INPUT_PUSH_FILE);
    6262 out:
    6263     INTON;
    6264     return fd;
    6265 }
    6266 
    6267 
    6268 /*
    6269  * Like setinputfile, but takes an open file descriptor.  Call this with
    6270  * interrupts off.
    6271  */
    6272 
    6273 static void
    6274 setinputfd(int fd, int push)
    6275 {
    6276     (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
    6277     if (push) {
    6278         pushfile();
    6279         parsefile->buf = 0;
    6280     }
    6281     parsefile->fd = fd;
    6282     if (parsefile->buf == NULL)
    6283         parsefile->buf = ckmalloc(IBUFSIZ);
    6284     parselleft = parsenleft = 0;
    6285     plinno = 1;
    6286 }
    6287 
    6288 
    6289 /*
    6290  * Like setinputfile, but takes input from a string.
    6291  */
    6292 
    6293 static void
    6294 setinputstring(char *string)
    6295 {
    6296     INTOFF;
    6297     pushfile();
    6298     parsenextc = string;
    6299     parsenleft = strlen(string);
    6300     parsefile->buf = NULL;
    6301     plinno = 1;
    6302     INTON;
    6303 }
    6304 
    6305 
    6306 /*
    6307  * To handle the "." command, a stack of input files is used.  Pushfile
    6308  * adds a new entry to the stack and popfile restores the previous level.
    6309  */
    6310 
    6311 static void
    6312 pushfile(void)
    6313 {
    6314     struct parsefile *pf;
    6315 
    6316     parsefile->nleft = parsenleft;
    6317     parsefile->lleft = parselleft;
    6318     parsefile->nextc = parsenextc;
    6319     parsefile->linno = plinno;
    6320     pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
    6321     pf->prev = parsefile;
    6322     pf->fd = -1;
    6323     pf->strpush = NULL;
    6324     pf->basestrpush.prev = NULL;
    6325     parsefile = pf;
    6326 }
    6327 
    6328 
    6329 static void
    6330 popfile(void)
    6331 {
    6332     struct parsefile *pf = parsefile;
    6333 
    6334     INTOFF;
    6335     if (pf->fd >= 0)
    6336         close(pf->fd);
    6337     if (pf->buf)
    6338         ckfree(pf->buf);
    6339     while (pf->strpush)
    6340         popstring();
    6341     parsefile = pf->prev;
    6342     ckfree(pf);
    6343     parsenleft = parsefile->nleft;
    6344     parselleft = parsefile->lleft;
    6345     parsenextc = parsefile->nextc;
    6346     plinno = parsefile->linno;
    6347     INTON;
    6348 }
    6349 
    6350 
    6351 /*
    6352  * Return to top level.
    6353  */
    6354 
    6355 static void
    6356 popallfiles(void)
    6357 {
    6358     while (parsefile != &basepf)
    6359         popfile();
    6360 }
    6361 
    6362 
    6363 /*
    6364  * Close the file(s) that the shell is reading commands from.  Called
    6365  * after a fork is done.
    6366  */
    6367 
    6368 static void
    6369 closescript(void)
    6370 {
    6371     popallfiles();
    6372     if (parsefile->fd > 0) {
    6373         close(parsefile->fd);
    6374         parsefile->fd = 0;
    6375     }
    6376 }
    6377 
    6378 /*      jobs.c    */
     3239        act.sa_handler = SIG_DFL;
     3240    }
     3241    *t = action;
     3242    act.sa_flags = 0;
     3243    sigfillset(&act.sa_mask);
     3244    sigaction(signo, &act, 0);
     3245}
    63793246
    63803247/* mode flags for set_curjob */
     
    63873254#define DOWAIT_BLOCK 1
    63883255
     3256#if JOBS
     3257/* pgrp of shell on invocation */
     3258static int initialpgrp;
     3259static int ttyfd = -1;
     3260#endif
    63893261/* array of jobs */
    63903262static struct job *jobtab;
    63913263/* size of array */
    63923264static unsigned njobs;
    6393 #if JOBS
    6394 /* pgrp of shell on invocation */
    6395 static int initialpgrp;
    6396 static int ttyfd = -1;
    6397 #endif
    63983265/* current job */
    63993266static struct job *curjob;
    64003267/* number of presumed living untracked jobs */
    64013268static int jobless;
    6402 
    6403 static void set_curjob(struct job *, unsigned);
    6404 #if JOBS
    6405 static int restartjob(struct job *, int);
    6406 static void xtcsetpgrp(int, pid_t);
    6407 static char *commandtext(union node *);
    6408 static void cmdlist(union node *, int);
    6409 static void cmdtxt(union node *);
    6410 static void cmdputs(const char *);
    6411 static void showpipe(struct job *, FILE *);
    6412 #endif
    6413 static int sprint_status(char *, int, int);
    6414 static void freejob(struct job *);
    6415 static struct job *getjob(const char *, int);
    6416 static struct job *growjobtab(void);
    6417 static void forkchild(struct job *, union node *, int);
    6418 static void forkparent(struct job *, union node *, int, pid_t);
    6419 static int dowait(int, struct job *);
    6420 static int getstatus(struct job *);
    64213269
    64223270static void
     
    64403288    switch (mode) {
    64413289    default:
    6442 #ifdef DEBUG
     3290#if DEBUG
    64433291        abort();
    64443292#endif
     
    64683316}
    64693317
     3318#if JOBS || DEBUG
     3319static int
     3320jobno(const struct job *jp)
     3321{
     3322    return jp - jobtab + 1;
     3323}
     3324#endif
     3325
     3326/*
     3327 * Convert a job name to a job structure.
     3328 */
     3329static struct job *
     3330getjob(const char *name, int getctl)
     3331{
     3332    struct job *jp;
     3333    struct job *found;
     3334    const char *err_msg = "No such job: %s";
     3335    unsigned num;
     3336    int c;
     3337    const char *p;
     3338    char *(*match)(const char *, const char *);
     3339
     3340    jp = curjob;
     3341    p = name;
     3342    if (!p)
     3343        goto currentjob;
     3344
     3345    if (*p != '%')
     3346        goto err;
     3347
     3348    c = *++p;
     3349    if (!c)
     3350        goto currentjob;
     3351
     3352    if (!p[1]) {
     3353        if (c == '+' || c == '%') {
     3354 currentjob:
     3355            err_msg = "No current job";
     3356            goto check;
     3357        }
     3358        if (c == '-') {
     3359            if (jp)
     3360                jp = jp->prev_job;
     3361            err_msg = "No previous job";
     3362 check:
     3363            if (!jp)
     3364                goto err;
     3365            goto gotit;
     3366        }
     3367    }
     3368
     3369    if (is_number(p)) {
     3370        num = atoi(p);
     3371        if (num < njobs) {
     3372            jp = jobtab + num - 1;
     3373            if (jp->used)
     3374                goto gotit;
     3375            goto err;
     3376        }
     3377    }
     3378
     3379    match = prefix;
     3380    if (*p == '?') {
     3381        match = strstr;
     3382        p++;
     3383    }
     3384
     3385    found = 0;
     3386    while (1) {
     3387        if (!jp)
     3388            goto err;
     3389        if (match(jp->ps[0].cmd, p)) {
     3390            if (found)
     3391                goto err;
     3392            found = jp;
     3393            err_msg = "%s: ambiguous";
     3394        }
     3395        jp = jp->prev_job;
     3396    }
     3397
     3398 gotit:
    64703399#if JOBS
     3400    err_msg = "job %s not created under job control";
     3401    if (getctl && jp->jobctl == 0)
     3402        goto err;
     3403#endif
     3404    return jp;
     3405 err:
     3406    ash_msg_and_raise_error(err_msg, name);
     3407}
     3408
     3409/*
     3410 * Mark a job structure as unused.
     3411 */
     3412static void
     3413freejob(struct job *jp)
     3414{
     3415    struct procstat *ps;
     3416    int i;
     3417
     3418    INT_OFF;
     3419    for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
     3420        if (ps->cmd != nullstr)
     3421            free(ps->cmd);
     3422    }
     3423    if (jp->ps != &jp->ps0)
     3424        free(jp->ps);
     3425    jp->used = 0;
     3426    set_curjob(jp, CUR_DELETE);
     3427    INT_ON;
     3428}
     3429
     3430#if JOBS
     3431static void
     3432xtcsetpgrp(int fd, pid_t pgrp)
     3433{
     3434    if (tcsetpgrp(fd, pgrp))
     3435        ash_msg_and_raise_error("cannot set tty process group (%m)");
     3436}
     3437
    64713438/*
    64723439 * Turn job control on and off.
     
    64783445 * Called with interrupts off.
    64793446 */
    6480 
    6481 void
     3447static void
    64823448setjobctl(int on)
    64833449{
     
    64913457        ofd = fd = open(_PATH_TTY, O_RDWR);
    64923458        if (fd < 0) {
     3459    /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
     3460     * That sometimes helps to acquire controlling tty.
     3461     * Obviously, a workaround for bugs when someone
     3462     * failed to provide a controlling tty to bash! :) */
    64933463            fd += 3;
    64943464            while (!isatty(fd) && --fd >= 0)
     
    65013471        fcntl(fd, F_SETFD, FD_CLOEXEC);
    65023472        do { /* while we are in the background */
    6503             if ((pgrp = tcgetpgrp(fd)) < 0) {
    6504 out:
    6505                 sh_warnx("can't access tty; job control turned off");
     3473            pgrp = tcgetpgrp(fd);
     3474            if (pgrp < 0) {
     3475 out:
     3476                ash_msg("can't access tty; job control turned off");
    65063477                mflag = on = 0;
    65073478                goto close;
     
    65233494        fd = ttyfd;
    65243495        pgrp = initialpgrp;
    6525         xtcsetpgrp(fd, pgrp);
     3496        /* was xtcsetpgrp, but this can make exiting ash
     3497         * with pty already deleted loop forever */
     3498        tcsetpgrp(fd, pgrp);
    65263499        setpgid(0, pgrp);
    65273500        setsignal(SIGTSTP);
    65283501        setsignal(SIGTTOU);
    65293502        setsignal(SIGTTIN);
    6530 close:
     3503 close:
    65313504        close(fd);
    65323505        fd = -1;
     
    65393512killcmd(int argc, char **argv)
    65403513{
    6541     int signo = -1;
    6542     int list = 0;
    6543     int i;
    6544     pid_t pid;
    6545     struct job *jp;
    6546 
    6547     if (argc <= 1) {
    6548 usage:
    6549         sh_error(
    6550 "Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
    6551 "kill -l [exitstatus]"
    6552         );
    6553     }
    6554 
    6555     if (**++argv == '-') {
    6556         signo = decode_signal(*argv + 1, 1);
    6557         if (signo < 0) {
    6558             int c;
    6559 
    6560             while ((c = nextopt("ls:")) != '\0')
    6561                 switch (c) {
    6562                 default:
    6563 #ifdef DEBUG
    6564                     abort();
    6565 #endif
    6566                 case 'l':
    6567                     list = 1;
    6568                     break;
    6569                 case 's':
    6570                     signo = decode_signal(optionarg, 1);
    6571                     if (signo < 0) {
    6572                         sh_error(
    6573                             "invalid signal number or name: %s",
    6574                             optionarg
    6575                         );
    6576                     }
    6577                     break;
    6578                 }
    6579             argv = argptr;
    6580         } else
    6581             argv++;
    6582     }
    6583 
    6584     if (!list && signo < 0)
    6585         signo = SIGTERM;
    6586 
    6587     if ((signo < 0 || !*argv) ^ list) {
    6588         goto usage;
    6589     }
    6590 
    6591     if (list) {
    6592         const char *name;
    6593 
    6594         if (!*argv) {
    6595             for (i = 1; i < NSIG; i++) {
    6596                 name = u_signal_names(0, &i, 1);
    6597                 if (name)
    6598                     out1fmt(snlfmt, name);
     3514    if (argv[1] && strcmp(argv[1], "-l") != 0) {
     3515        int i = 1;
     3516        do {
     3517            if (argv[i][0] == '%') {
     3518                struct job *jp = getjob(argv[i], 0);
     3519                unsigned pid = jp->ps[0].pid;
     3520                /* Enough space for ' -NNN<nul>' */
     3521                argv[i] = alloca(sizeof(int)*3 + 3);
     3522                /* kill_main has matching code to expect
     3523                 * leading space. Needed to not confuse
     3524                 * negative pids with "kill -SIGNAL_NO" syntax */
     3525                sprintf(argv[i], " -%u", pid);
    65993526            }
    6600             return 0;
    6601         }
    6602         name = u_signal_names(*argptr, &signo, -1);
    6603         if (name)
    6604             out1fmt(snlfmt, name);
    6605         else
    6606             sh_error("invalid signal number or exit status: %s", *argptr);
    6607         return 0;
    6608     }
    6609 
    6610     i = 0;
    6611     do {
    6612         if (**argv == '%') {
    6613             jp = getjob(*argv, 0);
    6614             pid = -jp->ps[0].pid;
    6615         } else {
    6616             pid = **argv == '-' ?
    6617                 -number(*argv + 1) : number(*argv);
    6618         }
    6619         if (kill(pid, signo) != 0) {
    6620             sh_warnx("(%d) - %m", pid);
    6621             i = 1;
    6622         }
    6623     } while (*++argv);
    6624 
    6625     return i;
    6626 }
    6627 #endif /* JOBS */
    6628 
    6629 #if defined(JOBS) || defined(DEBUG)
    6630 static int
    6631 jobno(const struct job *jp)
    6632 {
    6633     return jp - jobtab + 1;
    6634 }
    6635 #endif
    6636 
    6637 #if JOBS
    6638 static int
    6639 fgcmd(int argc, char **argv)
    6640 {
    6641     struct job *jp;
    6642     FILE *out;
    6643     int mode;
    6644     int retval;
    6645 
    6646     mode = (**argv == 'f') ? FORK_FG : FORK_BG;
    6647     nextopt(nullstr);
    6648     argv = argptr;
    6649     out = stdout;
    6650     do {
    6651         jp = getjob(*argv, 1);
    6652         if (mode == FORK_BG) {
    6653             set_curjob(jp, CUR_RUNNING);
    6654             fprintf(out, "[%d] ", jobno(jp));
    6655         }
    6656         outstr(jp->ps->cmd, out);
    6657         showpipe(jp, out);
    6658         retval = restartjob(jp, mode);
    6659     } while (*argv && *++argv);
    6660     return retval;
    6661 }
    6662 
    6663 static int bgcmd(int, char **) __attribute__((__alias__("fgcmd")));
     3527        } while (argv[++i]);
     3528    }
     3529    return kill_main(argc, argv);
     3530}
     3531
     3532static void
     3533showpipe(struct job *jp, FILE *out)
     3534{
     3535    struct procstat *sp;
     3536    struct procstat *spend;
     3537
     3538    spend = jp->ps + jp->nprocs;
     3539    for (sp = jp->ps + 1; sp < spend; sp++)
     3540        fprintf(out, " | %s", sp->cmd);
     3541    outcslow('\n', out);
     3542    flush_stdout_stderr();
     3543}
    66643544
    66653545
     
    66723552    pid_t pgid;
    66733553
    6674     INTOFF;
     3554    INT_OFF;
    66753555    if (jp->state == JOBDONE)
    66763556        goto out;
     
    66863566            ps->status = -1;
    66873567        }
    6688     } while (ps++, --i);
    6689 out:
     3568        ps++;
     3569    } while (--i);
     3570 out:
    66903571    status = (mode == FORK_FG) ? waitforjob(jp) : 0;
    6691     INTON;
     3572    INT_ON;
    66923573    return status;
     3574}
     3575
     3576static int
     3577fg_bgcmd(int argc, char **argv)
     3578{
     3579    struct job *jp;
     3580    FILE *out;
     3581    int mode;
     3582    int retval;
     3583
     3584    mode = (**argv == 'f') ? FORK_FG : FORK_BG;
     3585    nextopt(nullstr);
     3586    argv = argptr;
     3587    out = stdout;
     3588    do {
     3589        jp = getjob(*argv, 1);
     3590        if (mode == FORK_BG) {
     3591            set_curjob(jp, CUR_RUNNING);
     3592            fprintf(out, "[%d] ", jobno(jp));
     3593        }
     3594        outstr(jp->ps->cmd, out);
     3595        showpipe(jp, out);
     3596        retval = restartjob(jp, mode);
     3597    } while (*argv && *++argv);
     3598    return retval;
    66933599}
    66943600#endif
     
    67283634            col = fmtstr(s, 16, "Done");
    67293635    }
    6730 
    6731 out:
     3636 out:
    67323637    return col;
    67333638}
    6734 
    6735 #if JOBS
    6736 static void
    6737 showjob(FILE *out, struct job *jp, int mode)
    6738 {
    6739     struct procstat *ps;
    6740     struct procstat *psend;
    6741     int col;
    6742     int indent;
    6743     char s[80];
    6744 
    6745     ps = jp->ps;
    6746 
    6747     if (mode & SHOW_PGID) {
    6748         /* just output process (group) id of pipeline */
    6749         fprintf(out, "%d\n", ps->pid);
    6750         return;
    6751     }
    6752 
    6753     col = fmtstr(s, 16, "[%d]   ", jobno(jp));
    6754     indent = col;
    6755 
    6756     if (jp == curjob)
    6757         s[col - 2] = '+';
    6758     else if (curjob && jp == curjob->prev_job)
    6759         s[col - 2] = '-';
    6760 
    6761     if (mode & SHOW_PID)
    6762         col += fmtstr(s + col, 16, "%d ", ps->pid);
    6763 
    6764     psend = ps + jp->nprocs;
    6765 
    6766     if (jp->state == JOBRUNNING) {
    6767         scopy("Running", s + col);
    6768         col += strlen("Running");
    6769     } else {
    6770         int status = psend[-1].status;
    6771 #if JOBS
    6772         if (jp->state == JOBSTOPPED)
    6773             status = jp->stopstatus;
    6774 #endif
    6775         col += sprint_status(s + col, status, 0);
    6776     }
    6777 
    6778     goto start;
    6779 
    6780     do {
    6781         /* for each process */
    6782         col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;
    6783 
    6784 start:
    6785         fprintf(out, "%s%*c%s",
    6786             s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
    6787         );
    6788         if (!(mode & SHOW_PID)) {
    6789             showpipe(jp, out);
    6790             break;
    6791         }
    6792         if (++ps == psend) {
    6793             outcslow('\n', out);
    6794             break;
    6795         }
    6796     } while (1);
    6797 
    6798     jp->changed = 0;
    6799 
    6800     if (jp->state == JOBDONE) {
    6801         TRACE(("showjob: freeing job %d\n", jobno(jp)));
    6802         freejob(jp);
    6803     }
    6804 }
    6805 
    6806 
    6807 static int
    6808 jobscmd(int argc, char **argv)
    6809 {
    6810     int mode, m;
    6811     FILE *out;
    6812 
    6813     mode = 0;
    6814     while ((m = nextopt("lp")))
    6815         if (m == 'l')
    6816             mode = SHOW_PID;
    6817         else
    6818             mode = SHOW_PGID;
    6819 
    6820     out = stdout;
    6821     argv = argptr;
    6822     if (*argv)
    6823         do
    6824             showjob(out, getjob(*argv,0), mode);
    6825         while (*++argv);
    6826     else
    6827         showjobs(out, mode);
    6828 
    6829     return 0;
    6830 }
    6831 
    6832 
    6833 /*
    6834  * Print a list of jobs.  If "change" is nonzero, only print jobs whose
    6835  * statuses have changed since the last call to showjobs.
    6836  */
    6837 
    6838 static void
    6839 showjobs(FILE *out, int mode)
    6840 {
    6841     struct job *jp;
    6842 
    6843     TRACE(("showjobs(%x) called\n", mode));
    6844 
    6845     /* If not even one one job changed, there is nothing to do */
    6846     while (dowait(DOWAIT_NORMAL, NULL) > 0)
    6847         continue;
    6848 
    6849     for (jp = curjob; jp; jp = jp->prev_job) {
    6850         if (!(mode & SHOW_CHANGED) || jp->changed)
    6851             showjob(out, jp, mode);
    6852     }
    6853 }
    6854 #endif /* JOBS */
    6855 
    6856 /*
    6857  * Mark a job structure as unused.
    6858  */
    6859 
    6860 static void
    6861 freejob(struct job *jp)
    6862 {
    6863     struct procstat *ps;
    6864     int i;
    6865 
    6866     INTOFF;
    6867     for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
    6868         if (ps->cmd != nullstr)
    6869             ckfree(ps->cmd);
    6870     }
    6871     if (jp->ps != &jp->ps0)
    6872         ckfree(jp->ps);
    6873     jp->used = 0;
    6874     set_curjob(jp, CUR_DELETE);
    6875     INTON;
    6876 }
    6877 
    6878 
    6879 static int
    6880 waitcmd(int argc, char **argv)
    6881 {
    6882     struct job *job;
    6883     int retval;
    6884     struct job *jp;
    6885 
    6886     EXSIGON();
    6887 
    6888     nextopt(nullstr);
    6889     retval = 0;
    6890 
    6891     argv = argptr;
    6892     if (!*argv) {
    6893         /* wait for all jobs */
    6894         for (;;) {
    6895             jp = curjob;
    6896             while (1) {
    6897                 if (!jp) {
    6898                     /* no running procs */
    6899                     goto out;
    6900                 }
    6901                 if (jp->state == JOBRUNNING)
    6902                     break;
    6903                 jp->waited = 1;
    6904                 jp = jp->prev_job;
    6905             }
    6906             dowait(DOWAIT_BLOCK, 0);
    6907         }
    6908     }
    6909 
    6910     retval = 127;
    6911     do {
    6912         if (**argv != '%') {
    6913             pid_t pid = number(*argv);
    6914             job = curjob;
    6915             goto start;
    6916             do {
    6917                 if (job->ps[job->nprocs - 1].pid == pid)
    6918                     break;
    6919                 job = job->prev_job;
    6920 start:
    6921                 if (!job)
    6922                     goto repeat;
    6923             } while (1);
    6924         } else
    6925             job = getjob(*argv, 0);
    6926         /* loop until process terminated or stopped */
    6927         while (job->state == JOBRUNNING)
    6928             dowait(DOWAIT_BLOCK, 0);
    6929         job->waited = 1;
    6930         retval = getstatus(job);
    6931 repeat:
    6932         ;
    6933     } while (*++argv);
    6934 
    6935 out:
    6936     return retval;
    6937 }
    6938 
    6939 
    6940 /*
    6941  * Convert a job name to a job structure.
    6942  */
    6943 
    6944 static struct job *
    6945 getjob(const char *name, int getctl)
    6946 {
    6947     struct job *jp;
    6948     struct job *found;
    6949     const char *err_msg = "No such job: %s";
    6950     unsigned num;
    6951     int c;
    6952     const char *p;
    6953     char *(*match)(const char *, const char *);
    6954 
    6955     jp = curjob;
    6956     p = name;
    6957     if (!p)
    6958         goto currentjob;
    6959 
    6960     if (*p != '%')
    6961         goto err;
    6962 
    6963     c = *++p;
    6964     if (!c)
    6965         goto currentjob;
    6966 
    6967     if (!p[1]) {
    6968         if (c == '+' || c == '%') {
    6969 currentjob:
    6970             err_msg = "No current job";
    6971             goto check;
    6972         } else if (c == '-') {
    6973             if (jp)
    6974                 jp = jp->prev_job;
    6975             err_msg = "No previous job";
    6976 check:
    6977             if (!jp)
    6978                 goto err;
    6979             goto gotit;
    6980         }
    6981     }
    6982 
    6983     if (is_number(p)) {
    6984         num = atoi(p);
    6985         if (num < njobs) {
    6986             jp = jobtab + num - 1;
    6987             if (jp->used)
    6988                 goto gotit;
    6989             goto err;
    6990         }
    6991     }
    6992 
    6993     match = prefix;
    6994     if (*p == '?') {
    6995         match = strstr;
    6996         p++;
    6997     }
    6998 
    6999     found = 0;
    7000     while (1) {
    7001         if (!jp)
    7002             goto err;
    7003         if (match(jp->ps[0].cmd, p)) {
    7004             if (found)
    7005                 goto err;
    7006             found = jp;
    7007             err_msg = "%s: ambiguous";
    7008         }
    7009         jp = jp->prev_job;
    7010     }
    7011 
    7012 gotit:
    7013 #if JOBS
    7014     err_msg = "job %s not created under job control";
    7015     if (getctl && jp->jobctl == 0)
    7016         goto err;
    7017 #endif
    7018     return jp;
    7019 err:
    7020     sh_error(err_msg, name);
    7021 }
    7022 
    7023 
    7024 /*
    7025  * Return a new job structure.
    7026  * Called with interrupts off.
    7027  */
    7028 
    7029 static struct job *
    7030 makejob(union node *node, int nprocs)
    7031 {
    7032     int i;
    7033     struct job *jp;
    7034 
    7035     for (i = njobs, jp = jobtab ; ; jp++) {
    7036         if (--i < 0) {
    7037             jp = growjobtab();
    7038             break;
    7039         }
    7040         if (jp->used == 0)
    7041             break;
    7042         if (jp->state != JOBDONE || !jp->waited)
    7043             continue;
    7044 #if JOBS
    7045         if (jobctl)
    7046             continue;
    7047 #endif
    7048         freejob(jp);
    7049         break;
    7050     }
    7051     memset(jp, 0, sizeof(*jp));
    7052 #if JOBS
    7053     if (jobctl)
    7054         jp->jobctl = 1;
    7055 #endif
    7056     jp->prev_job = curjob;
    7057     curjob = jp;
    7058     jp->used = 1;
    7059     jp->ps = &jp->ps0;
    7060     if (nprocs > 1) {
    7061         jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
    7062     }
    7063     TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
    7064         jobno(jp)));
    7065     return jp;
    7066 }
    7067 
    7068 static struct job *
    7069 growjobtab(void)
    7070 {
    7071     size_t len;
    7072     ptrdiff_t offset;
    7073     struct job *jp, *jq;
    7074 
    7075     len = njobs * sizeof(*jp);
    7076     jq = jobtab;
    7077     jp = ckrealloc(jq, len + 4 * sizeof(*jp));
    7078 
    7079     offset = (char *)jp - (char *)jq;
    7080     if (offset) {
    7081         /* Relocate pointers */
    7082         size_t l = len;
    7083 
    7084         jq = (struct job *)((char *)jq + l);
    7085         while (l) {
    7086             l -= sizeof(*jp);
    7087             jq--;
    7088 #define joff(p) ((struct job *)((char *)(p) + l))
    7089 #define jmove(p) (p) = (void *)((char *)(p) + offset)
    7090             if (xlikely(joff(jp)->ps == &jq->ps0))
    7091                 jmove(joff(jp)->ps);
    7092             if (joff(jp)->prev_job)
    7093                 jmove(joff(jp)->prev_job);
    7094         }
    7095         if (curjob)
    7096             jmove(curjob);
    7097 #undef joff
    7098 #undef jmove
    7099     }
    7100 
    7101     njobs += 4;
    7102     jobtab = jp;
    7103     jp = (struct job *)((char *)jp + len);
    7104     jq = jp + 3;
    7105     do {
    7106         jq->used = 0;
    7107     } while (--jq >= jp);
    7108     return jp;
    7109 }
    7110 
    7111 
    7112 /*
    7113  * Fork off a subshell.  If we are doing job control, give the subshell its
    7114  * own process group.  Jp is a job structure that the job is to be added to.
    7115  * N is the command that will be evaluated by the child.  Both jp and n may
    7116  * be NULL.  The mode parameter can be one of the following:
    7117  *      FORK_FG - Fork off a foreground process.
    7118  *      FORK_BG - Fork off a background process.
    7119  *      FORK_NOJOB - Like FORK_FG, but don't give the process its own
    7120  *                   process group even if job control is on.
    7121  *
    7122  * When job control is turned off, background processes have their standard
    7123  * input redirected to /dev/null (except for the second and later processes
    7124  * in a pipeline).
    7125  *
    7126  * Called with interrupts off.
    7127  */
    7128 
    7129 static inline void
    7130 forkchild(struct job *jp, union node *n, int mode)
    7131 {
    7132     int oldlvl;
    7133 
    7134     TRACE(("Child shell %d\n", getpid()));
    7135     oldlvl = shlvl;
    7136     shlvl++;
    7137 
    7138     closescript();
    7139     clear_traps();
    7140 #if JOBS
    7141     /* do job control only in root shell */
    7142     jobctl = 0;
    7143     if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) {
    7144         pid_t pgrp;
    7145 
    7146         if (jp->nprocs == 0)
    7147             pgrp = getpid();
    7148         else
    7149             pgrp = jp->ps[0].pid;
    7150         /* This can fail because we are doing it in the parent also */
    7151         (void)setpgid(0, pgrp);
    7152         if (mode == FORK_FG)
    7153             xtcsetpgrp(ttyfd, pgrp);
    7154         setsignal(SIGTSTP);
    7155         setsignal(SIGTTOU);
    7156     } else
    7157 #endif
    7158     if (mode == FORK_BG) {
    7159         ignoresig(SIGINT);
    7160         ignoresig(SIGQUIT);
    7161         if (jp->nprocs == 0) {
    7162             close(0);
    7163             if (open(bb_dev_null, O_RDONLY) != 0)
    7164                 sh_error("Can't open %s", bb_dev_null);
    7165         }
    7166     }
    7167     if (!oldlvl && iflag) {
    7168         setsignal(SIGINT);
    7169         setsignal(SIGQUIT);
    7170         setsignal(SIGTERM);
    7171     }
    7172     for (jp = curjob; jp; jp = jp->prev_job)
    7173         freejob(jp);
    7174     jobless = 0;
    7175 }
    7176 
    7177 static inline void
    7178 forkparent(struct job *jp, union node *n, int mode, pid_t pid)
    7179 {
    7180     TRACE(("In parent shell:  child = %d\n", pid));
    7181     if (!jp) {
    7182         while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
    7183         jobless++;
    7184         return;
    7185     }
    7186 #if JOBS
    7187     if (mode != FORK_NOJOB && jp->jobctl) {
    7188         int pgrp;
    7189 
    7190         if (jp->nprocs == 0)
    7191             pgrp = pid;
    7192         else
    7193             pgrp = jp->ps[0].pid;
    7194         /* This can fail because we are doing it in the child also */
    7195         (void)setpgid(pid, pgrp);
    7196     }
    7197 #endif
    7198     if (mode == FORK_BG) {
    7199         backgndpid = pid;               /* set $! */
    7200         set_curjob(jp, CUR_RUNNING);
    7201     }
    7202     if (jp) {
    7203         struct procstat *ps = &jp->ps[jp->nprocs++];
    7204         ps->pid = pid;
    7205         ps->status = -1;
    7206         ps->cmd = nullstr;
    7207 #if JOBS
    7208         if (jobctl && n)
    7209             ps->cmd = commandtext(n);
    7210 #endif
    7211     }
    7212 }
    7213 
    7214 static int
    7215 forkshell(struct job *jp, union node *n, int mode)
    7216 {
    7217     int pid;
    7218 
    7219     TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
    7220     pid = fork();
    7221     if (pid < 0) {
    7222         TRACE(("Fork failed, errno=%d", errno));
    7223         if (jp)
    7224             freejob(jp);
    7225         sh_error("Cannot fork");
    7226     }
    7227     if (pid == 0)
    7228         forkchild(jp, n, mode);
    7229     else
    7230         forkparent(jp, n, mode, pid);
    7231     return pid;
    7232 }
    7233 
    7234 /*
    7235  * Wait for job to finish.
    7236  *
    7237  * Under job control we have the problem that while a child process is
    7238  * running interrupts generated by the user are sent to the child but not
    7239  * to the shell.  This means that an infinite loop started by an inter-
    7240  * active user may be hard to kill.  With job control turned off, an
    7241  * interactive user may place an interactive program inside a loop.  If
    7242  * the interactive program catches interrupts, the user doesn't want
    7243  * these interrupts to also abort the loop.  The approach we take here
    7244  * is to have the shell ignore interrupt signals while waiting for a
    7245  * foreground process to terminate, and then send itself an interrupt
    7246  * signal if the child process was terminated by an interrupt signal.
    7247  * Unfortunately, some programs want to do a bit of cleanup and then
    7248  * exit on interrupt; unless these processes terminate themselves by
    7249  * sending a signal to themselves (instead of calling exit) they will
    7250  * confuse this approach.
    7251  *
    7252  * Called with interrupts off.
    7253  */
    7254 
    7255 int
    7256 waitforjob(struct job *jp)
    7257 {
    7258     int st;
    7259 
    7260     TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
    7261     while (jp->state == JOBRUNNING) {
    7262         dowait(DOWAIT_BLOCK, jp);
    7263     }
    7264     st = getstatus(jp);
    7265 #if JOBS
    7266     if (jp->jobctl) {
    7267         xtcsetpgrp(ttyfd, rootpid);
    7268         /*
    7269          * This is truly gross.
    7270          * If we're doing job control, then we did a TIOCSPGRP which
    7271          * caused us (the shell) to no longer be in the controlling
    7272          * session -- so we wouldn't have seen any ^C/SIGINT.  So, we
    7273          * intuit from the subprocess exit status whether a SIGINT
    7274          * occurred, and if so interrupt ourselves.  Yuck.  - mycroft
    7275          */
    7276         if (jp->sigint)
    7277             raise(SIGINT);
    7278     }
    7279     if (jp->state == JOBDONE)
    7280 #endif
    7281         freejob(jp);
    7282     return st;
    7283 }
    7284 
    72853639
    72863640/*
     
    73123666 * and the jobs command may give out of date information.
    73133667 */
    7314 
    7315 static inline int
     3668static int
    73163669waitproc(int block, int *status)
    73173670{
     
    73303683 * Wait for a process to terminate.
    73313684 */
    7332 
    73333685static int
    73343686dowait(int block, struct job *job)
     
    73453697    if (pid <= 0)
    73463698        return pid;
    7347     INTOFF;
     3699    INT_OFF;
    73483700    thisjob = NULL;
    73493701    for (jp = curjob; jp; jp = jp->prev_job) {
     
    73573709        do {
    73583710            if (sp->pid == pid) {
    7359                 TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->status, status));
     3711                TRACE(("Job %d: changing status of proc %d "
     3712                    "from 0x%x to 0x%x\n",
     3713                    jobno(jp), pid, sp->status, status));
    73603714                sp->status = status;
    73613715                thisjob = jp;
     
    73823736    goto out;
    73833737
    7384 gotjob:
     3738 gotjob:
    73853739    if (state != JOBRUNNING) {
    73863740        thisjob->changed = 1;
    73873741
    73883742        if (thisjob->state != state) {
    7389             TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state));
     3743            TRACE(("Job %d: changing state from %d to %d\n",
     3744                jobno(thisjob), thisjob->state, state));
    73903745            thisjob->state = state;
    73913746#if JOBS
     
    73973752    }
    73983753
    7399 out:
    7400     INTON;
     3754 out:
     3755    INT_ON;
    74013756
    74023757    if (thisjob && thisjob == job) {
     
    74143769}
    74153770
    7416 
    7417 /*
    7418  * return 1 if there are stopped jobs, otherwise 0
    7419  */
    7420 
    7421 int
    7422 stoppedjobs(void)
     3771#if JOBS
     3772static void
     3773showjob(FILE *out, struct job *jp, int mode)
     3774{
     3775    struct procstat *ps;
     3776    struct procstat *psend;
     3777    int col;
     3778    int indent_col;
     3779    char s[80];
     3780
     3781    ps = jp->ps;
     3782
     3783    if (mode & SHOW_PGID) {
     3784        /* just output process (group) id of pipeline */
     3785        fprintf(out, "%d\n", ps->pid);
     3786        return;
     3787    }
     3788
     3789    col = fmtstr(s, 16, "[%d]   ", jobno(jp));
     3790    indent_col = col;
     3791
     3792    if (jp == curjob)
     3793        s[col - 2] = '+';
     3794    else if (curjob && jp == curjob->prev_job)
     3795        s[col - 2] = '-';
     3796
     3797    if (mode & SHOW_PID)
     3798        col += fmtstr(s + col, 16, "%d ", ps->pid);
     3799
     3800    psend = ps + jp->nprocs;
     3801
     3802    if (jp->state == JOBRUNNING) {
     3803        strcpy(s + col, "Running");
     3804        col += sizeof("Running") - 1;
     3805    } else {
     3806        int status = psend[-1].status;
     3807        if (jp->state == JOBSTOPPED)
     3808            status = jp->stopstatus;
     3809        col += sprint_status(s + col, status, 0);
     3810    }
     3811
     3812    goto start;
     3813
     3814    do {
     3815        /* for each process */
     3816        col = fmtstr(s, 48, " |\n%*c%d ", indent_col, ' ', ps->pid) - 3;
     3817 start:
     3818        fprintf(out, "%s%*c%s",
     3819            s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
     3820        );
     3821        if (!(mode & SHOW_PID)) {
     3822            showpipe(jp, out);
     3823            break;
     3824        }
     3825        if (++ps == psend) {
     3826            outcslow('\n', out);
     3827            break;
     3828        }
     3829    } while (1);
     3830
     3831    jp->changed = 0;
     3832
     3833    if (jp->state == JOBDONE) {
     3834        TRACE(("showjob: freeing job %d\n", jobno(jp)));
     3835        freejob(jp);
     3836    }
     3837}
     3838
     3839/*
     3840 * Print a list of jobs.  If "change" is nonzero, only print jobs whose
     3841 * statuses have changed since the last call to showjobs.
     3842 */
     3843static void
     3844showjobs(FILE *out, int mode)
    74233845{
    74243846    struct job *jp;
     3847
     3848    TRACE(("showjobs(%x) called\n", mode));
     3849
     3850    /* If not even one one job changed, there is nothing to do */
     3851    while (dowait(DOWAIT_NORMAL, NULL) > 0)
     3852        continue;
     3853
     3854    for (jp = curjob; jp; jp = jp->prev_job) {
     3855        if (!(mode & SHOW_CHANGED) || jp->changed) {
     3856            showjob(out, jp, mode);
     3857        }
     3858    }
     3859}
     3860
     3861static int
     3862jobscmd(int argc, char **argv)
     3863{
     3864    int mode, m;
     3865
     3866    mode = 0;
     3867    while ((m = nextopt("lp"))) {
     3868        if (m == 'l')
     3869            mode = SHOW_PID;
     3870        else
     3871            mode = SHOW_PGID;
     3872    }
     3873
     3874    argv = argptr;
     3875    if (*argv) {
     3876        do
     3877            showjob(stdout, getjob(*argv,0), mode);
     3878        while (*++argv);
     3879    } else
     3880        showjobs(stdout, mode);
     3881
     3882    return 0;
     3883}
     3884#endif /* JOBS */
     3885
     3886static int
     3887getstatus(struct job *job)
     3888{
     3889    int status;
    74253890    int retval;
    74263891
     3892    status = job->ps[job->nprocs - 1].status;
     3893    retval = WEXITSTATUS(status);
     3894    if (!WIFEXITED(status)) {
     3895#if JOBS
     3896        retval = WSTOPSIG(status);
     3897        if (!WIFSTOPPED(status))
     3898#endif
     3899        {
     3900            /* XXX: limits number of signals */
     3901            retval = WTERMSIG(status);
     3902#if JOBS
     3903            if (retval == SIGINT)
     3904                job->sigint = 1;
     3905#endif
     3906        }
     3907        retval += 128;
     3908    }
     3909    TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
     3910        jobno(job), job->nprocs, status, retval));
     3911    return retval;
     3912}
     3913
     3914static int
     3915waitcmd(int argc, char **argv)
     3916{
     3917    struct job *job;
     3918    int retval;
     3919    struct job *jp;
     3920
     3921    EXSIGON;
     3922
     3923    nextopt(nullstr);
    74273924    retval = 0;
    7428     if (job_warning)
    7429         goto out;
    7430     jp = curjob;
    7431     if (jp && jp->state == JOBSTOPPED) {
    7432         out2str("You have stopped jobs.\n");
    7433         job_warning = 2;
    7434         retval++;
    7435     }
    7436 
    7437 out:
     3925
     3926    argv = argptr;
     3927    if (!*argv) {
     3928        /* wait for all jobs */
     3929        for (;;) {
     3930            jp = curjob;
     3931            while (1) {
     3932                if (!jp) {
     3933                    /* no running procs */
     3934                    goto out;
     3935                }
     3936                if (jp->state == JOBRUNNING)
     3937                    break;
     3938                jp->waited = 1;
     3939                jp = jp->prev_job;
     3940            }
     3941            dowait(DOWAIT_BLOCK, 0);
     3942        }
     3943    }
     3944
     3945    retval = 127;
     3946    do {
     3947        if (**argv != '%') {
     3948            pid_t pid = number(*argv);
     3949            job = curjob;
     3950            goto start;
     3951            do {
     3952                if (job->ps[job->nprocs - 1].pid == pid)
     3953                    break;
     3954                job = job->prev_job;
     3955 start:
     3956                if (!job)
     3957                    goto repeat;
     3958            } while (1);
     3959        } else
     3960            job = getjob(*argv, 0);
     3961        /* loop until process terminated or stopped */
     3962        while (job->state == JOBRUNNING)
     3963            dowait(DOWAIT_BLOCK, 0);
     3964        job->waited = 1;
     3965        retval = getstatus(job);
     3966 repeat:
     3967        ;
     3968    } while (*++argv);
     3969
     3970 out:
    74383971    return retval;
    74393972}
    74403973
     3974static struct job *
     3975growjobtab(void)
     3976{
     3977    size_t len;
     3978    ptrdiff_t offset;
     3979    struct job *jp, *jq;
     3980
     3981    len = njobs * sizeof(*jp);
     3982    jq = jobtab;
     3983    jp = ckrealloc(jq, len + 4 * sizeof(*jp));
     3984
     3985    offset = (char *)jp - (char *)jq;
     3986    if (offset) {
     3987        /* Relocate pointers */
     3988        size_t l = len;
     3989
     3990        jq = (struct job *)((char *)jq + l);
     3991        while (l) {
     3992            l -= sizeof(*jp);
     3993            jq--;
     3994#define joff(p) ((struct job *)((char *)(p) + l))
     3995#define jmove(p) (p) = (void *)((char *)(p) + offset)
     3996            if (joff(jp)->ps == &jq->ps0)
     3997                jmove(joff(jp)->ps);
     3998            if (joff(jp)->prev_job)
     3999                jmove(joff(jp)->prev_job);
     4000        }
     4001        if (curjob)
     4002            jmove(curjob);
     4003#undef joff
     4004#undef jmove
     4005    }
     4006
     4007    njobs += 4;
     4008    jobtab = jp;
     4009    jp = (struct job *)((char *)jp + len);
     4010    jq = jp + 3;
     4011    do {
     4012        jq->used = 0;
     4013    } while (--jq >= jp);
     4014    return jp;
     4015}
     4016
     4017/*
     4018 * Return a new job structure.
     4019 * Called with interrupts off.
     4020 */
     4021static struct job *
     4022makejob(union node *node, int nprocs)
     4023{
     4024    int i;
     4025    struct job *jp;
     4026
     4027    for (i = njobs, jp = jobtab; ; jp++) {
     4028        if (--i < 0) {
     4029            jp = growjobtab();
     4030            break;
     4031        }
     4032        if (jp->used == 0)
     4033            break;
     4034        if (jp->state != JOBDONE || !jp->waited)
     4035            continue;
     4036#if JOBS
     4037        if (jobctl)
     4038            continue;
     4039#endif
     4040        freejob(jp);
     4041        break;
     4042    }
     4043    memset(jp, 0, sizeof(*jp));
     4044#if JOBS
     4045    /* jp->jobctl is a bitfield.
     4046     * "jp->jobctl |= jobctl" likely to give awful code */
     4047    if (jobctl)
     4048        jp->jobctl = 1;
     4049#endif
     4050    jp->prev_job = curjob;
     4051    curjob = jp;
     4052    jp->used = 1;
     4053    jp->ps = &jp->ps0;
     4054    if (nprocs > 1) {
     4055        jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
     4056    }
     4057    TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
     4058                jobno(jp)));
     4059    return jp;
     4060}
     4061
     4062#if JOBS
    74414063/*
    74424064 * Return a string identifying a command (to be printed by the
    74434065 * jobs command).
    74444066 */
    7445 
    7446 #if JOBS
    74474067static char *cmdnextc;
    7448 
    7449 static char *
    7450 commandtext(union node *n)
    7451 {
    7452     char *name;
    7453 
    7454     STARTSTACKSTR(cmdnextc);
    7455     cmdtxt(n);
    7456     name = stackblock();
    7457     TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
    7458         name, cmdnextc, cmdnextc));
    7459     return savestr(name);
    7460 }
    7461 
    7462 static void
    7463 cmdtxt(union node *n)
    7464 {
    7465     union node *np;
    7466     struct nodelist *lp;
    7467     const char *p;
    7468     char s[2];
    7469 
    7470     if (!n)
    7471         return;
    7472     switch (n->type) {
    7473     default:
    7474 #if DEBUG
    7475         abort();
    7476 #endif
    7477     case NPIPE:
    7478         lp = n->npipe.cmdlist;
    7479         for (;;) {
    7480             cmdtxt(lp->n);
    7481             lp = lp->next;
    7482             if (!lp)
    7483                 break;
    7484             cmdputs(" | ");
    7485         }
    7486         break;
    7487     case NSEMI:
    7488         p = "; ";
    7489         goto binop;
    7490     case NAND:
    7491         p = " && ";
    7492         goto binop;
    7493     case NOR:
    7494         p = " || ";
    7495 binop:
    7496         cmdtxt(n->nbinary.ch1);
    7497         cmdputs(p);
    7498         n = n->nbinary.ch2;
    7499         goto donode;
    7500     case NREDIR:
    7501     case NBACKGND:
    7502         n = n->nredir.n;
    7503         goto donode;
    7504     case NNOT:
    7505         cmdputs("!");
    7506         n = n->nnot.com;
    7507 donode:
    7508         cmdtxt(n);
    7509         break;
    7510     case NIF:
    7511         cmdputs("if ");
    7512         cmdtxt(n->nif.test);
    7513         cmdputs("; then ");
    7514         n = n->nif.ifpart;
    7515         if (n->nif.elsepart) {
    7516             cmdtxt(n);
    7517             cmdputs("; else ");
    7518             n = n->nif.elsepart;
    7519         }
    7520         p = "; fi";
    7521         goto dotail;
    7522     case NSUBSHELL:
    7523         cmdputs("(");
    7524         n = n->nredir.n;
    7525         p = ")";
    7526         goto dotail;
    7527     case NWHILE:
    7528         p = "while ";
    7529         goto until;
    7530     case NUNTIL:
    7531         p = "until ";
    7532 until:
    7533         cmdputs(p);
    7534         cmdtxt(n->nbinary.ch1);
    7535         n = n->nbinary.ch2;
    7536         p = "; done";
    7537 dodo:
    7538         cmdputs("; do ");
    7539 dotail:
    7540         cmdtxt(n);
    7541         goto dotail2;
    7542     case NFOR:
    7543         cmdputs("for ");
    7544         cmdputs(n->nfor.var);
    7545         cmdputs(" in ");
    7546         cmdlist(n->nfor.args, 1);
    7547         n = n->nfor.body;
    7548         p = "; done";
    7549         goto dodo;
    7550     case NDEFUN:
    7551         cmdputs(n->narg.text);
    7552         p = "() { ... }";
    7553         goto dotail2;
    7554     case NCMD:
    7555         cmdlist(n->ncmd.args, 1);
    7556         cmdlist(n->ncmd.redirect, 0);
    7557         break;
    7558     case NARG:
    7559         p = n->narg.text;
    7560 dotail2:
    7561         cmdputs(p);
    7562         break;
    7563     case NHERE:
    7564     case NXHERE:
    7565         p = "<<...";
    7566         goto dotail2;
    7567     case NCASE:
    7568         cmdputs("case ");
    7569         cmdputs(n->ncase.expr->narg.text);
    7570         cmdputs(" in ");
    7571         for (np = n->ncase.cases; np; np = np->nclist.next) {
    7572             cmdtxt(np->nclist.pattern);
    7573             cmdputs(") ");
    7574             cmdtxt(np->nclist.body);
    7575             cmdputs(";; ");
    7576         }
    7577         p = "esac";
    7578         goto dotail2;
    7579     case NTO:
    7580         p = ">";
    7581         goto redir;
    7582     case NCLOBBER:
    7583         p = ">|";
    7584         goto redir;
    7585     case NAPPEND:
    7586         p = ">>";
    7587         goto redir;
    7588     case NTOFD:
    7589         p = ">&";
    7590         goto redir;
    7591     case NFROM:
    7592         p = "<";
    7593         goto redir;
    7594     case NFROMFD:
    7595         p = "<&";
    7596         goto redir;
    7597     case NFROMTO:
    7598         p = "<>";
    7599 redir:
    7600         s[0] = n->nfile.fd + '0';
    7601         s[1] = '\0';
    7602         cmdputs(s);
    7603         cmdputs(p);
    7604         if (n->type == NTOFD || n->type == NFROMFD) {
    7605             s[0] = n->ndup.dupfd + '0';
    7606             p = s;
    7607             goto dotail2;
    7608         } else {
    7609             n = n->nfile.fname;
    7610             goto donode;
    7611         }
    7612     }
    7613 }
    7614 
    7615 static void
    7616 cmdlist(union node *np, int sep)
    7617 {
    7618     for (; np; np = np->narg.next) {
    7619         if (!sep)
    7620             cmdputs(spcstr);
    7621         cmdtxt(np);
    7622         if (sep && np->narg.next)
    7623             cmdputs(spcstr);
    7624     }
    7625 }
    76264068
    76274069static void
     
    76374079        "%", "%%", "#", "##"
    76384080    };
     4081
    76394082    nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
    76404083    p = s;
     
    76514094            else
    76524095                str = "${";
    7653             if (!(subtype & VSQUOTE) != !(quoted & 1)) {
    7654                 quoted ^= 1;
    7655                 c = '"';
    7656             } else
     4096            if (!(subtype & VSQUOTE) == !(quoted & 1))
    76574097                goto dostr;
     4098            quoted ^= 1;
     4099            c = '"';
    76584100            break;
    76594101        case CTLENDVAR:
     
    76684110            str = "\"$(...)\"";
    76694111            goto dostr;
    7670 #ifdef CONFIG_ASH_MATH_SUPPORT
     4112#if ENABLE_ASH_MATH_SUPPORT
    76714113        case CTLARI:
    76724114            str = "$((";
     
    77044146        }
    77054147        USTPUTC(c, nextc);
    7706 checkstr:
     4148 checkstr:
    77074149        if (!str)
    77084150            continue;
    7709 dostr:
     4151 dostr:
    77104152        while ((c = *str++)) {
    77114153            USTPUTC(c, nextc);
     
    77194161}
    77204162
    7721 
    7722 static void
    7723 showpipe(struct job *jp, FILE *out)
    7724 {
    7725     struct procstat *sp;
    7726     struct procstat *spend;
    7727 
    7728     spend = jp->ps + jp->nprocs;
    7729     for (sp = jp->ps + 1; sp < spend; sp++)
    7730         fprintf(out, " | %s", sp->cmd);
    7731     outcslow('\n', out);
    7732     flushall();
    7733 }
    7734 
    7735 static void
    7736 xtcsetpgrp(int fd, pid_t pgrp)
    7737 {
    7738     if (tcsetpgrp(fd, pgrp))
    7739         sh_error("Cannot set tty process group (%m)");
     4163/* cmdtxt() and cmdlist() call each other */
     4164static void cmdtxt(union node *n);
     4165
     4166static void
     4167cmdlist(union node *np, int sep)
     4168{
     4169    for (; np; np = np->narg.next) {
     4170        if (!sep)
     4171            cmdputs(" ");
     4172        cmdtxt(np);
     4173        if (sep && np->narg.next)
     4174            cmdputs(" ");
     4175    }
     4176}
     4177
     4178static void
     4179cmdtxt(union node *n)
     4180{
     4181    union node *np;
     4182    struct nodelist *lp;
     4183    const char *p;
     4184    char s[2];
     4185
     4186    if (!n)
     4187        return;
     4188    switch (n->type) {
     4189    default:
     4190#if DEBUG
     4191        abort();
     4192#endif
     4193    case NPIPE:
     4194        lp = n->npipe.cmdlist;
     4195        for (;;) {
     4196            cmdtxt(lp->n);
     4197            lp = lp->next;
     4198            if (!lp)
     4199                break;
     4200            cmdputs(" | ");
     4201        }
     4202        break;
     4203    case NSEMI:
     4204        p = "; ";
     4205        goto binop;
     4206    case NAND:
     4207        p = " && ";
     4208        goto binop;
     4209    case NOR:
     4210        p = " || ";
     4211 binop:
     4212        cmdtxt(n->nbinary.ch1);
     4213        cmdputs(p);
     4214        n = n->nbinary.ch2;
     4215        goto donode;
     4216    case NREDIR:
     4217    case NBACKGND:
     4218        n = n->nredir.n;
     4219        goto donode;
     4220    case NNOT:
     4221        cmdputs("!");
     4222        n = n->nnot.com;
     4223 donode:
     4224        cmdtxt(n);
     4225        break;
     4226    case NIF:
     4227        cmdputs("if ");
     4228        cmdtxt(n->nif.test);
     4229        cmdputs("; then ");
     4230        n = n->nif.ifpart;
     4231        if (n->nif.elsepart) {
     4232            cmdtxt(n);
     4233            cmdputs("; else ");
     4234            n = n->nif.elsepart;
     4235        }
     4236        p = "; fi";
     4237        goto dotail;
     4238    case NSUBSHELL:
     4239        cmdputs("(");
     4240        n = n->nredir.n;
     4241        p = ")";
     4242        goto dotail;
     4243    case NWHILE:
     4244        p = "while ";
     4245        goto until;
     4246    case NUNTIL:
     4247        p = "until ";
     4248 until:
     4249        cmdputs(p);
     4250        cmdtxt(n->nbinary.ch1);
     4251        n = n->nbinary.ch2;
     4252        p = "; done";
     4253 dodo:
     4254        cmdputs("; do ");
     4255 dotail:
     4256        cmdtxt(n);
     4257        goto dotail2;
     4258    case NFOR:
     4259        cmdputs("for ");
     4260        cmdputs(n->nfor.var);
     4261        cmdputs(" in ");
     4262        cmdlist(n->nfor.args, 1);
     4263        n = n->nfor.body;
     4264        p = "; done";
     4265        goto dodo;
     4266    case NDEFUN:
     4267        cmdputs(n->narg.text);
     4268        p = "() { ... }";
     4269        goto dotail2;
     4270    case NCMD:
     4271        cmdlist(n->ncmd.args, 1);
     4272        cmdlist(n->ncmd.redirect, 0);
     4273        break;
     4274    case NARG:
     4275        p = n->narg.text;
     4276 dotail2:
     4277        cmdputs(p);
     4278        break;
     4279    case NHERE:
     4280    case NXHERE:
     4281        p = "<<...";
     4282        goto dotail2;
     4283    case NCASE:
     4284        cmdputs("case ");
     4285        cmdputs(n->ncase.expr->narg.text);
     4286        cmdputs(" in ");
     4287        for (np = n->ncase.cases; np; np = np->nclist.next) {
     4288            cmdtxt(np->nclist.pattern);
     4289            cmdputs(") ");
     4290            cmdtxt(np->nclist.body);
     4291            cmdputs(";; ");
     4292        }
     4293        p = "esac";
     4294        goto dotail2;
     4295    case NTO:
     4296        p = ">";
     4297        goto redir;
     4298    case NCLOBBER:
     4299        p = ">|";
     4300        goto redir;
     4301    case NAPPEND:
     4302        p = ">>";
     4303        goto redir;
     4304    case NTOFD:
     4305        p = ">&";
     4306        goto redir;
     4307    case NFROM:
     4308        p = "<";
     4309        goto redir;
     4310    case NFROMFD:
     4311        p = "<&";
     4312        goto redir;
     4313    case NFROMTO:
     4314        p = "<>";
     4315 redir:
     4316        s[0] = n->nfile.fd + '0';
     4317        s[1] = '\0';
     4318        cmdputs(s);
     4319        cmdputs(p);
     4320        if (n->type == NTOFD || n->type == NFROMFD) {
     4321            s[0] = n->ndup.dupfd + '0';
     4322            p = s;
     4323            goto dotail2;
     4324        }
     4325        n = n->nfile.fname;
     4326        goto donode;
     4327    }
     4328}
     4329
     4330static char *
     4331commandtext(union node *n)
     4332{
     4333    char *name;
     4334
     4335    STARTSTACKSTR(cmdnextc);
     4336    cmdtxt(n);
     4337    name = stackblock();
     4338    TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
     4339            name, cmdnextc, cmdnextc));
     4340    return ckstrdup(name);
    77404341}
    77414342#endif /* JOBS */
    77424343
     4344/*
     4345 * Fork off a subshell.  If we are doing job control, give the subshell its
     4346 * own process group.  Jp is a job structure that the job is to be added to.
     4347 * N is the command that will be evaluated by the child.  Both jp and n may
     4348 * be NULL.  The mode parameter can be one of the following:
     4349 *      FORK_FG - Fork off a foreground process.
     4350 *      FORK_BG - Fork off a background process.
     4351 *      FORK_NOJOB - Like FORK_FG, but don't give the process its own
     4352 *                   process group even if job control is on.
     4353 *
     4354 * When job control is turned off, background processes have their standard
     4355 * input redirected to /dev/null (except for the second and later processes
     4356 * in a pipeline).
     4357 *
     4358 * Called with interrupts off.
     4359 */
     4360/*
     4361 * Clear traps on a fork.
     4362 */
     4363static void
     4364clear_traps(void)
     4365{
     4366    char **tp;
     4367
     4368    for (tp = trap; tp < &trap[NSIG]; tp++) {
     4369        if (*tp && **tp) {      /* trap not NULL or SIG_IGN */
     4370            INT_OFF;
     4371            free(*tp);
     4372            *tp = NULL;
     4373            if (tp != &trap[0])
     4374                setsignal(tp - trap);
     4375            INT_ON;
     4376        }
     4377    }
     4378}
     4379
     4380/* Lives far away from here, needed for forkchild */
     4381static void closescript(void);
     4382/* Called after fork(), in child */
     4383static void
     4384forkchild(struct job *jp, union node *n, int mode)
     4385{
     4386    int oldlvl;
     4387
     4388    TRACE(("Child shell %d\n", getpid()));
     4389    oldlvl = shlvl;
     4390    shlvl++;
     4391
     4392    closescript();
     4393    clear_traps();
     4394#if JOBS
     4395    /* do job control only in root shell */
     4396    jobctl = 0;
     4397    if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) {
     4398        pid_t pgrp;
     4399
     4400        if (jp->nprocs == 0)
     4401            pgrp = getpid();
     4402        else
     4403            pgrp = jp->ps[0].pid;
     4404        /* This can fail because we are doing it in the parent also */
     4405        (void)setpgid(0, pgrp);
     4406        if (mode == FORK_FG)
     4407            xtcsetpgrp(ttyfd, pgrp);
     4408        setsignal(SIGTSTP);
     4409        setsignal(SIGTTOU);
     4410    } else
     4411#endif
     4412    if (mode == FORK_BG) {
     4413        ignoresig(SIGINT);
     4414        ignoresig(SIGQUIT);
     4415        if (jp->nprocs == 0) {
     4416            close(0);
     4417            if (open(bb_dev_null, O_RDONLY) != 0)
     4418                ash_msg_and_raise_error("can't open %s", bb_dev_null);
     4419        }
     4420    }
     4421    if (!oldlvl && iflag) {
     4422        setsignal(SIGINT);
     4423        setsignal(SIGQUIT);
     4424        setsignal(SIGTERM);
     4425    }
     4426#if JOBS
     4427    /* For "jobs | cat" to work like in bash, we must retain list of jobs
     4428     * in child, but we do need to remove ourself */
     4429    if (jp)
     4430        freejob(jp);
     4431#else
     4432    for (jp = curjob; jp; jp = jp->prev_job)
     4433        freejob(jp);
     4434#endif
     4435    jobless = 0;
     4436}
     4437
     4438/* Called after fork(), in parent */
     4439static void
     4440forkparent(struct job *jp, union node *n, int mode, pid_t pid)
     4441{
     4442    TRACE(("In parent shell: child = %d\n", pid));
     4443    if (!jp) {
     4444        while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
     4445        jobless++;
     4446        return;
     4447    }
     4448#if JOBS
     4449    if (mode != FORK_NOJOB && jp->jobctl) {
     4450        int pgrp;
     4451
     4452        if (jp->nprocs == 0)
     4453            pgrp = pid;
     4454        else
     4455            pgrp = jp->ps[0].pid;
     4456        /* This can fail because we are doing it in the child also */
     4457        setpgid(pid, pgrp);
     4458    }
     4459#endif
     4460    if (mode == FORK_BG) {
     4461        backgndpid = pid;               /* set $! */
     4462        set_curjob(jp, CUR_RUNNING);
     4463    }
     4464    if (jp) {
     4465        struct procstat *ps = &jp->ps[jp->nprocs++];
     4466        ps->pid = pid;
     4467        ps->status = -1;
     4468        ps->cmd = nullstr;
     4469#if JOBS
     4470        if (jobctl && n)
     4471            ps->cmd = commandtext(n);
     4472#endif
     4473    }
     4474}
     4475
    77434476static int
    7744 getstatus(struct job *job) {
     4477forkshell(struct job *jp, union node *n, int mode)
     4478{
     4479    int pid;
     4480
     4481    TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
     4482    pid = fork();
     4483    if (pid < 0) {
     4484        TRACE(("Fork failed, errno=%d", errno));
     4485        if (jp)
     4486            freejob(jp);
     4487        ash_msg_and_raise_error("cannot fork");
     4488    }
     4489    if (pid == 0)
     4490        forkchild(jp, n, mode);
     4491    else
     4492        forkparent(jp, n, mode, pid);
     4493    return pid;
     4494}
     4495
     4496/*
     4497 * Wait for job to finish.
     4498 *
     4499 * Under job control we have the problem that while a child process is
     4500 * running interrupts generated by the user are sent to the child but not
     4501 * to the shell.  This means that an infinite loop started by an inter-
     4502 * active user may be hard to kill.  With job control turned off, an
     4503 * interactive user may place an interactive program inside a loop.  If
     4504 * the interactive program catches interrupts, the user doesn't want
     4505 * these interrupts to also abort the loop.  The approach we take here
     4506 * is to have the shell ignore interrupt signals while waiting for a
     4507 * foreground process to terminate, and then send itself an interrupt
     4508 * signal if the child process was terminated by an interrupt signal.
     4509 * Unfortunately, some programs want to do a bit of cleanup and then
     4510 * exit on interrupt; unless these processes terminate themselves by
     4511 * sending a signal to themselves (instead of calling exit) they will
     4512 * confuse this approach.
     4513 *
     4514 * Called with interrupts off.
     4515 */
     4516static int
     4517waitforjob(struct job *jp)
     4518{
     4519    int st;
     4520
     4521    TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
     4522    while (jp->state == JOBRUNNING) {
     4523        dowait(DOWAIT_BLOCK, jp);
     4524    }
     4525    st = getstatus(jp);
     4526#if JOBS
     4527    if (jp->jobctl) {
     4528        xtcsetpgrp(ttyfd, rootpid);
     4529        /*
     4530         * This is truly gross.
     4531         * If we're doing job control, then we did a TIOCSPGRP which
     4532         * caused us (the shell) to no longer be in the controlling
     4533         * session -- so we wouldn't have seen any ^C/SIGINT.  So, we
     4534         * intuit from the subprocess exit status whether a SIGINT
     4535         * occurred, and if so interrupt ourselves.  Yuck.  - mycroft
     4536         */
     4537        if (jp->sigint)
     4538            raise(SIGINT);
     4539    }
     4540    if (jp->state == JOBDONE)
     4541#endif
     4542        freejob(jp);
     4543    return st;
     4544}
     4545
     4546/*
     4547 * return 1 if there are stopped jobs, otherwise 0
     4548 */
     4549static int
     4550stoppedjobs(void)
     4551{
     4552    struct job *jp;
     4553    int retval;
     4554
     4555    retval = 0;
     4556    if (job_warning)
     4557        goto out;
     4558    jp = curjob;
     4559    if (jp && jp->state == JOBSTOPPED) {
     4560        out2str("You have stopped jobs.\n");
     4561        job_warning = 2;
     4562        retval++;
     4563    }
     4564 out:
     4565    return retval;
     4566}
     4567
     4568
     4569/* ============ redir.c
     4570 *
     4571 * Code for dealing with input/output redirection.
     4572 */
     4573
     4574#define EMPTY -2                /* marks an unused slot in redirtab */
     4575#ifndef PIPE_BUF
     4576# define PIPESIZE 4096          /* amount of buffering in a pipe */
     4577#else
     4578# define PIPESIZE PIPE_BUF
     4579#endif
     4580
     4581/*
     4582 * Open a file in noclobber mode.
     4583 * The code was copied from bash.
     4584 */
     4585static int
     4586noclobberopen(const char *fname)
     4587{
     4588    int r, fd;
     4589    struct stat finfo, finfo2;
     4590
     4591    /*
     4592     * If the file exists and is a regular file, return an error
     4593     * immediately.
     4594     */
     4595    r = stat(fname, &finfo);
     4596    if (r == 0 && S_ISREG(finfo.st_mode)) {
     4597        errno = EEXIST;
     4598        return -1;
     4599    }
     4600
     4601    /*
     4602     * If the file was not present (r != 0), make sure we open it
     4603     * exclusively so that if it is created before we open it, our open
     4604     * will fail.  Make sure that we do not truncate an existing file.
     4605     * Note that we don't turn on O_EXCL unless the stat failed -- if the
     4606     * file was not a regular file, we leave O_EXCL off.
     4607     */
     4608    if (r != 0)
     4609        return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
     4610    fd = open(fname, O_WRONLY|O_CREAT, 0666);
     4611
     4612    /* If the open failed, return the file descriptor right away. */
     4613    if (fd < 0)
     4614        return fd;
     4615
     4616    /*
     4617     * OK, the open succeeded, but the file may have been changed from a
     4618     * non-regular file to a regular file between the stat and the open.
     4619     * We are assuming that the O_EXCL open handles the case where FILENAME
     4620     * did not exist and is symlinked to an existing file between the stat
     4621     * and open.
     4622     */
     4623
     4624    /*
     4625     * If we can open it and fstat the file descriptor, and neither check
     4626     * revealed that it was a regular file, and the file has not been
     4627     * replaced, return the file descriptor.
     4628     */
     4629    if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode)
     4630     && finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
     4631        return fd;
     4632
     4633    /* The file has been replaced.  badness. */
     4634    close(fd);
     4635    errno = EEXIST;
     4636    return -1;
     4637}
     4638
     4639/*
     4640 * Handle here documents.  Normally we fork off a process to write the
     4641 * data to a pipe.  If the document is short, we can stuff the data in
     4642 * the pipe without forking.
     4643 */
     4644/* openhere needs this forward reference */
     4645static void expandhere(union node *arg, int fd);
     4646static int
     4647openhere(union node *redir)
     4648{
     4649    int pip[2];
     4650    size_t len = 0;
     4651
     4652    if (pipe(pip) < 0)
     4653        ash_msg_and_raise_error("pipe call failed");
     4654    if (redir->type == NHERE) {
     4655        len = strlen(redir->nhere.doc->narg.text);
     4656        if (len <= PIPESIZE) {
     4657            full_write(pip[1], redir->nhere.doc->narg.text, len);
     4658            goto out;
     4659        }
     4660    }
     4661    if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
     4662        close(pip[0]);
     4663        signal(SIGINT, SIG_IGN);
     4664        signal(SIGQUIT, SIG_IGN);
     4665        signal(SIGHUP, SIG_IGN);
     4666#ifdef SIGTSTP
     4667        signal(SIGTSTP, SIG_IGN);
     4668#endif
     4669        signal(SIGPIPE, SIG_DFL);
     4670        if (redir->type == NHERE)
     4671            full_write(pip[1], redir->nhere.doc->narg.text, len);
     4672        else
     4673            expandhere(redir->nhere.doc, pip[1]);
     4674        _exit(0);
     4675    }
     4676 out:
     4677    close(pip[1]);
     4678    return pip[0];
     4679}
     4680
     4681static int
     4682openredirect(union node *redir)
     4683{
     4684    char *fname;
     4685    int f;
     4686
     4687    switch (redir->nfile.type) {
     4688    case NFROM:
     4689        fname = redir->nfile.expfname;
     4690        f = open(fname, O_RDONLY);
     4691        if (f < 0)
     4692            goto eopen;
     4693        break;
     4694    case NFROMTO:
     4695        fname = redir->nfile.expfname;
     4696        f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666);
     4697        if (f < 0)
     4698            goto ecreate;
     4699        break;
     4700    case NTO:
     4701        /* Take care of noclobber mode. */
     4702        if (Cflag) {
     4703            fname = redir->nfile.expfname;
     4704            f = noclobberopen(fname);
     4705            if (f < 0)
     4706                goto ecreate;
     4707            break;
     4708        }
     4709        /* FALLTHROUGH */
     4710    case NCLOBBER:
     4711        fname = redir->nfile.expfname;
     4712        f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
     4713        if (f < 0)
     4714            goto ecreate;
     4715        break;
     4716    case NAPPEND:
     4717        fname = redir->nfile.expfname;
     4718        f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
     4719        if (f < 0)
     4720            goto ecreate;
     4721        break;
     4722    default:
     4723#if DEBUG
     4724        abort();
     4725#endif
     4726        /* Fall through to eliminate warning. */
     4727    case NTOFD:
     4728    case NFROMFD:
     4729        f = -1;
     4730        break;
     4731    case NHERE:
     4732    case NXHERE:
     4733        f = openhere(redir);
     4734        break;
     4735    }
     4736
     4737    return f;
     4738 ecreate:
     4739    ash_msg_and_raise_error("cannot create %s: %s", fname, errmsg(errno, "nonexistent directory"));
     4740 eopen:
     4741    ash_msg_and_raise_error("cannot open %s: %s", fname, errmsg(errno, "no such file"));
     4742}
     4743
     4744/*
     4745 * Copy a file descriptor to be >= to.  Returns -1
     4746 * if the source file descriptor is closed, EMPTY if there are no unused
     4747 * file descriptors left.
     4748 */
     4749static int
     4750copyfd(int from, int to)
     4751{
     4752    int newfd;
     4753
     4754    newfd = fcntl(from, F_DUPFD, to);
     4755    if (newfd < 0) {
     4756        if (errno == EMFILE)
     4757            return EMPTY;
     4758        ash_msg_and_raise_error("%d: %m", from);
     4759    }
     4760    return newfd;
     4761}
     4762
     4763static void
     4764dupredirect(union node *redir, int f)
     4765{
     4766    int fd = redir->nfile.fd;
     4767
     4768    if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
     4769        if (redir->ndup.dupfd >= 0) {   /* if not ">&-" */
     4770            copyfd(redir->ndup.dupfd, fd);
     4771        }
     4772        return;
     4773    }
     4774
     4775    if (f != fd) {
     4776        copyfd(f, fd);
     4777        close(f);
     4778    }
     4779}
     4780
     4781/*
     4782 * Process a list of redirection commands.  If the REDIR_PUSH flag is set,
     4783 * old file descriptors are stashed away so that the redirection can be
     4784 * undone by calling popredir.  If the REDIR_BACKQ flag is set, then the
     4785 * standard output, and the standard error if it becomes a duplicate of
     4786 * stdout, is saved in memory.
     4787 */
     4788/* flags passed to redirect */
     4789#define REDIR_PUSH    01        /* save previous values of file descriptors */
     4790#define REDIR_SAVEFD2 03        /* set preverrout */
     4791static void
     4792redirect(union node *redir, int flags)
     4793{
     4794    union node *n;
     4795    struct redirtab *sv;
     4796    int i;
     4797    int fd;
     4798    int newfd;
     4799    int *p;
     4800    nullredirs++;
     4801    if (!redir) {
     4802        return;
     4803    }
     4804    sv = NULL;
     4805    INT_OFF;
     4806    if (flags & REDIR_PUSH) {
     4807        struct redirtab *q;
     4808        q = ckmalloc(sizeof(struct redirtab));
     4809        q->next = redirlist;
     4810        redirlist = q;
     4811        q->nullredirs = nullredirs - 1;
     4812        for (i = 0; i < 10; i++)
     4813            q->renamed[i] = EMPTY;
     4814        nullredirs = 0;
     4815        sv = q;
     4816    }
     4817    n = redir;
     4818    do {
     4819        fd = n->nfile.fd;
     4820        if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD)
     4821         && n->ndup.dupfd == fd)
     4822            continue; /* redirect from/to same file descriptor */
     4823
     4824        newfd = openredirect(n);
     4825        if (fd == newfd)
     4826            continue;
     4827        if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
     4828            i = fcntl(fd, F_DUPFD, 10);
     4829
     4830            if (i == -1) {
     4831                i = errno;
     4832                if (i != EBADF) {
     4833                    close(newfd);
     4834                    errno = i;
     4835                    ash_msg_and_raise_error("%d: %m", fd);
     4836                    /* NOTREACHED */
     4837                }
     4838            } else {
     4839                *p = i;
     4840                close(fd);
     4841            }
     4842        } else {
     4843            close(fd);
     4844        }
     4845        dupredirect(n, newfd);
     4846    } while ((n = n->nfile.next));
     4847    INT_ON;
     4848    if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0)
     4849        preverrout_fd = sv->renamed[2];
     4850}
     4851
     4852/*
     4853 * Undo the effects of the last redirection.
     4854 */
     4855static void
     4856popredir(int drop)
     4857{
     4858    struct redirtab *rp;
     4859    int i;
     4860
     4861    if (--nullredirs >= 0)
     4862        return;
     4863    INT_OFF;
     4864    rp = redirlist;
     4865    for (i = 0; i < 10; i++) {
     4866        if (rp->renamed[i] != EMPTY) {
     4867            if (!drop) {
     4868                close(i);
     4869                copyfd(rp->renamed[i], i);
     4870            }
     4871            close(rp->renamed[i]);
     4872        }
     4873    }
     4874    redirlist = rp->next;
     4875    nullredirs = rp->nullredirs;
     4876    free(rp);
     4877    INT_ON;
     4878}
     4879
     4880/*
     4881 * Undo all redirections.  Called on error or interrupt.
     4882 */
     4883
     4884/*
     4885 * Discard all saved file descriptors.
     4886 */
     4887static void
     4888clearredir(int drop)
     4889{
     4890    for (;;) {
     4891        nullredirs = 0;
     4892        if (!redirlist)
     4893            break;
     4894        popredir(drop);
     4895    }
     4896}
     4897
     4898static int
     4899redirectsafe(union node *redir, int flags)
     4900{
     4901    int err;
     4902    volatile int saveint;
     4903    struct jmploc *volatile savehandler = exception_handler;
     4904    struct jmploc jmploc;
     4905
     4906    SAVE_INT(saveint);
     4907    err = setjmp(jmploc.loc) * 2;
     4908    if (!err) {
     4909        exception_handler = &jmploc;
     4910        redirect(redir, flags);
     4911    }
     4912    exception_handler = savehandler;
     4913    if (err && exception != EXERROR)
     4914        longjmp(exception_handler->loc, 1);
     4915    RESTORE_INT(saveint);
     4916    return err;
     4917}
     4918
     4919
     4920/* ============ Routines to expand arguments to commands
     4921 *
     4922 * We have to deal with backquotes, shell variables, and file metacharacters.
     4923 */
     4924
     4925/*
     4926 * expandarg flags
     4927 */
     4928#define EXP_FULL        0x1     /* perform word splitting & file globbing */
     4929#define EXP_TILDE       0x2     /* do normal tilde expansion */
     4930#define EXP_VARTILDE    0x4     /* expand tildes in an assignment */
     4931#define EXP_REDIR       0x8     /* file glob for a redirection (1 match only) */
     4932#define EXP_CASE        0x10    /* keeps quotes around for CASE pattern */
     4933#define EXP_RECORD      0x20    /* need to record arguments for ifs breakup */
     4934#define EXP_VARTILDE2   0x40    /* expand tildes after colons only */
     4935#define EXP_WORD        0x80    /* expand word in parameter expansion */
     4936#define EXP_QWORD       0x100   /* expand word in quoted parameter expansion */
     4937/*
     4938 * _rmescape() flags
     4939 */
     4940#define RMESCAPE_ALLOC  0x1     /* Allocate a new string */
     4941#define RMESCAPE_GLOB   0x2     /* Add backslashes for glob */
     4942#define RMESCAPE_QUOTED 0x4     /* Remove CTLESC unless in quotes */
     4943#define RMESCAPE_GROW   0x8     /* Grow strings instead of stalloc */
     4944#define RMESCAPE_HEAP   0x10    /* Malloc strings instead of stalloc */
     4945
     4946/*
     4947 * Structure specifying which parts of the string should be searched
     4948 * for IFS characters.
     4949 */
     4950struct ifsregion {
     4951    struct ifsregion *next; /* next region in list */
     4952    int begoff;             /* offset of start of region */
     4953    int endoff;             /* offset of end of region */
     4954    int nulonly;            /* search for nul bytes only */
     4955};
     4956
     4957struct arglist {
     4958    struct strlist *list;
     4959    struct strlist **lastp;
     4960};
     4961
     4962/* output of current string */
     4963static char *expdest;
     4964/* list of back quote expressions */
     4965static struct nodelist *argbackq;
     4966/* first struct in list of ifs regions */
     4967static struct ifsregion ifsfirst;
     4968/* last struct in list */
     4969static struct ifsregion *ifslastp;
     4970/* holds expanded arg list */
     4971static struct arglist exparg;
     4972
     4973/*
     4974 * Our own itoa().
     4975 */
     4976static int
     4977cvtnum(arith_t num)
     4978{
     4979    int len;
     4980
     4981    expdest = makestrspace(32, expdest);
     4982#if ENABLE_ASH_MATH_SUPPORT_64
     4983    len = fmtstr(expdest, 32, "%lld", (long long) num);
     4984#else
     4985    len = fmtstr(expdest, 32, "%ld", num);
     4986#endif
     4987    STADJUST(len, expdest);
     4988    return len;
     4989}
     4990
     4991static size_t
     4992esclen(const char *start, const char *p)
     4993{
     4994    size_t esc = 0;
     4995
     4996    while (p > start && *--p == CTLESC) {
     4997        esc++;
     4998    }
     4999    return esc;
     5000}
     5001
     5002/*
     5003 * Remove any CTLESC characters from a string.
     5004 */
     5005static char *
     5006_rmescapes(char *str, int flag)
     5007{
     5008    static const char qchars[] ALIGN1 = { CTLESC, CTLQUOTEMARK, '\0' };
     5009
     5010    char *p, *q, *r;
     5011    unsigned inquotes;
     5012    int notescaped;
     5013    int globbing;
     5014
     5015    p = strpbrk(str, qchars);
     5016    if (!p) {
     5017        return str;
     5018    }
     5019    q = p;
     5020    r = str;
     5021    if (flag & RMESCAPE_ALLOC) {
     5022        size_t len = p - str;
     5023        size_t fulllen = len + strlen(p) + 1;
     5024
     5025        if (flag & RMESCAPE_GROW) {
     5026            r = makestrspace(fulllen, expdest);
     5027        } else if (flag & RMESCAPE_HEAP) {
     5028            r = ckmalloc(fulllen);
     5029        } else {
     5030            r = stalloc(fulllen);
     5031        }
     5032        q = r;
     5033        if (len > 0) {
     5034            q = memcpy(q, str, len) + len;
     5035        }
     5036    }
     5037    inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
     5038    globbing = flag & RMESCAPE_GLOB;
     5039    notescaped = globbing;
     5040    while (*p) {
     5041        if (*p == CTLQUOTEMARK) {
     5042            inquotes = ~inquotes;
     5043            p++;
     5044            notescaped = globbing;
     5045            continue;
     5046        }
     5047        if (*p == '\\') {
     5048            /* naked back slash */
     5049            notescaped = 0;
     5050            goto copy;
     5051        }
     5052        if (*p == CTLESC) {
     5053            p++;
     5054            if (notescaped && inquotes && *p != '/') {
     5055                *q++ = '\\';
     5056            }
     5057        }
     5058        notescaped = globbing;
     5059 copy:
     5060        *q++ = *p++;
     5061    }
     5062    *q = '\0';
     5063    if (flag & RMESCAPE_GROW) {
     5064        expdest = r;
     5065        STADJUST(q - r + 1, expdest);
     5066    }
     5067    return r;
     5068}
     5069#define rmescapes(p) _rmescapes((p), 0)
     5070
     5071#define pmatch(a, b) !fnmatch((a), (b), 0)
     5072
     5073/*
     5074 * Prepare a pattern for a expmeta (internal glob(3)) call.
     5075 *
     5076 * Returns an stalloced string.
     5077 */
     5078static char *
     5079preglob(const char *pattern, int quoted, int flag)
     5080{
     5081    flag |= RMESCAPE_GLOB;
     5082    if (quoted) {
     5083        flag |= RMESCAPE_QUOTED;
     5084    }
     5085    return _rmescapes((char *)pattern, flag);
     5086}
     5087
     5088/*
     5089 * Put a string on the stack.
     5090 */
     5091static void
     5092memtodest(const char *p, size_t len, int syntax, int quotes)
     5093{
     5094    char *q = expdest;
     5095
     5096    q = makestrspace(len * 2, q);
     5097
     5098    while (len--) {
     5099        int c = signed_char2int(*p++);
     5100        if (!c)
     5101            continue;
     5102        if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
     5103            USTPUTC(CTLESC, q);
     5104        USTPUTC(c, q);
     5105    }
     5106
     5107    expdest = q;
     5108}
     5109
     5110static void
     5111strtodest(const char *p, int syntax, int quotes)
     5112{
     5113    memtodest(p, strlen(p), syntax, quotes);
     5114}
     5115
     5116/*
     5117 * Record the fact that we have to scan this region of the
     5118 * string for IFS characters.
     5119 */
     5120static void
     5121recordregion(int start, int end, int nulonly)
     5122{
     5123    struct ifsregion *ifsp;
     5124
     5125    if (ifslastp == NULL) {
     5126        ifsp = &ifsfirst;
     5127    } else {
     5128        INT_OFF;
     5129        ifsp = ckmalloc(sizeof(*ifsp));
     5130        ifsp->next = NULL;
     5131        ifslastp->next = ifsp;
     5132        INT_ON;
     5133    }
     5134    ifslastp = ifsp;
     5135    ifslastp->begoff = start;
     5136    ifslastp->endoff = end;
     5137    ifslastp->nulonly = nulonly;
     5138}
     5139
     5140static void
     5141removerecordregions(int endoff)
     5142{
     5143    if (ifslastp == NULL)
     5144        return;
     5145
     5146    if (ifsfirst.endoff > endoff) {
     5147        while (ifsfirst.next != NULL) {
     5148            struct ifsregion *ifsp;
     5149            INT_OFF;
     5150            ifsp = ifsfirst.next->next;
     5151            free(ifsfirst.next);
     5152            ifsfirst.next = ifsp;
     5153            INT_ON;
     5154        }
     5155        if (ifsfirst.begoff > endoff)
     5156            ifslastp = NULL;
     5157        else {
     5158            ifslastp = &ifsfirst;
     5159            ifsfirst.endoff = endoff;
     5160        }
     5161        return;
     5162    }
     5163
     5164    ifslastp = &ifsfirst;
     5165    while (ifslastp->next && ifslastp->next->begoff < endoff)
     5166        ifslastp=ifslastp->next;
     5167    while (ifslastp->next != NULL) {
     5168        struct ifsregion *ifsp;
     5169        INT_OFF;
     5170        ifsp = ifslastp->next->next;
     5171        free(ifslastp->next);
     5172        ifslastp->next = ifsp;
     5173        INT_ON;
     5174    }
     5175    if (ifslastp->endoff > endoff)
     5176        ifslastp->endoff = endoff;
     5177}
     5178
     5179static char *
     5180exptilde(char *startp, char *p, int flag)
     5181{
     5182    char c;
     5183    char *name;
     5184    struct passwd *pw;
     5185    const char *home;
     5186    int quotes = flag & (EXP_FULL | EXP_CASE);
     5187    int startloc;
     5188
     5189    name = p + 1;
     5190
     5191    while ((c = *++p) != '\0') {
     5192        switch (c) {
     5193        case CTLESC:
     5194            return startp;
     5195        case CTLQUOTEMARK:
     5196            return startp;
     5197        case ':':
     5198            if (flag & EXP_VARTILDE)
     5199                goto done;
     5200            break;
     5201        case '/':
     5202        case CTLENDVAR:
     5203            goto done;
     5204        }
     5205    }
     5206 done:
     5207    *p = '\0';
     5208    if (*name == '\0') {
     5209        home = lookupvar(homestr);
     5210    } else {
     5211        pw = getpwnam(name);
     5212        if (pw == NULL)
     5213            goto lose;
     5214        home = pw->pw_dir;
     5215    }
     5216    if (!home || !*home)
     5217        goto lose;
     5218    *p = c;
     5219    startloc = expdest - (char *)stackblock();
     5220    strtodest(home, SQSYNTAX, quotes);
     5221    recordregion(startloc, expdest - (char *)stackblock(), 0);
     5222    return p;
     5223 lose:
     5224    *p = c;
     5225    return startp;
     5226}
     5227
     5228/*
     5229 * Execute a command inside back quotes.  If it's a builtin command, we
     5230 * want to save its output in a block obtained from malloc.  Otherwise
     5231 * we fork off a subprocess and get the output of the command via a pipe.
     5232 * Should be called with interrupts off.
     5233 */
     5234struct backcmd {                /* result of evalbackcmd */
     5235    int fd;                 /* file descriptor to read from */
     5236    char *buf;              /* buffer */
     5237    int nleft;              /* number of chars in buffer */
     5238    struct job *jp;         /* job structure for command */
     5239};
     5240
     5241/* These forward decls are needed to use "eval" code for backticks handling: */
     5242static int back_exitstatus; /* exit status of backquoted command */
     5243#define EV_EXIT 01              /* exit after evaluating tree */
     5244static void evaltree(union node *, int);
     5245
     5246static void
     5247evalbackcmd(union node *n, struct backcmd *result)
     5248{
     5249    int saveherefd;
     5250
     5251    result->fd = -1;
     5252    result->buf = NULL;
     5253    result->nleft = 0;
     5254    result->jp = NULL;
     5255    if (n == NULL) {
     5256        goto out;
     5257    }
     5258
     5259    saveherefd = herefd;
     5260    herefd = -1;
     5261
     5262    {
     5263        int pip[2];
     5264        struct job *jp;
     5265
     5266        if (pipe(pip) < 0)
     5267            ash_msg_and_raise_error("pipe call failed");
     5268        jp = makejob(n, 1);
     5269        if (forkshell(jp, n, FORK_NOJOB) == 0) {
     5270            FORCE_INT_ON;
     5271            close(pip[0]);
     5272            if (pip[1] != 1) {
     5273                close(1);
     5274                copyfd(pip[1], 1);
     5275                close(pip[1]);
     5276            }
     5277            eflag = 0;
     5278            evaltree(n, EV_EXIT); /* actually evaltreenr... */
     5279            /* NOTREACHED */
     5280        }
     5281        close(pip[1]);
     5282        result->fd = pip[0];
     5283        result->jp = jp;
     5284    }
     5285    herefd = saveherefd;
     5286 out:
     5287    TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
     5288        result->fd, result->buf, result->nleft, result->jp));
     5289}
     5290
     5291/*
     5292 * Expand stuff in backwards quotes.
     5293 */
     5294static void
     5295expbackq(union node *cmd, int quoted, int quotes)
     5296{
     5297    struct backcmd in;
     5298    int i;
     5299    char buf[128];
     5300    char *p;
     5301    char *dest;
     5302    int startloc;
     5303    int syntax = quoted? DQSYNTAX : BASESYNTAX;
     5304    struct stackmark smark;
     5305
     5306    INT_OFF;
     5307    setstackmark(&smark);
     5308    dest = expdest;
     5309    startloc = dest - (char *)stackblock();
     5310    grabstackstr(dest);
     5311    evalbackcmd(cmd, &in);
     5312    popstackmark(&smark);
     5313
     5314    p = in.buf;
     5315    i = in.nleft;
     5316    if (i == 0)
     5317        goto read;
     5318    for (;;) {
     5319        memtodest(p, i, syntax, quotes);
     5320 read:
     5321        if (in.fd < 0)
     5322            break;
     5323        i = safe_read(in.fd, buf, sizeof(buf));
     5324        TRACE(("expbackq: read returns %d\n", i));
     5325        if (i <= 0)
     5326            break;
     5327        p = buf;
     5328    }
     5329
     5330    if (in.buf)
     5331        free(in.buf);
     5332    if (in.fd >= 0) {
     5333        close(in.fd);
     5334        back_exitstatus = waitforjob(in.jp);
     5335    }
     5336    INT_ON;
     5337
     5338    /* Eat all trailing newlines */
     5339    dest = expdest;
     5340    for (; dest > (char *)stackblock() && dest[-1] == '\n';)
     5341        STUNPUTC(dest);
     5342    expdest = dest;
     5343
     5344    if (quoted == 0)
     5345        recordregion(startloc, dest - (char *)stackblock(), 0);
     5346    TRACE(("evalbackq: size=%d: \"%.*s\"\n",
     5347        (dest - (char *)stackblock()) - startloc,
     5348        (dest - (char *)stackblock()) - startloc,
     5349        stackblock() + startloc));
     5350}
     5351
     5352#if ENABLE_ASH_MATH_SUPPORT
     5353/*
     5354 * Expand arithmetic expression.  Backup to start of expression,
     5355 * evaluate, place result in (backed up) result, adjust string position.
     5356 */
     5357static void
     5358expari(int quotes)
     5359{
     5360    char *p, *start;
     5361    int begoff;
     5362    int flag;
     5363    int len;
     5364
     5365    /*      ifsfree(); */
     5366
     5367    /*
     5368     * This routine is slightly over-complicated for
     5369     * efficiency.  Next we scan backwards looking for the
     5370     * start of arithmetic.
     5371     */
     5372    start = stackblock();
     5373    p = expdest - 1;
     5374    *p = '\0';
     5375    p--;
     5376    do {
     5377        int esc;
     5378
     5379        while (*p != CTLARI) {
     5380            p--;
     5381#if DEBUG
     5382            if (p < start) {
     5383                ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
     5384            }
     5385#endif
     5386        }
     5387
     5388        esc = esclen(start, p);
     5389        if (!(esc % 2)) {
     5390            break;
     5391        }
     5392
     5393        p -= esc + 1;
     5394    } while (1);
     5395
     5396    begoff = p - start;
     5397
     5398    removerecordregions(begoff);
     5399
     5400    flag = p[1];
     5401
     5402    expdest = p;
     5403
     5404    if (quotes)
     5405        rmescapes(p + 2);
     5406
     5407    len = cvtnum(dash_arith(p + 2));
     5408
     5409    if (flag != '"')
     5410        recordregion(begoff, begoff + len, 0);
     5411}
     5412#endif
     5413
     5414/* argstr needs it */
     5415static char *evalvar(char *p, int flag);
     5416
     5417/*
     5418 * Perform variable and command substitution.  If EXP_FULL is set, output CTLESC
     5419 * characters to allow for further processing.  Otherwise treat
     5420 * $@ like $* since no splitting will be performed.
     5421 */
     5422static void
     5423argstr(char *p, int flag)
     5424{
     5425    static const char spclchars[] ALIGN1 = {
     5426        '=',
     5427        ':',
     5428        CTLQUOTEMARK,
     5429        CTLENDVAR,
     5430        CTLESC,
     5431        CTLVAR,
     5432        CTLBACKQ,
     5433        CTLBACKQ | CTLQUOTE,
     5434#if ENABLE_ASH_MATH_SUPPORT
     5435        CTLENDARI,
     5436#endif
     5437        0
     5438    };
     5439    const char *reject = spclchars;
     5440    int c;
     5441    int quotes = flag & (EXP_FULL | EXP_CASE);      /* do CTLESC */
     5442    int breakall = flag & EXP_WORD;
     5443    int inquotes;
     5444    size_t length;
     5445    int startloc;
     5446
     5447    if (!(flag & EXP_VARTILDE)) {
     5448        reject += 2;
     5449    } else if (flag & EXP_VARTILDE2) {
     5450        reject++;
     5451    }
     5452    inquotes = 0;
     5453    length = 0;
     5454    if (flag & EXP_TILDE) {
     5455        char *q;
     5456
     5457        flag &= ~EXP_TILDE;
     5458 tilde:
     5459        q = p;
     5460        if (*q == CTLESC && (flag & EXP_QWORD))
     5461            q++;
     5462        if (*q == '~')
     5463            p = exptilde(p, q, flag);
     5464    }
     5465 start:
     5466    startloc = expdest - (char *)stackblock();
     5467    for (;;) {
     5468        length += strcspn(p + length, reject);
     5469        c = p[length];
     5470        if (c && (!(c & 0x80)
     5471#if ENABLE_ASH_MATH_SUPPORT
     5472                    || c == CTLENDARI
     5473#endif
     5474           )) {
     5475            /* c == '=' || c == ':' || c == CTLENDARI */
     5476            length++;
     5477        }
     5478        if (length > 0) {
     5479            int newloc;
     5480            expdest = stack_nputstr(p, length, expdest);
     5481            newloc = expdest - (char *)stackblock();
     5482            if (breakall && !inquotes && newloc > startloc) {
     5483                recordregion(startloc, newloc, 0);
     5484            }
     5485            startloc = newloc;
     5486        }
     5487        p += length + 1;
     5488        length = 0;
     5489
     5490        switch (c) {
     5491        case '\0':
     5492            goto breakloop;
     5493        case '=':
     5494            if (flag & EXP_VARTILDE2) {
     5495                p--;
     5496                continue;
     5497            }
     5498            flag |= EXP_VARTILDE2;
     5499            reject++;
     5500            /* fall through */
     5501        case ':':
     5502            /*
     5503             * sort of a hack - expand tildes in variable
     5504             * assignments (after the first '=' and after ':'s).
     5505             */
     5506            if (*--p == '~') {
     5507                goto tilde;
     5508            }
     5509            continue;
     5510        }
     5511
     5512        switch (c) {
     5513        case CTLENDVAR: /* ??? */
     5514            goto breakloop;
     5515        case CTLQUOTEMARK:
     5516            /* "$@" syntax adherence hack */
     5517            if (
     5518                !inquotes &&
     5519                !memcmp(p, dolatstr, 4) &&
     5520                (p[4] == CTLQUOTEMARK || (
     5521                    p[4] == CTLENDVAR &&
     5522                    p[5] == CTLQUOTEMARK
     5523                ))
     5524            ) {
     5525                p = evalvar(p + 1, flag) + 1;
     5526                goto start;
     5527            }
     5528            inquotes = !inquotes;
     5529 addquote:
     5530            if (quotes) {
     5531                p--;
     5532                length++;
     5533                startloc++;
     5534            }
     5535            break;
     5536        case CTLESC:
     5537            startloc++;
     5538            length++;
     5539            goto addquote;
     5540        case CTLVAR:
     5541            p = evalvar(p, flag);
     5542            goto start;
     5543        case CTLBACKQ:
     5544            c = 0;
     5545        case CTLBACKQ|CTLQUOTE:
     5546            expbackq(argbackq->n, c, quotes);
     5547            argbackq = argbackq->next;
     5548            goto start;
     5549#if ENABLE_ASH_MATH_SUPPORT
     5550        case CTLENDARI:
     5551            p--;
     5552            expari(quotes);
     5553            goto start;
     5554#endif
     5555        }
     5556    }
     5557 breakloop:
     5558    ;
     5559}
     5560
     5561static char *
     5562scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
     5563    int zero)
     5564{
     5565    char *loc;
     5566    char *loc2;
     5567    char c;
     5568
     5569    loc = startp;
     5570    loc2 = rmesc;
     5571    do {
     5572        int match;
     5573        const char *s = loc2;
     5574        c = *loc2;
     5575        if (zero) {
     5576            *loc2 = '\0';
     5577            s = rmesc;
     5578        }
     5579        match = pmatch(str, s);
     5580        *loc2 = c;
     5581        if (match)
     5582            return loc;
     5583        if (quotes && *loc == CTLESC)
     5584            loc++;
     5585        loc++;
     5586        loc2++;
     5587    } while (c);
     5588    return 0;
     5589}
     5590
     5591static char *
     5592scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
     5593    int zero)
     5594{
     5595    int esc = 0;
     5596    char *loc;
     5597    char *loc2;
     5598
     5599    for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
     5600        int match;
     5601        char c = *loc2;
     5602        const char *s = loc2;
     5603        if (zero) {
     5604            *loc2 = '\0';
     5605            s = rmesc;
     5606        }
     5607        match = pmatch(str, s);
     5608        *loc2 = c;
     5609        if (match)
     5610            return loc;
     5611        loc--;
     5612        if (quotes) {
     5613            if (--esc < 0) {
     5614                esc = esclen(startp, loc);
     5615            }
     5616            if (esc % 2) {
     5617                esc--;
     5618                loc--;
     5619            }
     5620        }
     5621    }
     5622    return 0;
     5623}
     5624
     5625static void varunset(const char *, const char *, const char *, int) ATTRIBUTE_NORETURN;
     5626static void
     5627varunset(const char *end, const char *var, const char *umsg, int varflags)
     5628{
     5629    const char *msg;
     5630    const char *tail;
     5631
     5632    tail = nullstr;
     5633    msg = "parameter not set";
     5634    if (umsg) {
     5635        if (*end == CTLENDVAR) {
     5636            if (varflags & VSNUL)
     5637                tail = " or null";
     5638        } else
     5639            msg = umsg;
     5640    }
     5641    ash_msg_and_raise_error("%.*s: %s%s", end - var - 1, var, msg, tail);
     5642}
     5643
     5644static const char *
     5645subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
     5646{
     5647    char *startp;
     5648    char *loc;
     5649    int saveherefd = herefd;
     5650    struct nodelist *saveargbackq = argbackq;
     5651    int amount;
     5652    char *rmesc, *rmescend;
     5653    int zero;
     5654    char *(*scan)(char *, char *, char *, char *, int , int);
     5655
     5656    herefd = -1;
     5657    argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
     5658    STPUTC('\0', expdest);
     5659    herefd = saveherefd;
     5660    argbackq = saveargbackq;
     5661    startp = stackblock() + startloc;
     5662
     5663    switch (subtype) {
     5664    case VSASSIGN:
     5665        setvar(str, startp, 0);
     5666        amount = startp - expdest;
     5667        STADJUST(amount, expdest);
     5668        return startp;
     5669
     5670    case VSQUESTION:
     5671        varunset(p, str, startp, varflags);
     5672        /* NOTREACHED */
     5673    }
     5674
     5675    subtype -= VSTRIMRIGHT;
     5676#if DEBUG
     5677    if (subtype < 0 || subtype > 3)
     5678        abort();
     5679#endif
     5680
     5681    rmesc = startp;
     5682    rmescend = stackblock() + strloc;
     5683    if (quotes) {
     5684        rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
     5685        if (rmesc != startp) {
     5686            rmescend = expdest;
     5687            startp = stackblock() + startloc;
     5688        }
     5689    }
     5690    rmescend--;
     5691    str = stackblock() + strloc;
     5692    preglob(str, varflags & VSQUOTE, 0);
     5693
     5694    /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
     5695    zero = subtype >> 1;
     5696    /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
     5697    scan = (subtype & 1) ^ zero ? scanleft : scanright;
     5698
     5699    loc = scan(startp, rmesc, rmescend, str, quotes, zero);
     5700    if (loc) {
     5701        if (zero) {
     5702            memmove(startp, loc, str - loc);
     5703            loc = startp + (str - loc) - 1;
     5704        }
     5705        *loc = '\0';
     5706        amount = loc - expdest;
     5707        STADJUST(amount, expdest);
     5708    }
     5709    return loc;
     5710}
     5711
     5712/*
     5713 * Add the value of a specialized variable to the stack string.
     5714 */
     5715static ssize_t
     5716varvalue(char *name, int varflags, int flags)
     5717{
     5718    int num;
     5719    char *p;
     5720    int i;
     5721    int sep = 0;
     5722    int sepq = 0;
     5723    ssize_t len = 0;
     5724    char **ap;
     5725    int syntax;
     5726    int quoted = varflags & VSQUOTE;
     5727    int subtype = varflags & VSTYPE;
     5728    int quotes = flags & (EXP_FULL | EXP_CASE);
     5729
     5730    if (quoted && (flags & EXP_FULL))
     5731        sep = 1 << CHAR_BIT;
     5732
     5733    syntax = quoted ? DQSYNTAX : BASESYNTAX;
     5734    switch (*name) {
     5735    case '$':
     5736        num = rootpid;
     5737        goto numvar;
     5738    case '?':
     5739        num = exitstatus;
     5740        goto numvar;
     5741    case '#':
     5742        num = shellparam.nparam;
     5743        goto numvar;
     5744    case '!':
     5745        num = backgndpid;
     5746        if (num == 0)
     5747            return -1;
     5748 numvar:
     5749        len = cvtnum(num);
     5750        break;
     5751    case '-':
     5752        p = makestrspace(NOPTS, expdest);
     5753        for (i = NOPTS - 1; i >= 0; i--) {
     5754            if (optlist[i]) {
     5755                USTPUTC(optletters(i), p);
     5756                len++;
     5757            }
     5758        }
     5759        expdest = p;
     5760        break;
     5761    case '@':
     5762        if (sep)
     5763            goto param;
     5764        /* fall through */
     5765    case '*':
     5766        sep = ifsset() ? signed_char2int(ifsval()[0]) : ' ';
     5767        if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))
     5768            sepq = 1;
     5769 param:
     5770        ap = shellparam.p;
     5771        if (!ap)
     5772            return -1;
     5773        while ((p = *ap++)) {
     5774            size_t partlen;
     5775
     5776            partlen = strlen(p);
     5777            len += partlen;
     5778
     5779            if (!(subtype == VSPLUS || subtype == VSLENGTH))
     5780                memtodest(p, partlen, syntax, quotes);
     5781
     5782            if (*ap && sep) {
     5783                char *q;
     5784
     5785                len++;
     5786                if (subtype == VSPLUS || subtype == VSLENGTH) {
     5787                    continue;
     5788                }
     5789                q = expdest;
     5790                if (sepq)
     5791                    STPUTC(CTLESC, q);
     5792                STPUTC(sep, q);
     5793                expdest = q;
     5794            }
     5795        }
     5796        return len;
     5797    case '0':
     5798    case '1':
     5799    case '2':
     5800    case '3':
     5801    case '4':
     5802    case '5':
     5803    case '6':
     5804    case '7':
     5805    case '8':
     5806    case '9':
     5807        num = atoi(name);
     5808        if (num < 0 || num > shellparam.nparam)
     5809            return -1;
     5810        p = num ? shellparam.p[num - 1] : arg0;
     5811        goto value;
     5812    default:
     5813        p = lookupvar(name);
     5814 value:
     5815        if (!p)
     5816            return -1;
     5817
     5818        len = strlen(p);
     5819        if (!(subtype == VSPLUS || subtype == VSLENGTH))
     5820            memtodest(p, len, syntax, quotes);
     5821        return len;
     5822    }
     5823
     5824    if (subtype == VSPLUS || subtype == VSLENGTH)
     5825        STADJUST(-len, expdest);
     5826    return len;
     5827}
     5828
     5829/*
     5830 * Expand a variable, and return a pointer to the next character in the
     5831 * input string.
     5832 */
     5833static char *
     5834evalvar(char *p, int flag)
     5835{
     5836    int subtype;
     5837    int varflags;
     5838    char *var;
     5839    int patloc;
     5840    int c;
     5841    int startloc;
     5842    ssize_t varlen;
     5843    int easy;
     5844    int quotes;
     5845    int quoted;
     5846
     5847    quotes = flag & (EXP_FULL | EXP_CASE);
     5848    varflags = *p++;
     5849    subtype = varflags & VSTYPE;
     5850    quoted = varflags & VSQUOTE;
     5851    var = p;
     5852    easy = (!quoted || (*var == '@' && shellparam.nparam));
     5853    startloc = expdest - (char *)stackblock();
     5854    p = strchr(p, '=') + 1;
     5855
     5856 again:
     5857    varlen = varvalue(var, varflags, flag);
     5858    if (varflags & VSNUL)
     5859        varlen--;
     5860
     5861    if (subtype == VSPLUS) {
     5862        varlen = -1 - varlen;
     5863        goto vsplus;
     5864    }
     5865
     5866    if (subtype == VSMINUS) {
     5867 vsplus:
     5868        if (varlen < 0) {
     5869            argstr(
     5870                p, flag | EXP_TILDE |
     5871                    (quoted ?  EXP_QWORD : EXP_WORD)
     5872            );
     5873            goto end;
     5874        }
     5875        if (easy)
     5876            goto record;
     5877        goto end;
     5878    }
     5879
     5880    if (subtype == VSASSIGN || subtype == VSQUESTION) {
     5881        if (varlen < 0) {
     5882            if (subevalvar(p, var, 0, subtype, startloc, varflags, 0)) {
     5883                varflags &= ~VSNUL;
     5884                /*
     5885                 * Remove any recorded regions beyond
     5886                 * start of variable
     5887                 */
     5888                removerecordregions(startloc);
     5889                goto again;
     5890            }
     5891            goto end;
     5892        }
     5893        if (easy)
     5894            goto record;
     5895        goto end;
     5896    }
     5897
     5898    if (varlen < 0 && uflag)
     5899        varunset(p, var, 0, 0);
     5900
     5901    if (subtype == VSLENGTH) {
     5902        cvtnum(varlen > 0 ? varlen : 0);
     5903        goto record;
     5904    }
     5905
     5906    if (subtype == VSNORMAL) {
     5907        if (!easy)
     5908            goto end;
     5909 record:
     5910        recordregion(startloc, expdest - (char *)stackblock(), quoted);
     5911        goto end;
     5912    }
     5913
     5914#if DEBUG
     5915    switch (subtype) {
     5916    case VSTRIMLEFT:
     5917    case VSTRIMLEFTMAX:
     5918    case VSTRIMRIGHT:
     5919    case VSTRIMRIGHTMAX:
     5920        break;
     5921    default:
     5922        abort();
     5923    }
     5924#endif
     5925
     5926    if (varlen >= 0) {
     5927        /*
     5928         * Terminate the string and start recording the pattern
     5929         * right after it
     5930         */
     5931        STPUTC('\0', expdest);
     5932        patloc = expdest - (char *)stackblock();
     5933        if (subevalvar(p, NULL, patloc, subtype,
     5934                startloc, varflags, quotes) == 0) {
     5935            int amount = expdest - (
     5936                (char *)stackblock() + patloc - 1
     5937            );
     5938            STADJUST(-amount, expdest);
     5939        }
     5940        /* Remove any recorded regions beyond start of variable */
     5941        removerecordregions(startloc);
     5942        goto record;
     5943    }
     5944
     5945 end:
     5946    if (subtype != VSNORMAL) {      /* skip to end of alternative */
     5947        int nesting = 1;
     5948        for (;;) {
     5949            c = *p++;
     5950            if (c == CTLESC)
     5951                p++;
     5952            else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
     5953                if (varlen >= 0)
     5954                    argbackq = argbackq->next;
     5955            } else if (c == CTLVAR) {
     5956                if ((*p++ & VSTYPE) != VSNORMAL)
     5957                    nesting++;
     5958            } else if (c == CTLENDVAR) {
     5959                if (--nesting == 0)
     5960                    break;
     5961            }
     5962        }
     5963    }
     5964    return p;
     5965}
     5966
     5967/*
     5968 * Break the argument string into pieces based upon IFS and add the
     5969 * strings to the argument list.  The regions of the string to be
     5970 * searched for IFS characters have been stored by recordregion.
     5971 */
     5972static void
     5973ifsbreakup(char *string, struct arglist *arglist)
     5974{
     5975    struct ifsregion *ifsp;
     5976    struct strlist *sp;
     5977    char *start;
     5978    char *p;
     5979    char *q;
     5980    const char *ifs, *realifs;
     5981    int ifsspc;
     5982    int nulonly;
     5983
     5984    start = string;
     5985    if (ifslastp != NULL) {
     5986        ifsspc = 0;
     5987        nulonly = 0;
     5988        realifs = ifsset() ? ifsval() : defifs;
     5989        ifsp = &ifsfirst;
     5990        do {
     5991            p = string + ifsp->begoff;
     5992            nulonly = ifsp->nulonly;
     5993            ifs = nulonly ? nullstr : realifs;
     5994            ifsspc = 0;
     5995            while (p < string + ifsp->endoff) {
     5996                q = p;
     5997                if (*p == CTLESC)
     5998                    p++;
     5999                if (!strchr(ifs, *p)) {
     6000                    p++;
     6001                    continue;
     6002                }
     6003                if (!nulonly)
     6004                    ifsspc = (strchr(defifs, *p) != NULL);
     6005                /* Ignore IFS whitespace at start */
     6006                if (q == start && ifsspc) {
     6007                    p++;
     6008                    start = p;
     6009                    continue;
     6010                }
     6011                *q = '\0';
     6012                sp = stalloc(sizeof(*sp));
     6013                sp->text = start;
     6014                *arglist->lastp = sp;
     6015                arglist->lastp = &sp->next;
     6016                p++;
     6017                if (!nulonly) {
     6018                    for (;;) {
     6019                        if (p >= string + ifsp->endoff) {
     6020                            break;
     6021                        }
     6022                        q = p;
     6023                        if (*p == CTLESC)
     6024                            p++;
     6025                        if (strchr(ifs, *p) == NULL ) {
     6026                            p = q;
     6027                            break;
     6028                        } else if (strchr(defifs, *p) == NULL) {
     6029                            if (ifsspc) {
     6030                                p++;
     6031                                ifsspc = 0;
     6032                            } else {
     6033                                p = q;
     6034                                break;
     6035                            }
     6036                        } else
     6037                            p++;
     6038                    }
     6039                }
     6040                start = p;
     6041            } /* while */
     6042            ifsp = ifsp->next;
     6043        } while (ifsp != NULL);
     6044        if (nulonly)
     6045            goto add;
     6046    }
     6047
     6048    if (!*start)
     6049        return;
     6050
     6051 add:
     6052    sp = stalloc(sizeof(*sp));
     6053    sp->text = start;
     6054    *arglist->lastp = sp;
     6055    arglist->lastp = &sp->next;
     6056}
     6057
     6058static void
     6059ifsfree(void)
     6060{
     6061    struct ifsregion *p;
     6062
     6063    INT_OFF;
     6064    p = ifsfirst.next;
     6065    do {
     6066        struct ifsregion *ifsp;
     6067        ifsp = p->next;
     6068        free(p);
     6069        p = ifsp;
     6070    } while (p);
     6071    ifslastp = NULL;
     6072    ifsfirst.next = NULL;
     6073    INT_ON;
     6074}
     6075
     6076/*
     6077 * Add a file name to the list.
     6078 */
     6079static void
     6080addfname(const char *name)
     6081{
     6082    struct strlist *sp;
     6083
     6084    sp = stalloc(sizeof(*sp));
     6085    sp->text = ststrdup(name);
     6086    *exparg.lastp = sp;
     6087    exparg.lastp = &sp->next;
     6088}
     6089
     6090static char *expdir;
     6091
     6092/*
     6093 * Do metacharacter (i.e. *, ?, [...]) expansion.
     6094 */
     6095static void
     6096expmeta(char *enddir, char *name)
     6097{
     6098    char *p;
     6099    const char *cp;
     6100    char *start;
     6101    char *endname;
     6102    int metaflag;
     6103    struct stat statb;
     6104    DIR *dirp;
     6105    struct dirent *dp;
     6106    int atend;
     6107    int matchdot;
     6108
     6109    metaflag = 0;
     6110    start = name;
     6111    for (p = name; *p; p++) {
     6112        if (*p == '*' || *p == '?')
     6113            metaflag = 1;
     6114        else if (*p == '[') {
     6115            char *q = p + 1;
     6116            if (*q == '!')
     6117                q++;
     6118            for (;;) {
     6119                if (*q == '\\')
     6120                    q++;
     6121                if (*q == '/' || *q == '\0')
     6122                    break;
     6123                if (*++q == ']') {
     6124                    metaflag = 1;
     6125                    break;
     6126                }
     6127            }
     6128        } else if (*p == '\\')
     6129            p++;
     6130        else if (*p == '/') {
     6131            if (metaflag)
     6132                goto out;
     6133            start = p + 1;
     6134        }
     6135    }
     6136 out:
     6137    if (metaflag == 0) {    /* we've reached the end of the file name */
     6138        if (enddir != expdir)
     6139            metaflag++;
     6140        p = name;
     6141        do {
     6142            if (*p == '\\')
     6143                p++;
     6144            *enddir++ = *p;
     6145        } while (*p++);
     6146        if (metaflag == 0 || lstat(expdir, &statb) >= 0)
     6147            addfname(expdir);
     6148        return;
     6149    }
     6150    endname = p;
     6151    if (name < start) {
     6152        p = name;
     6153        do {
     6154            if (*p == '\\')
     6155                p++;
     6156            *enddir++ = *p++;
     6157        } while (p < start);
     6158    }
     6159    if (enddir == expdir) {
     6160        cp = ".";
     6161    } else if (enddir == expdir + 1 && *expdir == '/') {
     6162        cp = "/";
     6163    } else {
     6164        cp = expdir;
     6165        enddir[-1] = '\0';
     6166    }
     6167    dirp = opendir(cp);
     6168    if (dirp == NULL)
     6169        return;
     6170    if (enddir != expdir)
     6171        enddir[-1] = '/';
     6172    if (*endname == 0) {
     6173        atend = 1;
     6174    } else {
     6175        atend = 0;
     6176        *endname++ = '\0';
     6177    }
     6178    matchdot = 0;
     6179    p = start;
     6180    if (*p == '\\')
     6181        p++;
     6182    if (*p == '.')
     6183        matchdot++;
     6184    while (! intpending && (dp = readdir(dirp)) != NULL) {
     6185        if (dp->d_name[0] == '.' && ! matchdot)
     6186            continue;
     6187        if (pmatch(start, dp->d_name)) {
     6188            if (atend) {
     6189                strcpy(enddir, dp->d_name);
     6190                addfname(expdir);
     6191            } else {
     6192                for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
     6193                    continue;
     6194                p[-1] = '/';
     6195                expmeta(p, endname);
     6196            }
     6197        }
     6198    }
     6199    closedir(dirp);
     6200    if (! atend)
     6201        endname[-1] = '/';
     6202}
     6203
     6204static struct strlist *
     6205msort(struct strlist *list, int len)
     6206{
     6207    struct strlist *p, *q = NULL;
     6208    struct strlist **lpp;
     6209    int half;
     6210    int n;
     6211
     6212    if (len <= 1)
     6213        return list;
     6214    half = len >> 1;
     6215    p = list;
     6216    for (n = half; --n >= 0; ) {
     6217        q = p;
     6218        p = p->next;
     6219    }
     6220    q->next = NULL;                 /* terminate first half of list */
     6221    q = msort(list, half);          /* sort first half of list */
     6222    p = msort(p, len - half);               /* sort second half */
     6223    lpp = &list;
     6224    for (;;) {
     6225#if ENABLE_LOCALE_SUPPORT
     6226        if (strcoll(p->text, q->text) < 0)
     6227#else
     6228        if (strcmp(p->text, q->text) < 0)
     6229#endif
     6230                        {
     6231            *lpp = p;
     6232            lpp = &p->next;
     6233            p = *lpp;
     6234            if (p == NULL) {
     6235                *lpp = q;
     6236                break;
     6237            }
     6238        } else {
     6239            *lpp = q;
     6240            lpp = &q->next;
     6241            q = *lpp;
     6242            if (q == NULL) {
     6243                *lpp = p;
     6244                break;
     6245            }
     6246        }
     6247    }
     6248    return list;
     6249}
     6250
     6251/*
     6252 * Sort the results of file name expansion.  It calculates the number of
     6253 * strings to sort and then calls msort (short for merge sort) to do the
     6254 * work.
     6255 */
     6256static struct strlist *
     6257expsort(struct strlist *str)
     6258{
     6259    int len;
     6260    struct strlist *sp;
     6261
     6262    len = 0;
     6263    for (sp = str; sp; sp = sp->next)
     6264        len++;
     6265    return msort(str, len);
     6266}
     6267
     6268static void
     6269expandmeta(struct strlist *str, int flag)
     6270{
     6271    static const char metachars[] ALIGN1 = {
     6272        '*', '?', '[', 0
     6273    };
     6274    /* TODO - EXP_REDIR */
     6275
     6276    while (str) {
     6277        struct strlist **savelastp;
     6278        struct strlist *sp;
     6279        char *p;
     6280
     6281        if (fflag)
     6282            goto nometa;
     6283        if (!strpbrk(str->text, metachars))
     6284            goto nometa;
     6285        savelastp = exparg.lastp;
     6286
     6287        INT_OFF;
     6288        p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
     6289        {
     6290            int i = strlen(str->text);
     6291            expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
     6292        }
     6293
     6294        expmeta(expdir, p);
     6295        free(expdir);
     6296        if (p != str->text)
     6297            free(p);
     6298        INT_ON;
     6299        if (exparg.lastp == savelastp) {
     6300            /*
     6301             * no matches
     6302             */
     6303 nometa:
     6304            *exparg.lastp = str;
     6305            rmescapes(str->text);
     6306            exparg.lastp = &str->next;
     6307        } else {
     6308            *exparg.lastp = NULL;
     6309            *savelastp = sp = expsort(*savelastp);
     6310            while (sp->next != NULL)
     6311                sp = sp->next;
     6312            exparg.lastp = &sp->next;
     6313        }
     6314        str = str->next;
     6315    }
     6316}
     6317
     6318/*
     6319 * Perform variable substitution and command substitution on an argument,
     6320 * placing the resulting list of arguments in arglist.  If EXP_FULL is true,
     6321 * perform splitting and file name expansion.  When arglist is NULL, perform
     6322 * here document expansion.
     6323 */
     6324static void
     6325expandarg(union node *arg, struct arglist *arglist, int flag)
     6326{
     6327    struct strlist *sp;
     6328    char *p;
     6329
     6330    argbackq = arg->narg.backquote;
     6331    STARTSTACKSTR(expdest);
     6332    ifsfirst.next = NULL;
     6333    ifslastp = NULL;
     6334    argstr(arg->narg.text, flag);
     6335    p = _STPUTC('\0', expdest);
     6336    expdest = p - 1;
     6337    if (arglist == NULL) {
     6338        return;                 /* here document expanded */
     6339    }
     6340    p = grabstackstr(p);
     6341    exparg.lastp = &exparg.list;
     6342    /*
     6343     * TODO - EXP_REDIR
     6344     */
     6345    if (flag & EXP_FULL) {
     6346        ifsbreakup(p, &exparg);
     6347        *exparg.lastp = NULL;
     6348        exparg.lastp = &exparg.list;
     6349        expandmeta(exparg.list, flag);
     6350    } else {
     6351        if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
     6352            rmescapes(p);
     6353        sp = stalloc(sizeof(*sp));
     6354        sp->text = p;
     6355        *exparg.lastp = sp;
     6356        exparg.lastp = &sp->next;
     6357    }
     6358    if (ifsfirst.next)
     6359        ifsfree();
     6360    *exparg.lastp = NULL;
     6361    if (exparg.list) {
     6362        *arglist->lastp = exparg.list;
     6363        arglist->lastp = exparg.lastp;
     6364    }
     6365}
     6366
     6367/*
     6368 * Expand shell variables and backquotes inside a here document.
     6369 */
     6370static void
     6371expandhere(union node *arg, int fd)
     6372{
     6373    herefd = fd;
     6374    expandarg(arg, (struct arglist *)NULL, 0);
     6375    full_write(fd, stackblock(), expdest - (char *)stackblock());
     6376}
     6377
     6378/*
     6379 * Returns true if the pattern matches the string.
     6380 */
     6381static int
     6382patmatch(char *pattern, const char *string)
     6383{
     6384    return pmatch(preglob(pattern, 0, 0), string);
     6385}
     6386
     6387/*
     6388 * See if a pattern matches in a case statement.
     6389 */
     6390static int
     6391casematch(union node *pattern, char *val)
     6392{
     6393    struct stackmark smark;
     6394    int result;
     6395
     6396    setstackmark(&smark);
     6397    argbackq = pattern->narg.backquote;
     6398    STARTSTACKSTR(expdest);
     6399    ifslastp = NULL;
     6400    argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
     6401    STACKSTRNUL(expdest);
     6402    result = patmatch(stackblock(), val);
     6403    popstackmark(&smark);
     6404    return result;
     6405}
     6406
     6407
     6408/* ============ find_command */
     6409
     6410struct builtincmd {
     6411    const char *name;
     6412    int (*builtin)(int, char **);
     6413    /* unsigned flags; */
     6414};
     6415#define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
     6416#define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
     6417#define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
     6418
     6419struct cmdentry {
     6420    int cmdtype;
     6421    union param {
     6422        int index;
     6423        const struct builtincmd *cmd;
     6424        struct funcnode *func;
     6425    } u;
     6426};
     6427/* values of cmdtype */
     6428#define CMDUNKNOWN      -1      /* no entry in table for command */
     6429#define CMDNORMAL       0       /* command is an executable program */
     6430#define CMDFUNCTION     1       /* command is a shell function */
     6431#define CMDBUILTIN      2       /* command is a shell builtin */
     6432
     6433/* action to find_command() */
     6434#define DO_ERR          0x01    /* prints errors */
     6435#define DO_ABS          0x02    /* checks absolute paths */
     6436#define DO_NOFUNC       0x04    /* don't return shell functions, for command */
     6437#define DO_ALTPATH      0x08    /* using alternate path */
     6438#define DO_ALTBLTIN     0x20    /* %builtin in alt. path */
     6439
     6440static void find_command(char *, struct cmdentry *, int, const char *);
     6441
     6442
     6443/* ============ Hashing commands */
     6444
     6445/*
     6446 * When commands are first encountered, they are entered in a hash table.
     6447 * This ensures that a full path search will not have to be done for them
     6448 * on each invocation.
     6449 *
     6450 * We should investigate converting to a linear search, even though that
     6451 * would make the command name "hash" a misnomer.
     6452 */
     6453
     6454#define CMDTABLESIZE 31         /* should be prime */
     6455#define ARB 1                   /* actual size determined at run time */
     6456
     6457struct tblentry {
     6458    struct tblentry *next;  /* next entry in hash chain */
     6459    union param param;      /* definition of builtin function */
     6460    short cmdtype;          /* index identifying command */
     6461    char rehash;            /* if set, cd done since entry created */
     6462    char cmdname[ARB];      /* name of command */
     6463};
     6464
     6465static struct tblentry *cmdtable[CMDTABLESIZE];
     6466static int builtinloc = -1;             /* index in path of %builtin, or -1 */
     6467
     6468static void
     6469tryexec(char *cmd, char **argv, char **envp)
     6470{
     6471    int repeated = 0;
     6472
     6473#if ENABLE_FEATURE_SH_STANDALONE
     6474    if (strchr(cmd, '/') == NULL) {
     6475        const struct bb_applet *a;
     6476
     6477        a = find_applet_by_name(cmd);
     6478        if (a) {
     6479            if (a->noexec) {
     6480                current_applet = a;
     6481                run_current_applet_and_exit(argv);
     6482            }
     6483            /* re-exec ourselves with the new arguments */
     6484            execve(bb_busybox_exec_path, argv, envp);
     6485            /* If they called chroot or otherwise made the binary no longer
     6486             * executable, fall through */
     6487        }
     6488    }
     6489#endif
     6490
     6491 repeat:
     6492#ifdef SYSV
     6493    do {
     6494        execve(cmd, argv, envp);
     6495    } while (errno == EINTR);
     6496#else
     6497    execve(cmd, argv, envp);
     6498#endif
     6499    if (repeated++) {
     6500        free(argv);
     6501    } else if (errno == ENOEXEC) {
     6502        char **ap;
     6503        char **new;
     6504
     6505        for (ap = argv; *ap; ap++)
     6506            ;
     6507        ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
     6508        ap[1] = cmd;
     6509        ap[0] = cmd = (char *)DEFAULT_SHELL;
     6510        ap += 2;
     6511        argv++;
     6512        while ((*ap++ = *argv++))
     6513            ;
     6514        argv = new;
     6515        goto repeat;
     6516    }
     6517}
     6518
     6519/*
     6520 * Exec a program.  Never returns.  If you change this routine, you may
     6521 * have to change the find_command routine as well.
     6522 */
     6523#define environment() listvars(VEXPORT, VUNSET, 0)
     6524static void shellexec(char **, const char *, int) ATTRIBUTE_NORETURN;
     6525static void
     6526shellexec(char **argv, const char *path, int idx)
     6527{
     6528    char *cmdname;
     6529    int e;
     6530    char **envp;
     6531    int exerrno;
     6532
     6533    clearredir(1);
     6534    envp = environment();
     6535    if (strchr(argv[0], '/')
     6536#if ENABLE_FEATURE_SH_STANDALONE
     6537     || find_applet_by_name(argv[0])
     6538#endif
     6539    ) {
     6540        tryexec(argv[0], argv, envp);
     6541        e = errno;
     6542    } else {
     6543        e = ENOENT;
     6544        while ((cmdname = padvance(&path, argv[0])) != NULL) {
     6545            if (--idx < 0 && pathopt == NULL) {
     6546                tryexec(cmdname, argv, envp);
     6547                if (errno != ENOENT && errno != ENOTDIR)
     6548                    e = errno;
     6549            }
     6550            stunalloc(cmdname);
     6551        }
     6552    }
     6553
     6554    /* Map to POSIX errors */
     6555    switch (e) {
     6556    case EACCES:
     6557        exerrno = 126;
     6558        break;
     6559    case ENOENT:
     6560        exerrno = 127;
     6561        break;
     6562    default:
     6563        exerrno = 2;
     6564        break;
     6565    }
     6566    exitstatus = exerrno;
     6567    TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
     6568        argv[0], e, suppressint ));
     6569    ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found"));
     6570    /* NOTREACHED */
     6571}
     6572
     6573static void
     6574printentry(struct tblentry *cmdp)
     6575{
     6576    int idx;
     6577    const char *path;
     6578    char *name;
     6579
     6580    idx = cmdp->param.index;
     6581    path = pathval();
     6582    do {
     6583        name = padvance(&path, cmdp->cmdname);
     6584        stunalloc(name);
     6585    } while (--idx >= 0);
     6586    out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
     6587}
     6588
     6589/*
     6590 * Clear out command entries.  The argument specifies the first entry in
     6591 * PATH which has changed.
     6592 */
     6593static void
     6594clearcmdentry(int firstchange)
     6595{
     6596    struct tblentry **tblp;
     6597    struct tblentry **pp;
     6598    struct tblentry *cmdp;
     6599
     6600    INT_OFF;
     6601    for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
     6602        pp = tblp;
     6603        while ((cmdp = *pp) != NULL) {
     6604            if ((cmdp->cmdtype == CMDNORMAL &&
     6605                 cmdp->param.index >= firstchange)
     6606             || (cmdp->cmdtype == CMDBUILTIN &&
     6607                 builtinloc >= firstchange)
     6608            ) {
     6609                *pp = cmdp->next;
     6610                free(cmdp);
     6611            } else {
     6612                pp = &cmdp->next;
     6613            }
     6614        }
     6615    }
     6616    INT_ON;
     6617}
     6618
     6619/*
     6620 * Locate a command in the command hash table.  If "add" is nonzero,
     6621 * add the command to the table if it is not already present.  The
     6622 * variable "lastcmdentry" is set to point to the address of the link
     6623 * pointing to the entry, so that delete_cmd_entry can delete the
     6624 * entry.
     6625 *
     6626 * Interrupts must be off if called with add != 0.
     6627 */
     6628static struct tblentry **lastcmdentry;
     6629
     6630static struct tblentry *
     6631cmdlookup(const char *name, int add)
     6632{
     6633    unsigned int hashval;
     6634    const char *p;
     6635    struct tblentry *cmdp;
     6636    struct tblentry **pp;
     6637
     6638    p = name;
     6639    hashval = (unsigned char)*p << 4;
     6640    while (*p)
     6641        hashval += (unsigned char)*p++;
     6642    hashval &= 0x7FFF;
     6643    pp = &cmdtable[hashval % CMDTABLESIZE];
     6644    for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
     6645        if (strcmp(cmdp->cmdname, name) == 0)
     6646            break;
     6647        pp = &cmdp->next;
     6648    }
     6649    if (add && cmdp == NULL) {
     6650        cmdp = *pp = ckmalloc(sizeof(struct tblentry) - ARB
     6651                    + strlen(name) + 1);
     6652        cmdp->next = NULL;
     6653        cmdp->cmdtype = CMDUNKNOWN;
     6654        strcpy(cmdp->cmdname, name);
     6655    }
     6656    lastcmdentry = pp;
     6657    return cmdp;
     6658}
     6659
     6660/*
     6661 * Delete the command entry returned on the last lookup.
     6662 */
     6663static void
     6664delete_cmd_entry(void)
     6665{
     6666    struct tblentry *cmdp;
     6667
     6668    INT_OFF;
     6669    cmdp = *lastcmdentry;
     6670    *lastcmdentry = cmdp->next;
     6671    if (cmdp->cmdtype == CMDFUNCTION)
     6672        freefunc(cmdp->param.func);
     6673    free(cmdp);
     6674    INT_ON;
     6675}
     6676
     6677/*
     6678 * Add a new command entry, replacing any existing command entry for
     6679 * the same name - except special builtins.
     6680 */
     6681static void
     6682addcmdentry(char *name, struct cmdentry *entry)
     6683{
     6684    struct tblentry *cmdp;
     6685
     6686    cmdp = cmdlookup(name, 1);
     6687    if (cmdp->cmdtype == CMDFUNCTION) {
     6688        freefunc(cmdp->param.func);
     6689    }
     6690    cmdp->cmdtype = entry->cmdtype;
     6691    cmdp->param = entry->u;
     6692    cmdp->rehash = 0;
     6693}
     6694
     6695static int
     6696hashcmd(int argc, char **argv)
     6697{
     6698    struct tblentry **pp;
     6699    struct tblentry *cmdp;
     6700    int c;
     6701    struct cmdentry entry;
     6702    char *name;
     6703
     6704    while ((c = nextopt("r")) != '\0') {
     6705        clearcmdentry(0);
     6706        return 0;
     6707    }
     6708    if (*argptr == NULL) {
     6709        for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
     6710            for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
     6711                if (cmdp->cmdtype == CMDNORMAL)
     6712                    printentry(cmdp);
     6713            }
     6714        }
     6715        return 0;
     6716    }
     6717    c = 0;
     6718    while ((name = *argptr) != NULL) {
     6719        cmdp = cmdlookup(name, 0);
     6720        if (cmdp != NULL
     6721         && (cmdp->cmdtype == CMDNORMAL
     6722             || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
     6723            delete_cmd_entry();
     6724        find_command(name, &entry, DO_ERR, pathval());
     6725        if (entry.cmdtype == CMDUNKNOWN)
     6726            c = 1;
     6727        argptr++;
     6728    }
     6729    return c;
     6730}
     6731
     6732/*
     6733 * Called when a cd is done.  Marks all commands so the next time they
     6734 * are executed they will be rehashed.
     6735 */
     6736static void
     6737hashcd(void)
     6738{
     6739    struct tblentry **pp;
     6740    struct tblentry *cmdp;
     6741
     6742    for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
     6743        for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
     6744            if (cmdp->cmdtype == CMDNORMAL || (
     6745                cmdp->cmdtype == CMDBUILTIN &&
     6746                !(IS_BUILTIN_REGULAR(cmdp->param.cmd)) &&
     6747                builtinloc > 0
     6748            ))
     6749                cmdp->rehash = 1;
     6750        }
     6751    }
     6752}
     6753
     6754/*
     6755 * Fix command hash table when PATH changed.
     6756 * Called before PATH is changed.  The argument is the new value of PATH;
     6757 * pathval() still returns the old value at this point.
     6758 * Called with interrupts off.
     6759 */
     6760static void
     6761changepath(const char *newval)
     6762{
     6763    const char *old, *new;
     6764    int idx;
     6765    int firstchange;
     6766    int idx_bltin;
     6767
     6768    old = pathval();
     6769    new = newval;
     6770    firstchange = 9999;     /* assume no change */
     6771    idx = 0;
     6772    idx_bltin = -1;
     6773    for (;;) {
     6774        if (*old != *new) {
     6775            firstchange = idx;
     6776            if ((*old == '\0' && *new == ':')
     6777             || (*old == ':' && *new == '\0'))
     6778                firstchange++;
     6779            old = new;      /* ignore subsequent differences */
     6780        }
     6781        if (*new == '\0')
     6782            break;
     6783        if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
     6784            idx_bltin = idx;
     6785        if (*new == ':') {
     6786            idx++;
     6787        }
     6788        new++, old++;
     6789    }
     6790    if (builtinloc < 0 && idx_bltin >= 0)
     6791        builtinloc = idx_bltin;             /* zap builtins */
     6792    if (builtinloc >= 0 && idx_bltin < 0)
     6793        firstchange = 0;
     6794    clearcmdentry(firstchange);
     6795    builtinloc = idx_bltin;
     6796}
     6797
     6798#define TEOF 0
     6799#define TNL 1
     6800#define TREDIR 2
     6801#define TWORD 3
     6802#define TSEMI 4
     6803#define TBACKGND 5
     6804#define TAND 6
     6805#define TOR 7
     6806#define TPIPE 8
     6807#define TLP 9
     6808#define TRP 10
     6809#define TENDCASE 11
     6810#define TENDBQUOTE 12
     6811#define TNOT 13
     6812#define TCASE 14
     6813#define TDO 15
     6814#define TDONE 16
     6815#define TELIF 17
     6816#define TELSE 18
     6817#define TESAC 19
     6818#define TFI 20
     6819#define TFOR 21
     6820#define TIF 22
     6821#define TIN 23
     6822#define TTHEN 24
     6823#define TUNTIL 25
     6824#define TWHILE 26
     6825#define TBEGIN 27
     6826#define TEND 28
     6827
     6828/* first char is indicating which tokens mark the end of a list */
     6829static const char *const tokname_array[] = {
     6830    "\1end of file",
     6831    "\0newline",
     6832    "\0redirection",
     6833    "\0word",
     6834    "\0;",
     6835    "\0&",
     6836    "\0&&",
     6837    "\0||",
     6838    "\0|",
     6839    "\0(",
     6840    "\1)",
     6841    "\1;;",
     6842    "\1`",
     6843#define KWDOFFSET 13
     6844    /* the following are keywords */
     6845    "\0!",
     6846    "\0case",
     6847    "\1do",
     6848    "\1done",
     6849    "\1elif",
     6850    "\1else",
     6851    "\1esac",
     6852    "\1fi",
     6853    "\0for",
     6854    "\0if",
     6855    "\0in",
     6856    "\1then",
     6857    "\0until",
     6858    "\0while",
     6859    "\0{",
     6860    "\1}",
     6861};
     6862
     6863static const char *
     6864tokname(int tok)
     6865{
     6866    static char buf[16];
     6867
     6868//try this:
     6869//if (tok < TSEMI) return tokname_array[tok] + 1;
     6870//sprintf(buf, "\"%s\"", tokname_array[tok] + 1);
     6871//return buf;
     6872
     6873    if (tok >= TSEMI)
     6874        buf[0] = '"';
     6875    sprintf(buf + (tok >= TSEMI), "%s%c",
     6876            tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0));
     6877    return buf;
     6878}
     6879
     6880/* Wrapper around strcmp for qsort/bsearch/... */
     6881static int
     6882pstrcmp(const void *a, const void *b)
     6883{
     6884    return strcmp((char*) a, (*(char**) b) + 1);
     6885}
     6886
     6887static const char *const *
     6888findkwd(const char *s)
     6889{
     6890    return bsearch(s, tokname_array + KWDOFFSET,
     6891            ARRAY_SIZE(tokname_array) - KWDOFFSET,
     6892            sizeof(tokname_array[0]), pstrcmp);
     6893}
     6894
     6895/*
     6896 * Locate and print what a word is...
     6897 */
     6898static int
     6899describe_command(char *command, int describe_command_verbose)
     6900{
     6901    struct cmdentry entry;
     6902    struct tblentry *cmdp;
     6903#if ENABLE_ASH_ALIAS
     6904    const struct alias *ap;
     6905#endif
     6906    const char *path = pathval();
     6907
     6908    if (describe_command_verbose) {
     6909        out1str(command);
     6910    }
     6911
     6912    /* First look at the keywords */
     6913    if (findkwd(command)) {
     6914        out1str(describe_command_verbose ? " is a shell keyword" : command);
     6915        goto out;
     6916    }
     6917
     6918#if ENABLE_ASH_ALIAS
     6919    /* Then look at the aliases */
     6920    ap = lookupalias(command, 0);
     6921    if (ap != NULL) {
     6922        if (!describe_command_verbose) {
     6923            out1str("alias ");
     6924            printalias(ap);
     6925            return 0;
     6926        }
     6927        out1fmt(" is an alias for %s", ap->val);
     6928        goto out;
     6929    }
     6930#endif
     6931    /* Then check if it is a tracked alias */
     6932    cmdp = cmdlookup(command, 0);
     6933    if (cmdp != NULL) {
     6934        entry.cmdtype = cmdp->cmdtype;
     6935        entry.u = cmdp->param;
     6936    } else {
     6937        /* Finally use brute force */
     6938        find_command(command, &entry, DO_ABS, path);
     6939    }
     6940
     6941    switch (entry.cmdtype) {
     6942    case CMDNORMAL: {
     6943        int j = entry.u.index;
     6944        char *p;
     6945        if (j == -1) {
     6946            p = command;
     6947        } else {
     6948            do {
     6949                p = padvance(&path, command);
     6950                stunalloc(p);
     6951            } while (--j >= 0);
     6952        }
     6953        if (describe_command_verbose) {
     6954            out1fmt(" is%s %s",
     6955                (cmdp ? " a tracked alias for" : nullstr), p
     6956            );
     6957        } else {
     6958            out1str(p);
     6959        }
     6960        break;
     6961    }
     6962
     6963    case CMDFUNCTION:
     6964        if (describe_command_verbose) {
     6965            out1str(" is a shell function");
     6966        } else {
     6967            out1str(command);
     6968        }
     6969        break;
     6970
     6971    case CMDBUILTIN:
     6972        if (describe_command_verbose) {
     6973            out1fmt(" is a %sshell builtin",
     6974                IS_BUILTIN_SPECIAL(entry.u.cmd) ?
     6975                    "special " : nullstr
     6976            );
     6977        } else {
     6978            out1str(command);
     6979        }
     6980        break;
     6981
     6982    default:
     6983        if (describe_command_verbose) {
     6984            out1str(": not found\n");
     6985        }
     6986        return 127;
     6987    }
     6988 out:
     6989    outstr("\n", stdout);
     6990    return 0;
     6991}
     6992
     6993static int
     6994typecmd(int argc, char **argv)
     6995{
     6996    int i = 1;
     6997    int err = 0;
     6998    int verbose = 1;
     6999
     7000    /* type -p ... ? (we don't bother checking for 'p') */
     7001    if (argv[1] && argv[1][0] == '-') {
     7002        i++;
     7003        verbose = 0;
     7004    }
     7005    while (i < argc) {
     7006        err |= describe_command(argv[i++], verbose);
     7007    }
     7008    return err;
     7009}
     7010
     7011#if ENABLE_ASH_CMDCMD
     7012static int
     7013commandcmd(int argc, char **argv)
     7014{
     7015    int c;
     7016    enum {
     7017        VERIFY_BRIEF = 1,
     7018        VERIFY_VERBOSE = 2,
     7019    } verify = 0;
     7020
     7021    while ((c = nextopt("pvV")) != '\0')
     7022        if (c == 'V')
     7023            verify |= VERIFY_VERBOSE;
     7024        else if (c == 'v')
     7025            verify |= VERIFY_BRIEF;
     7026#if DEBUG
     7027        else if (c != 'p')
     7028            abort();
     7029#endif
     7030    if (verify)
     7031        return describe_command(*argptr, verify - VERIFY_BRIEF);
     7032
     7033    return 0;
     7034}
     7035#endif
     7036
     7037
     7038/* ============ eval.c */
     7039
     7040static int funcblocksize;          /* size of structures in function */
     7041static int funcstringsize;         /* size of strings in node */
     7042static void *funcblock;            /* block to allocate function from */
     7043static char *funcstring;           /* block to allocate strings from */
     7044
     7045/* flags in argument to evaltree */
     7046#define EV_EXIT 01              /* exit after evaluating tree */
     7047#define EV_TESTED 02            /* exit status is checked; ignore -e flag */
     7048#define EV_BACKCMD 04           /* command executing within back quotes */
     7049
     7050static const short nodesize[26] = {
     7051    SHELL_ALIGN(sizeof(struct ncmd)),
     7052    SHELL_ALIGN(sizeof(struct npipe)),
     7053    SHELL_ALIGN(sizeof(struct nredir)),
     7054    SHELL_ALIGN(sizeof(struct nredir)),
     7055    SHELL_ALIGN(sizeof(struct nredir)),
     7056    SHELL_ALIGN(sizeof(struct nbinary)),
     7057    SHELL_ALIGN(sizeof(struct nbinary)),
     7058    SHELL_ALIGN(sizeof(struct nbinary)),
     7059    SHELL_ALIGN(sizeof(struct nif)),
     7060    SHELL_ALIGN(sizeof(struct nbinary)),
     7061    SHELL_ALIGN(sizeof(struct nbinary)),
     7062    SHELL_ALIGN(sizeof(struct nfor)),
     7063    SHELL_ALIGN(sizeof(struct ncase)),
     7064    SHELL_ALIGN(sizeof(struct nclist)),
     7065    SHELL_ALIGN(sizeof(struct narg)),
     7066    SHELL_ALIGN(sizeof(struct narg)),
     7067    SHELL_ALIGN(sizeof(struct nfile)),
     7068    SHELL_ALIGN(sizeof(struct nfile)),
     7069    SHELL_ALIGN(sizeof(struct nfile)),
     7070    SHELL_ALIGN(sizeof(struct nfile)),
     7071    SHELL_ALIGN(sizeof(struct nfile)),
     7072    SHELL_ALIGN(sizeof(struct ndup)),
     7073    SHELL_ALIGN(sizeof(struct ndup)),
     7074    SHELL_ALIGN(sizeof(struct nhere)),
     7075    SHELL_ALIGN(sizeof(struct nhere)),
     7076    SHELL_ALIGN(sizeof(struct nnot)),
     7077};
     7078
     7079static void calcsize(union node *n);
     7080
     7081static void
     7082sizenodelist(struct nodelist *lp)
     7083{
     7084    while (lp) {
     7085        funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
     7086        calcsize(lp->n);
     7087        lp = lp->next;
     7088    }
     7089}
     7090
     7091static void
     7092calcsize(union node *n)
     7093{
     7094    if (n == NULL)
     7095        return;
     7096    funcblocksize += nodesize[n->type];
     7097    switch (n->type) {
     7098    case NCMD:
     7099        calcsize(n->ncmd.redirect);
     7100        calcsize(n->ncmd.args);
     7101        calcsize(n->ncmd.assign);
     7102        break;
     7103    case NPIPE:
     7104        sizenodelist(n->npipe.cmdlist);
     7105        break;
     7106    case NREDIR:
     7107    case NBACKGND:
     7108    case NSUBSHELL:
     7109        calcsize(n->nredir.redirect);
     7110        calcsize(n->nredir.n);
     7111        break;
     7112    case NAND:
     7113    case NOR:
     7114    case NSEMI:
     7115    case NWHILE:
     7116    case NUNTIL:
     7117        calcsize(n->nbinary.ch2);
     7118        calcsize(n->nbinary.ch1);
     7119        break;
     7120    case NIF:
     7121        calcsize(n->nif.elsepart);
     7122        calcsize(n->nif.ifpart);
     7123        calcsize(n->nif.test);
     7124        break;
     7125    case NFOR:
     7126        funcstringsize += strlen(n->nfor.var) + 1;
     7127        calcsize(n->nfor.body);
     7128        calcsize(n->nfor.args);
     7129        break;
     7130    case NCASE:
     7131        calcsize(n->ncase.cases);
     7132        calcsize(n->ncase.expr);
     7133        break;
     7134    case NCLIST:
     7135        calcsize(n->nclist.body);
     7136        calcsize(n->nclist.pattern);
     7137        calcsize(n->nclist.next);
     7138        break;
     7139    case NDEFUN:
     7140    case NARG:
     7141        sizenodelist(n->narg.backquote);
     7142        funcstringsize += strlen(n->narg.text) + 1;
     7143        calcsize(n->narg.next);
     7144        break;
     7145    case NTO:
     7146    case NCLOBBER:
     7147    case NFROM:
     7148    case NFROMTO:
     7149    case NAPPEND:
     7150        calcsize(n->nfile.fname);
     7151        calcsize(n->nfile.next);
     7152        break;
     7153    case NTOFD:
     7154    case NFROMFD:
     7155        calcsize(n->ndup.vname);
     7156        calcsize(n->ndup.next);
     7157    break;
     7158    case NHERE:
     7159    case NXHERE:
     7160        calcsize(n->nhere.doc);
     7161        calcsize(n->nhere.next);
     7162        break;
     7163    case NNOT:
     7164        calcsize(n->nnot.com);
     7165        break;
     7166    };
     7167}
     7168
     7169static char *
     7170nodeckstrdup(char *s)
     7171{
     7172    char *rtn = funcstring;
     7173
     7174    strcpy(funcstring, s);
     7175    funcstring += strlen(s) + 1;
     7176    return rtn;
     7177}
     7178
     7179static union node *copynode(union node *);
     7180
     7181static struct nodelist *
     7182copynodelist(struct nodelist *lp)
     7183{
     7184    struct nodelist *start;
     7185    struct nodelist **lpp;
     7186
     7187    lpp = &start;
     7188    while (lp) {
     7189        *lpp = funcblock;
     7190        funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
     7191        (*lpp)->n = copynode(lp->n);
     7192        lp = lp->next;
     7193        lpp = &(*lpp)->next;
     7194    }
     7195    *lpp = NULL;
     7196    return start;
     7197}
     7198
     7199static union node *
     7200copynode(union node *n)
     7201{
     7202    union node *new;
     7203
     7204    if (n == NULL)
     7205        return NULL;
     7206    new = funcblock;
     7207    funcblock = (char *) funcblock + nodesize[n->type];
     7208
     7209    switch (n->type) {
     7210    case NCMD:
     7211        new->ncmd.redirect = copynode(n->ncmd.redirect);
     7212        new->ncmd.args = copynode(n->ncmd.args);
     7213        new->ncmd.assign = copynode(n->ncmd.assign);
     7214        break;
     7215    case NPIPE:
     7216        new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
     7217        new->npipe.backgnd = n->npipe.backgnd;
     7218        break;
     7219    case NREDIR:
     7220    case NBACKGND:
     7221    case NSUBSHELL:
     7222        new->nredir.redirect = copynode(n->nredir.redirect);
     7223        new->nredir.n = copynode(n->nredir.n);
     7224        break;
     7225    case NAND:
     7226    case NOR:
     7227    case NSEMI:
     7228    case NWHILE:
     7229    case NUNTIL:
     7230        new->nbinary.ch2 = copynode(n->nbinary.ch2);
     7231        new->nbinary.ch1 = copynode(n->nbinary.ch1);
     7232        break;
     7233    case NIF:
     7234        new->nif.elsepart = copynode(n->nif.elsepart);
     7235        new->nif.ifpart = copynode(n->nif.ifpart);
     7236        new->nif.test = copynode(n->nif.test);
     7237        break;
     7238    case NFOR:
     7239        new->nfor.var = nodeckstrdup(n->nfor.var);
     7240        new->nfor.body = copynode(n->nfor.body);
     7241        new->nfor.args = copynode(n->nfor.args);
     7242        break;
     7243    case NCASE:
     7244        new->ncase.cases = copynode(n->ncase.cases);
     7245        new->ncase.expr = copynode(n->ncase.expr);
     7246        break;
     7247    case NCLIST:
     7248        new->nclist.body = copynode(n->nclist.body);
     7249        new->nclist.pattern = copynode(n->nclist.pattern);
     7250        new->nclist.next = copynode(n->nclist.next);
     7251        break;
     7252    case NDEFUN:
     7253    case NARG:
     7254        new->narg.backquote = copynodelist(n->narg.backquote);
     7255        new->narg.text = nodeckstrdup(n->narg.text);
     7256        new->narg.next = copynode(n->narg.next);
     7257        break;
     7258    case NTO:
     7259    case NCLOBBER:
     7260    case NFROM:
     7261    case NFROMTO:
     7262    case NAPPEND:
     7263        new->nfile.fname = copynode(n->nfile.fname);
     7264        new->nfile.fd = n->nfile.fd;
     7265        new->nfile.next = copynode(n->nfile.next);
     7266        break;
     7267    case NTOFD:
     7268    case NFROMFD:
     7269        new->ndup.vname = copynode(n->ndup.vname);
     7270        new->ndup.dupfd = n->ndup.dupfd;
     7271        new->ndup.fd = n->ndup.fd;
     7272        new->ndup.next = copynode(n->ndup.next);
     7273        break;
     7274    case NHERE:
     7275    case NXHERE:
     7276        new->nhere.doc = copynode(n->nhere.doc);
     7277        new->nhere.fd = n->nhere.fd;
     7278        new->nhere.next = copynode(n->nhere.next);
     7279        break;
     7280    case NNOT:
     7281        new->nnot.com = copynode(n->nnot.com);
     7282        break;
     7283    };
     7284    new->type = n->type;
     7285    return new;
     7286}
     7287
     7288/*
     7289 * Make a copy of a parse tree.
     7290 */
     7291static struct funcnode *
     7292copyfunc(union node *n)
     7293{
     7294    struct funcnode *f;
     7295    size_t blocksize;
     7296
     7297    funcblocksize = offsetof(struct funcnode, n);
     7298    funcstringsize = 0;
     7299    calcsize(n);
     7300    blocksize = funcblocksize;
     7301    f = ckmalloc(blocksize + funcstringsize);
     7302    funcblock = (char *) f + offsetof(struct funcnode, n);
     7303    funcstring = (char *) f + blocksize;
     7304    copynode(n);
     7305    f->count = 0;
     7306    return f;
     7307}
     7308
     7309/*
     7310 * Define a shell function.
     7311 */
     7312static void
     7313defun(char *name, union node *func)
     7314{
     7315    struct cmdentry entry;
     7316
     7317    INT_OFF;
     7318    entry.cmdtype = CMDFUNCTION;
     7319    entry.u.func = copyfunc(func);
     7320    addcmdentry(name, &entry);
     7321    INT_ON;
     7322}
     7323
     7324static int evalskip;            /* set if we are skipping commands */
     7325/* reasons for skipping commands (see comment on breakcmd routine) */
     7326#define SKIPBREAK      (1 << 0)
     7327#define SKIPCONT       (1 << 1)
     7328#define SKIPFUNC       (1 << 2)
     7329#define SKIPFILE       (1 << 3)
     7330#define SKIPEVAL       (1 << 4)
     7331static int skipcount;           /* number of levels to skip */
     7332static int funcnest;            /* depth of function calls */
     7333
     7334/* forward decl way out to parsing code - dotrap needs it */
     7335static int evalstring(char *s, int mask);
     7336
     7337/*
     7338 * Called to execute a trap.  Perhaps we should avoid entering new trap
     7339 * handlers while we are executing a trap handler.
     7340 */
     7341static int
     7342dotrap(void)
     7343{
     7344    char *p;
     7345    char *q;
     7346    int i;
     7347    int savestatus;
     7348    int skip = 0;
     7349
     7350    savestatus = exitstatus;
     7351    pendingsig = 0;
     7352    xbarrier();
     7353
     7354    for (i = 0, q = gotsig; i < NSIG - 1; i++, q++) {
     7355        if (!*q)
     7356            continue;
     7357        *q = '\0';
     7358
     7359        p = trap[i + 1];
     7360        if (!p)
     7361            continue;
     7362        skip = evalstring(p, SKIPEVAL);
     7363        exitstatus = savestatus;
     7364        if (skip)
     7365            break;
     7366    }
     7367
     7368    return skip;
     7369}
     7370
     7371/* forward declarations - evaluation is fairly recursive business... */
     7372static void evalloop(union node *, int);
     7373static void evalfor(union node *, int);
     7374static void evalcase(union node *, int);
     7375static void evalsubshell(union node *, int);
     7376static void expredir(union node *);
     7377static void evalpipe(union node *, int);
     7378static void evalcommand(union node *, int);
     7379static int evalbltin(const struct builtincmd *, int, char **);
     7380static void prehash(union node *);
     7381
     7382/*
     7383 * Evaluate a parse tree.  The value is left in the global variable
     7384 * exitstatus.
     7385 */
     7386static void
     7387evaltree(union node *n, int flags)
     7388{
     7389    int checkexit = 0;
     7390    void (*evalfn)(union node *, int);
     7391    unsigned isor;
    77457392    int status;
    7746     int retval;
    7747 
    7748     status = job->ps[job->nprocs - 1].status;
    7749     retval = WEXITSTATUS(status);
    7750     if (!WIFEXITED(status)) {
     7393    if (n == NULL) {
     7394        TRACE(("evaltree(NULL) called\n"));
     7395        goto out;
     7396    }
     7397    TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
     7398            getpid(), n, n->type, flags));
     7399    switch (n->type) {
     7400    default:
     7401#if DEBUG
     7402        out1fmt("Node type = %d\n", n->type);
     7403        fflush(stdout);
     7404        break;
     7405#endif
     7406    case NNOT:
     7407        evaltree(n->nnot.com, EV_TESTED);
     7408        status = !exitstatus;
     7409        goto setstatus;
     7410    case NREDIR:
     7411        expredir(n->nredir.redirect);
     7412        status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
     7413        if (!status) {
     7414            evaltree(n->nredir.n, flags & EV_TESTED);
     7415            status = exitstatus;
     7416        }
     7417        popredir(0);
     7418        goto setstatus;
     7419    case NCMD:
     7420        evalfn = evalcommand;
     7421 checkexit:
     7422        if (eflag && !(flags & EV_TESTED))
     7423            checkexit = ~0;
     7424        goto calleval;
     7425    case NFOR:
     7426        evalfn = evalfor;
     7427        goto calleval;
     7428    case NWHILE:
     7429    case NUNTIL:
     7430        evalfn = evalloop;
     7431        goto calleval;
     7432    case NSUBSHELL:
     7433    case NBACKGND:
     7434        evalfn = evalsubshell;
     7435        goto calleval;
     7436    case NPIPE:
     7437        evalfn = evalpipe;
     7438        goto checkexit;
     7439    case NCASE:
     7440        evalfn = evalcase;
     7441        goto calleval;
     7442    case NAND:
     7443    case NOR:
     7444    case NSEMI:
     7445#if NAND + 1 != NOR
     7446#error NAND + 1 != NOR
     7447#endif
     7448#if NOR + 1 != NSEMI
     7449#error NOR + 1 != NSEMI
     7450#endif
     7451        isor = n->type - NAND;
     7452        evaltree(
     7453            n->nbinary.ch1,
     7454            (flags | ((isor >> 1) - 1)) & EV_TESTED
     7455        );
     7456        if (!exitstatus == isor)
     7457            break;
     7458        if (!evalskip) {
     7459            n = n->nbinary.ch2;
     7460 evaln:
     7461            evalfn = evaltree;
     7462 calleval:
     7463            evalfn(n, flags);
     7464            break;
     7465        }
     7466        break;
     7467    case NIF:
     7468        evaltree(n->nif.test, EV_TESTED);
     7469        if (evalskip)
     7470            break;
     7471        if (exitstatus == 0) {
     7472            n = n->nif.ifpart;
     7473            goto evaln;
     7474        } else if (n->nif.elsepart) {
     7475            n = n->nif.elsepart;
     7476            goto evaln;
     7477        }
     7478        goto success;
     7479    case NDEFUN:
     7480        defun(n->narg.text, n->narg.next);
     7481 success:
     7482        status = 0;
     7483 setstatus:
     7484        exitstatus = status;
     7485        break;
     7486    }
     7487 out:
     7488    if ((checkexit & exitstatus))
     7489        evalskip |= SKIPEVAL;
     7490    else if (pendingsig && dotrap())
     7491        goto exexit;
     7492
     7493    if (flags & EV_EXIT) {
     7494 exexit:
     7495        raise_exception(EXEXIT);
     7496    }
     7497}
     7498
     7499#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
     7500static
     7501#endif
     7502void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
     7503
     7504static int loopnest;            /* current loop nesting level */
     7505
     7506static void
     7507evalloop(union node *n, int flags)
     7508{
     7509    int status;
     7510
     7511    loopnest++;
     7512    status = 0;
     7513    flags &= EV_TESTED;
     7514    for (;;) {
     7515        int i;
     7516
     7517        evaltree(n->nbinary.ch1, EV_TESTED);
     7518        if (evalskip) {
     7519 skipping:
     7520            if (evalskip == SKIPCONT && --skipcount <= 0) {
     7521                evalskip = 0;
     7522                continue;
     7523            }
     7524            if (evalskip == SKIPBREAK && --skipcount <= 0)
     7525                evalskip = 0;
     7526            break;
     7527        }
     7528        i = exitstatus;
     7529        if (n->type != NWHILE)
     7530            i = !i;
     7531        if (i != 0)
     7532            break;
     7533        evaltree(n->nbinary.ch2, flags);
     7534        status = exitstatus;
     7535        if (evalskip)
     7536            goto skipping;
     7537    }
     7538    loopnest--;
     7539    exitstatus = status;
     7540}
     7541
     7542static void
     7543evalfor(union node *n, int flags)
     7544{
     7545    struct arglist arglist;
     7546    union node *argp;
     7547    struct strlist *sp;
     7548    struct stackmark smark;
     7549
     7550    setstackmark(&smark);
     7551    arglist.lastp = &arglist.list;
     7552    for (argp = n->nfor.args; argp; argp = argp->narg.next) {
     7553        expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
     7554        /* XXX */
     7555        if (evalskip)
     7556            goto out;
     7557    }
     7558    *arglist.lastp = NULL;
     7559
     7560    exitstatus = 0;
     7561    loopnest++;
     7562    flags &= EV_TESTED;
     7563    for (sp = arglist.list; sp; sp = sp->next) {
     7564        setvar(n->nfor.var, sp->text, 0);
     7565        evaltree(n->nfor.body, flags);
     7566        if (evalskip) {
     7567            if (evalskip == SKIPCONT && --skipcount <= 0) {
     7568                evalskip = 0;
     7569                continue;
     7570            }
     7571            if (evalskip == SKIPBREAK && --skipcount <= 0)
     7572                evalskip = 0;
     7573            break;
     7574        }
     7575    }
     7576    loopnest--;
     7577 out:
     7578    popstackmark(&smark);
     7579}
     7580
     7581static void
     7582evalcase(union node *n, int flags)
     7583{
     7584    union node *cp;
     7585    union node *patp;
     7586    struct arglist arglist;
     7587    struct stackmark smark;
     7588
     7589    setstackmark(&smark);
     7590    arglist.lastp = &arglist.list;
     7591    expandarg(n->ncase.expr, &arglist, EXP_TILDE);
     7592    exitstatus = 0;
     7593    for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
     7594        for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
     7595            if (casematch(patp, arglist.list->text)) {
     7596                if (evalskip == 0) {
     7597                    evaltree(cp->nclist.body, flags);
     7598                }
     7599                goto out;
     7600            }
     7601        }
     7602    }
     7603 out:
     7604    popstackmark(&smark);
     7605}
     7606
     7607/*
     7608 * Kick off a subshell to evaluate a tree.
     7609 */
     7610static void
     7611evalsubshell(union node *n, int flags)
     7612{
     7613    struct job *jp;
     7614    int backgnd = (n->type == NBACKGND);
     7615    int status;
     7616
     7617    expredir(n->nredir.redirect);
     7618    if (!backgnd && flags & EV_EXIT && !trap[0])
     7619        goto nofork;
     7620    INT_OFF;
     7621    jp = makejob(n, 1);
     7622    if (forkshell(jp, n, backgnd) == 0) {
     7623        INT_ON;
     7624        flags |= EV_EXIT;
     7625        if (backgnd)
     7626            flags &=~ EV_TESTED;
     7627 nofork:
     7628        redirect(n->nredir.redirect, 0);
     7629        evaltreenr(n->nredir.n, flags);
     7630        /* never returns */
     7631    }
     7632    status = 0;
     7633    if (! backgnd)
     7634        status = waitforjob(jp);
     7635    exitstatus = status;
     7636    INT_ON;
     7637}
     7638
     7639/*
     7640 * Compute the names of the files in a redirection list.
     7641 */
     7642static void fixredir(union node *, const char *, int);
     7643static void
     7644expredir(union node *n)
     7645{
     7646    union node *redir;
     7647
     7648    for (redir = n; redir; redir = redir->nfile.next) {
     7649        struct arglist fn;
     7650
     7651        memset(&fn, 0, sizeof(fn));
     7652        fn.lastp = &fn.list;
     7653        switch (redir->type) {
     7654        case NFROMTO:
     7655        case NFROM:
     7656        case NTO:
     7657        case NCLOBBER:
     7658        case NAPPEND:
     7659            expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
     7660            redir->nfile.expfname = fn.list->text;
     7661            break;
     7662        case NFROMFD:
     7663        case NTOFD:
     7664            if (redir->ndup.vname) {
     7665                expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
     7666                if (fn.list == NULL)
     7667                    ash_msg_and_raise_error("redir error");
     7668                fixredir(redir, fn.list->text, 1);
     7669            }
     7670            break;
     7671        }
     7672    }
     7673}
     7674
     7675/*
     7676 * Evaluate a pipeline.  All the processes in the pipeline are children
     7677 * of the process creating the pipeline.  (This differs from some versions
     7678 * of the shell, which make the last process in a pipeline the parent
     7679 * of all the rest.)
     7680 */
     7681static void
     7682evalpipe(union node *n, int flags)
     7683{
     7684    struct job *jp;
     7685    struct nodelist *lp;
     7686    int pipelen;
     7687    int prevfd;
     7688    int pip[2];
     7689
     7690    TRACE(("evalpipe(0x%lx) called\n", (long)n));
     7691    pipelen = 0;
     7692    for (lp = n->npipe.cmdlist; lp; lp = lp->next)
     7693        pipelen++;
     7694    flags |= EV_EXIT;
     7695    INT_OFF;
     7696    jp = makejob(n, pipelen);
     7697    prevfd = -1;
     7698    for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
     7699        prehash(lp->n);
     7700        pip[1] = -1;
     7701        if (lp->next) {
     7702            if (pipe(pip) < 0) {
     7703                close(prevfd);
     7704                ash_msg_and_raise_error("pipe call failed");
     7705            }
     7706        }
     7707        if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
     7708            INT_ON;
     7709            if (pip[1] >= 0) {
     7710                close(pip[0]);
     7711            }
     7712            if (prevfd > 0) {
     7713                dup2(prevfd, 0);
     7714                close(prevfd);
     7715            }
     7716            if (pip[1] > 1) {
     7717                dup2(pip[1], 1);
     7718                close(pip[1]);
     7719            }
     7720            evaltreenr(lp->n, flags);
     7721            /* never returns */
     7722        }
     7723        if (prevfd >= 0)
     7724            close(prevfd);
     7725        prevfd = pip[0];
     7726        close(pip[1]);
     7727    }
     7728    if (n->npipe.backgnd == 0) {
     7729        exitstatus = waitforjob(jp);
     7730        TRACE(("evalpipe:  job done exit status %d\n", exitstatus));
     7731    }
     7732    INT_ON;
     7733}
     7734
     7735/*
     7736 * Controls whether the shell is interactive or not.
     7737 */
     7738static void
     7739setinteractive(int on)
     7740{
     7741    static int is_interactive;
     7742
     7743    if (++on == is_interactive)
     7744        return;
     7745    is_interactive = on;
     7746    setsignal(SIGINT);
     7747    setsignal(SIGQUIT);
     7748    setsignal(SIGTERM);
     7749#if !ENABLE_FEATURE_SH_EXTRA_QUIET
     7750    if (is_interactive > 1) {
     7751        /* Looks like they want an interactive shell */
     7752        static smallint did_banner;
     7753
     7754        if (!did_banner) {
     7755            out1fmt(
     7756                "\n\n"
     7757                "%s built-in shell (ash)\n"
     7758                "Enter 'help' for a list of built-in commands."
     7759                "\n\n",
     7760                bb_banner);
     7761            did_banner = 1;
     7762        }
     7763    }
     7764#endif
     7765}
     7766
     7767#if ENABLE_FEATURE_EDITING_VI
     7768#define setvimode(on) do { \
     7769    if (on) line_input_state->flags |= VI_MODE; \
     7770    else line_input_state->flags &= ~VI_MODE; \
     7771} while (0)
     7772#else
     7773#define setvimode(on) viflag = 0   /* forcibly keep the option off */
     7774#endif
     7775
     7776static void
     7777optschanged(void)
     7778{
     7779#if DEBUG
     7780    opentrace();
     7781#endif
     7782    setinteractive(iflag);
     7783    setjobctl(mflag);
     7784    setvimode(viflag);
     7785}
     7786
     7787static struct localvar *localvars;
     7788
     7789/*
     7790 * Called after a function returns.
     7791 * Interrupts must be off.
     7792 */
     7793static void
     7794poplocalvars(void)
     7795{
     7796    struct localvar *lvp;
     7797    struct var *vp;
     7798
     7799    while ((lvp = localvars) != NULL) {
     7800        localvars = lvp->next;
     7801        vp = lvp->vp;
     7802        TRACE(("poplocalvar %s", vp ? vp->text : "-"));
     7803        if (vp == NULL) {       /* $- saved */
     7804            memcpy(optlist, lvp->text, sizeof(optlist));
     7805            free((char*)lvp->text);
     7806            optschanged();
     7807        } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
     7808            unsetvar(vp->text);
     7809        } else {
     7810            if (vp->func)
     7811                (*vp->func)(strchrnul(lvp->text, '=') + 1);
     7812            if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
     7813                free((char*)vp->text);
     7814            vp->flags = lvp->flags;
     7815            vp->text = lvp->text;
     7816        }
     7817        free(lvp);
     7818    }
     7819}
     7820
     7821static int
     7822evalfun(struct funcnode *func, int argc, char **argv, int flags)
     7823{
     7824    volatile struct shparam saveparam;
     7825    struct localvar *volatile savelocalvars;
     7826    struct jmploc *volatile savehandler;
     7827    struct jmploc jmploc;
     7828    int e;
     7829
     7830    saveparam = shellparam;
     7831    savelocalvars = localvars;
     7832    e = setjmp(jmploc.loc);
     7833    if (e) {
     7834        goto funcdone;
     7835    }
     7836    INT_OFF;
     7837    savehandler = exception_handler;
     7838    exception_handler = &jmploc;
     7839    localvars = NULL;
     7840    shellparam.malloc = 0;
     7841    func->count++;
     7842    funcnest++;
     7843    INT_ON;
     7844    shellparam.nparam = argc - 1;
     7845    shellparam.p = argv + 1;
     7846#if ENABLE_ASH_GETOPTS
     7847    shellparam.optind = 1;
     7848    shellparam.optoff = -1;
     7849#endif
     7850    evaltree(&func->n, flags & EV_TESTED);
     7851funcdone:
     7852    INT_OFF;
     7853    funcnest--;
     7854    freefunc(func);
     7855    poplocalvars();
     7856    localvars = savelocalvars;
     7857    freeparam(&shellparam);
     7858    shellparam = saveparam;
     7859    exception_handler = savehandler;
     7860    INT_ON;
     7861    evalskip &= ~SKIPFUNC;
     7862    return e;
     7863}
     7864
     7865#if ENABLE_ASH_CMDCMD
     7866static char **
     7867parse_command_args(char **argv, const char **path)
     7868{
     7869    char *cp, c;
     7870
     7871    for (;;) {
     7872        cp = *++argv;
     7873        if (!cp)
     7874            return 0;
     7875        if (*cp++ != '-')
     7876            break;
     7877        c = *cp++;
     7878        if (!c)
     7879            break;
     7880        if (c == '-' && !*cp) {
     7881            argv++;
     7882            break;
     7883        }
     7884        do {
     7885            switch (c) {
     7886            case 'p':
     7887                *path = bb_default_path;
     7888                break;
     7889            default:
     7890                /* run 'typecmd' for other options */
     7891                return 0;
     7892            }
     7893            c = *cp++;
     7894        } while (c);
     7895    }
     7896    return argv;
     7897}
     7898#endif
     7899
     7900/*
     7901 * Make a variable a local variable.  When a variable is made local, it's
     7902 * value and flags are saved in a localvar structure.  The saved values
     7903 * will be restored when the shell function returns.  We handle the name
     7904 * "-" as a special case.
     7905 */
     7906static void
     7907mklocal(char *name)
     7908{
     7909    struct localvar *lvp;
     7910    struct var **vpp;
     7911    struct var *vp;
     7912
     7913    INT_OFF;
     7914    lvp = ckmalloc(sizeof(struct localvar));
     7915    if (LONE_DASH(name)) {
     7916        char *p;
     7917        p = ckmalloc(sizeof(optlist));
     7918        lvp->text = memcpy(p, optlist, sizeof(optlist));
     7919        vp = NULL;
     7920    } else {
     7921        char *eq;
     7922
     7923        vpp = hashvar(name);
     7924        vp = *findvar(vpp, name);
     7925        eq = strchr(name, '=');
     7926        if (vp == NULL) {
     7927            if (eq)
     7928                setvareq(name, VSTRFIXED);
     7929            else
     7930                setvar(name, NULL, VSTRFIXED);
     7931            vp = *vpp;      /* the new variable */
     7932            lvp->flags = VUNSET;
     7933        } else {
     7934            lvp->text = vp->text;
     7935            lvp->flags = vp->flags;
     7936            vp->flags |= VSTRFIXED|VTEXTFIXED;
     7937            if (eq)
     7938                setvareq(name, 0);
     7939        }
     7940    }
     7941    lvp->vp = vp;
     7942    lvp->next = localvars;
     7943    localvars = lvp;
     7944    INT_ON;
     7945}
     7946
     7947/*
     7948 * The "local" command.
     7949 */
     7950static int
     7951localcmd(int argc, char **argv)
     7952{
     7953    char *name;
     7954
     7955    argv = argptr;
     7956    while ((name = *argv++) != NULL) {
     7957        mklocal(name);
     7958    }
     7959    return 0;
     7960}
     7961
     7962static int
     7963falsecmd(int argc, char **argv)
     7964{
     7965    return 1;
     7966}
     7967
     7968static int
     7969truecmd(int argc, char **argv)
     7970{
     7971    return 0;
     7972}
     7973
     7974static int
     7975execcmd(int argc, char **argv)
     7976{
     7977    if (argc > 1) {
     7978        iflag = 0;              /* exit on error */
     7979        mflag = 0;
     7980        optschanged();
     7981        shellexec(argv + 1, pathval(), 0);
     7982    }
     7983    return 0;
     7984}
     7985
     7986/*
     7987 * The return command.
     7988 */
     7989static int
     7990returncmd(int argc, char **argv)
     7991{
     7992    /*
     7993     * If called outside a function, do what ksh does;
     7994     * skip the rest of the file.
     7995     */
     7996    evalskip = funcnest ? SKIPFUNC : SKIPFILE;
     7997    return argv[1] ? number(argv[1]) : exitstatus;
     7998}
     7999
     8000/* Forward declarations for builtintab[] */
     8001static int breakcmd(int, char **);
     8002static int dotcmd(int, char **);
     8003static int evalcmd(int, char **);
     8004#if ENABLE_ASH_BUILTIN_ECHO
     8005static int echocmd(int, char **);
     8006#endif
     8007#if ENABLE_ASH_BUILTIN_TEST
     8008static int testcmd(int, char **);
     8009#endif
     8010static int exitcmd(int, char **);
     8011static int exportcmd(int, char **);
     8012#if ENABLE_ASH_GETOPTS
     8013static int getoptscmd(int, char **);
     8014#endif
     8015#if !ENABLE_FEATURE_SH_EXTRA_QUIET
     8016static int helpcmd(int argc, char **argv);
     8017#endif
     8018#if ENABLE_ASH_MATH_SUPPORT
     8019static int letcmd(int, char **);
     8020#endif
     8021static int readcmd(int, char **);
     8022static int setcmd(int, char **);
     8023static int shiftcmd(int, char **);
     8024static int timescmd(int, char **);
     8025static int trapcmd(int, char **);
     8026static int umaskcmd(int, char **);
     8027static int unsetcmd(int, char **);
     8028static int ulimitcmd(int, char **);
     8029
     8030#define BUILTIN_NOSPEC          "0"
     8031#define BUILTIN_SPECIAL         "1"
     8032#define BUILTIN_REGULAR         "2"
     8033#define BUILTIN_SPEC_REG        "3"
     8034#define BUILTIN_ASSIGN          "4"
     8035#define BUILTIN_SPEC_ASSG       "5"
     8036#define BUILTIN_REG_ASSG        "6"
     8037#define BUILTIN_SPEC_REG_ASSG   "7"
     8038
     8039/* make sure to keep these in proper order since it is searched via bsearch() */
     8040static const struct builtincmd builtintab[] = {
     8041    { BUILTIN_SPEC_REG      ".", dotcmd },
     8042    { BUILTIN_SPEC_REG      ":", truecmd },
     8043#if ENABLE_ASH_BUILTIN_TEST
     8044    { BUILTIN_REGULAR   "[", testcmd },
     8045    { BUILTIN_REGULAR   "[[", testcmd },
     8046#endif
     8047#if ENABLE_ASH_ALIAS
     8048    { BUILTIN_REG_ASSG      "alias", aliascmd },
     8049#endif
    77518050#if JOBS
    7752         retval = WSTOPSIG(status);
    7753         if (!WIFSTOPPED(status))
    7754 #endif
    7755         {
    7756             /* XXX: limits number of signals */
    7757             retval = WTERMSIG(status);
     8051    { BUILTIN_REGULAR       "bg", fg_bgcmd },
     8052#endif
     8053    { BUILTIN_SPEC_REG      "break", breakcmd },
     8054    { BUILTIN_REGULAR       "cd", cdcmd },
     8055    { BUILTIN_NOSPEC        "chdir", cdcmd },
     8056#if ENABLE_ASH_CMDCMD
     8057    { BUILTIN_REGULAR       "command", commandcmd },
     8058#endif
     8059    { BUILTIN_SPEC_REG      "continue", breakcmd },
     8060#if ENABLE_ASH_BUILTIN_ECHO
     8061    { BUILTIN_REGULAR       "echo", echocmd },
     8062#endif
     8063    { BUILTIN_SPEC_REG      "eval", evalcmd },
     8064    { BUILTIN_SPEC_REG      "exec", execcmd },
     8065    { BUILTIN_SPEC_REG      "exit", exitcmd },
     8066    { BUILTIN_SPEC_REG_ASSG "export", exportcmd },
     8067    { BUILTIN_REGULAR       "false", falsecmd },
    77588068#if JOBS
    7759             if (retval == SIGINT)
    7760                 job->sigint = 1;
    7761 #endif
    7762         }
    7763         retval += 128;
    7764     }
    7765     TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
    7766         jobno(job), job->nprocs, status, retval));
    7767     return retval;
    7768 }
    7769 
    7770 #ifdef CONFIG_ASH_MAIL
    7771 /*      mail.c       */
    7772 
    7773 /*
    7774  * Routines to check for mail.  (Perhaps make part of main.c?)
    7775  */
     8069    { BUILTIN_REGULAR       "fg", fg_bgcmd },
     8070#endif
     8071#if ENABLE_ASH_GETOPTS
     8072    { BUILTIN_REGULAR       "getopts", getoptscmd },
     8073#endif
     8074    { BUILTIN_NOSPEC        "hash", hashcmd },
     8075#if !ENABLE_FEATURE_SH_EXTRA_QUIET
     8076    { BUILTIN_NOSPEC        "help", helpcmd },
     8077#endif
     8078#if JOBS
     8079    { BUILTIN_REGULAR       "jobs", jobscmd },
     8080    { BUILTIN_REGULAR       "kill", killcmd },
     8081#endif
     8082#if ENABLE_ASH_MATH_SUPPORT
     8083    { BUILTIN_NOSPEC        "let", letcmd },
     8084#endif
     8085    { BUILTIN_ASSIGN        "local", localcmd },
     8086    { BUILTIN_NOSPEC        "pwd", pwdcmd },
     8087    { BUILTIN_REGULAR       "read", readcmd },
     8088    { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
     8089    { BUILTIN_SPEC_REG      "return", returncmd },
     8090    { BUILTIN_SPEC_REG      "set", setcmd },
     8091    { BUILTIN_SPEC_REG      "shift", shiftcmd },
     8092    { BUILTIN_SPEC_REG      "source", dotcmd },
     8093#if ENABLE_ASH_BUILTIN_TEST
     8094    { BUILTIN_REGULAR   "test", testcmd },
     8095#endif
     8096    { BUILTIN_SPEC_REG      "times", timescmd },
     8097    { BUILTIN_SPEC_REG      "trap", trapcmd },
     8098    { BUILTIN_REGULAR       "true", truecmd },
     8099    { BUILTIN_NOSPEC        "type", typecmd },
     8100    { BUILTIN_NOSPEC        "ulimit", ulimitcmd },
     8101    { BUILTIN_REGULAR       "umask", umaskcmd },
     8102#if ENABLE_ASH_ALIAS
     8103    { BUILTIN_REGULAR       "unalias", unaliascmd },
     8104#endif
     8105    { BUILTIN_SPEC_REG      "unset", unsetcmd },
     8106    { BUILTIN_REGULAR       "wait", waitcmd },
     8107};
     8108
     8109
     8110#define COMMANDCMD (builtintab + 5 + \
     8111    2 * ENABLE_ASH_BUILTIN_TEST + \
     8112    ENABLE_ASH_ALIAS + \
     8113    ENABLE_ASH_JOB_CONTROL)
     8114#define EXECCMD (builtintab + 7 + \
     8115    2 * ENABLE_ASH_BUILTIN_TEST + \
     8116    ENABLE_ASH_ALIAS + \
     8117    ENABLE_ASH_JOB_CONTROL + \
     8118    ENABLE_ASH_CMDCMD + \
     8119    ENABLE_ASH_BUILTIN_ECHO)
     8120
     8121/*
     8122 * Search the table of builtin commands.
     8123 */
     8124static struct builtincmd *
     8125find_builtin(const char *name)
     8126{
     8127    struct builtincmd *bp;
     8128
     8129    bp = bsearch(
     8130        name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
     8131        pstrcmp
     8132    );
     8133    return bp;
     8134}
     8135
     8136/*
     8137 * Execute a simple command.
     8138 */
     8139static int back_exitstatus; /* exit status of backquoted command */
     8140static int
     8141isassignment(const char *p)
     8142{
     8143    const char *q = endofname(p);
     8144    if (p == q)
     8145        return 0;
     8146    return *q == '=';
     8147}
     8148static int
     8149bltincmd(int argc, char **argv)
     8150{
     8151    /* Preserve exitstatus of a previous possible redirection
     8152     * as POSIX mandates */
     8153    return back_exitstatus;
     8154}
     8155static void
     8156evalcommand(union node *cmd, int flags)
     8157{
     8158    static const struct builtincmd bltin = {
     8159        "\0\0", bltincmd
     8160    };
     8161    struct stackmark smark;
     8162    union node *argp;
     8163    struct arglist arglist;
     8164    struct arglist varlist;
     8165    char **argv;
     8166    int argc;
     8167    const struct strlist *sp;
     8168    struct cmdentry cmdentry;
     8169    struct job *jp;
     8170    char *lastarg;
     8171    const char *path;
     8172    int spclbltin;
     8173    int cmd_is_exec;
     8174    int status;
     8175    char **nargv;
     8176    struct builtincmd *bcmd;
     8177    int pseudovarflag = 0;
     8178
     8179    /* First expand the arguments. */
     8180    TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
     8181    setstackmark(&smark);
     8182    back_exitstatus = 0;
     8183
     8184    cmdentry.cmdtype = CMDBUILTIN;
     8185    cmdentry.u.cmd = &bltin;
     8186    varlist.lastp = &varlist.list;
     8187    *varlist.lastp = NULL;
     8188    arglist.lastp = &arglist.list;
     8189    *arglist.lastp = NULL;
     8190
     8191    argc = 0;
     8192    if (cmd->ncmd.args) {
     8193        bcmd = find_builtin(cmd->ncmd.args->narg.text);
     8194        pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
     8195    }
     8196
     8197    for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
     8198        struct strlist **spp;
     8199
     8200        spp = arglist.lastp;
     8201        if (pseudovarflag && isassignment(argp->narg.text))
     8202            expandarg(argp, &arglist, EXP_VARTILDE);
     8203        else
     8204            expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
     8205
     8206        for (sp = *spp; sp; sp = sp->next)
     8207            argc++;
     8208    }
     8209
     8210    argv = nargv = stalloc(sizeof(char *) * (argc + 1));
     8211    for (sp = arglist.list; sp; sp = sp->next) {
     8212        TRACE(("evalcommand arg: %s\n", sp->text));
     8213        *nargv++ = sp->text;
     8214    }
     8215    *nargv = NULL;
     8216
     8217    lastarg = NULL;
     8218    if (iflag && funcnest == 0 && argc > 0)
     8219        lastarg = nargv[-1];
     8220
     8221    preverrout_fd = 2;
     8222    expredir(cmd->ncmd.redirect);
     8223    status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
     8224
     8225    path = vpath.text;
     8226    for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
     8227        struct strlist **spp;
     8228        char *p;
     8229
     8230        spp = varlist.lastp;
     8231        expandarg(argp, &varlist, EXP_VARTILDE);
     8232
     8233        /*
     8234         * Modify the command lookup path, if a PATH= assignment
     8235         * is present
     8236         */
     8237        p = (*spp)->text;
     8238        if (varequal(p, path))
     8239            path = p;
     8240    }
     8241
     8242    /* Print the command if xflag is set. */
     8243    if (xflag) {
     8244        int n;
     8245        const char *p = " %s";
     8246
     8247        p++;
     8248        dprintf(preverrout_fd, p, expandstr(ps4val()));
     8249
     8250        sp = varlist.list;
     8251        for (n = 0; n < 2; n++) {
     8252            while (sp) {
     8253                dprintf(preverrout_fd, p, sp->text);
     8254                sp = sp->next;
     8255                if (*p == '%') {
     8256                    p--;
     8257                }
     8258            }
     8259            sp = arglist.list;
     8260        }
     8261        full_write(preverrout_fd, "\n", 1);
     8262    }
     8263
     8264    cmd_is_exec = 0;
     8265    spclbltin = -1;
     8266
     8267    /* Now locate the command. */
     8268    if (argc) {
     8269        const char *oldpath;
     8270        int cmd_flag = DO_ERR;
     8271
     8272        path += 5;
     8273        oldpath = path;
     8274        for (;;) {
     8275            find_command(argv[0], &cmdentry, cmd_flag, path);
     8276            if (cmdentry.cmdtype == CMDUNKNOWN) {
     8277                status = 127;
     8278                flush_stderr();
     8279                goto bail;
     8280            }
     8281
     8282            /* implement bltin and command here */
     8283            if (cmdentry.cmdtype != CMDBUILTIN)
     8284                break;
     8285            if (spclbltin < 0)
     8286                spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
     8287            if (cmdentry.u.cmd == EXECCMD)
     8288                cmd_is_exec++;
     8289#if ENABLE_ASH_CMDCMD
     8290            if (cmdentry.u.cmd == COMMANDCMD) {
     8291                path = oldpath;
     8292                nargv = parse_command_args(argv, &path);
     8293                if (!nargv)
     8294                    break;
     8295                argc -= nargv - argv;
     8296                argv = nargv;
     8297                cmd_flag |= DO_NOFUNC;
     8298            } else
     8299#endif
     8300                break;
     8301        }
     8302    }
     8303
     8304    if (status) {
     8305        /* We have a redirection error. */
     8306        if (spclbltin > 0)
     8307            raise_exception(EXERROR);
     8308 bail:
     8309        exitstatus = status;
     8310        goto out;
     8311    }
     8312
     8313    /* Execute the command. */
     8314    switch (cmdentry.cmdtype) {
     8315    default:
     8316        /* Fork off a child process if necessary. */
     8317        if (!(flags & EV_EXIT) || trap[0]) {
     8318            INT_OFF;
     8319            jp = makejob(cmd, 1);
     8320            if (forkshell(jp, cmd, FORK_FG) != 0) {
     8321                exitstatus = waitforjob(jp);
     8322                INT_ON;
     8323                break;
     8324            }
     8325            FORCE_INT_ON;
     8326        }
     8327        listsetvar(varlist.list, VEXPORT|VSTACK);
     8328        shellexec(argv, path, cmdentry.u.index);
     8329        /* NOTREACHED */
     8330
     8331    case CMDBUILTIN:
     8332        cmdenviron = varlist.list;
     8333        if (cmdenviron) {
     8334            struct strlist *list = cmdenviron;
     8335            int i = VNOSET;
     8336            if (spclbltin > 0 || argc == 0) {
     8337                i = 0;
     8338                if (cmd_is_exec && argc > 1)
     8339                    i = VEXPORT;
     8340            }
     8341            listsetvar(list, i);
     8342        }
     8343        if (evalbltin(cmdentry.u.cmd, argc, argv)) {
     8344            int exit_status;
     8345            int i, j;
     8346
     8347            i = exception;
     8348            if (i == EXEXIT)
     8349                goto raise;
     8350
     8351            exit_status = 2;
     8352            j = 0;
     8353            if (i == EXINT)
     8354                j = SIGINT;
     8355            if (i == EXSIG)
     8356                j = pendingsig;
     8357            if (j)
     8358                exit_status = j + 128;
     8359            exitstatus = exit_status;
     8360
     8361            if (i == EXINT || spclbltin > 0) {
     8362 raise:
     8363                longjmp(exception_handler->loc, 1);
     8364            }
     8365            FORCE_INT_ON;
     8366        }
     8367        break;
     8368
     8369    case CMDFUNCTION:
     8370        listsetvar(varlist.list, 0);
     8371        if (evalfun(cmdentry.u.func, argc, argv, flags))
     8372            goto raise;
     8373        break;
     8374    }
     8375
     8376 out:
     8377    popredir(cmd_is_exec);
     8378    if (lastarg)
     8379        /* dsl: I think this is intended to be used to support
     8380         * '_' in 'vi' command mode during line editing...
     8381         * However I implemented that within libedit itself.
     8382         */
     8383        setvar("_", lastarg, 0);
     8384    popstackmark(&smark);
     8385}
     8386
     8387static int
     8388evalbltin(const struct builtincmd *cmd, int argc, char **argv)
     8389{
     8390    char *volatile savecmdname;
     8391    struct jmploc *volatile savehandler;
     8392    struct jmploc jmploc;
     8393    int i;
     8394
     8395    savecmdname = commandname;
     8396    i = setjmp(jmploc.loc);
     8397    if (i)
     8398        goto cmddone;
     8399    savehandler = exception_handler;
     8400    exception_handler = &jmploc;
     8401    commandname = argv[0];
     8402    argptr = argv + 1;
     8403    optptr = NULL;                  /* initialize nextopt */
     8404    exitstatus = (*cmd->builtin)(argc, argv);
     8405    flush_stdout_stderr();
     8406 cmddone:
     8407    exitstatus |= ferror(stdout);
     8408    clearerr(stdout);
     8409    commandname = savecmdname;
     8410    exsig = 0;
     8411    exception_handler = savehandler;
     8412
     8413    return i;
     8414}
     8415
     8416static int
     8417goodname(const char *p)
     8418{
     8419    return !*endofname(p);
     8420}
     8421
     8422
     8423/*
     8424 * Search for a command.  This is called before we fork so that the
     8425 * location of the command will be available in the parent as well as
     8426 * the child.  The check for "goodname" is an overly conservative
     8427 * check that the name will not be subject to expansion.
     8428 */
     8429static void
     8430prehash(union node *n)
     8431{
     8432    struct cmdentry entry;
     8433
     8434    if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
     8435        find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
     8436}
     8437
     8438
     8439/* ============ Builtin commands
     8440 *
     8441 * Builtin commands whose functions are closely tied to evaluation
     8442 * are implemented here.
     8443 */
     8444
     8445/*
     8446 * Handle break and continue commands.  Break, continue, and return are
     8447 * all handled by setting the evalskip flag.  The evaluation routines
     8448 * above all check this flag, and if it is set they start skipping
     8449 * commands rather than executing them.  The variable skipcount is
     8450 * the number of loops to break/continue, or the number of function
     8451 * levels to return.  (The latter is always 1.)  It should probably
     8452 * be an error to break out of more loops than exist, but it isn't
     8453 * in the standard shell so we don't make it one here.
     8454 */
     8455static int
     8456breakcmd(int argc, char **argv)
     8457{
     8458    int n = argc > 1 ? number(argv[1]) : 1;
     8459
     8460    if (n <= 0)
     8461        ash_msg_and_raise_error(illnum, argv[1]);
     8462    if (n > loopnest)
     8463        n = loopnest;
     8464    if (n > 0) {
     8465        evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
     8466        skipcount = n;
     8467    }
     8468    return 0;
     8469}
     8470
     8471
     8472/* ============ input.c
     8473 *
     8474 * This implements the input routines used by the parser.
     8475 */
     8476
     8477#define EOF_NLEFT -99           /* value of parsenleft when EOF pushed back */
     8478
     8479enum {
     8480    INPUT_PUSH_FILE = 1,
     8481    INPUT_NOFILE_OK = 2,
     8482};
     8483
     8484/*
     8485 * NEOF is returned by parsecmd when it encounters an end of file.  It
     8486 * must be distinct from NULL, so we use the address of a variable that
     8487 * happens to be handy.
     8488 */
     8489static int plinno = 1;                  /* input line number */
     8490/* number of characters left in input buffer */
     8491static int parsenleft;                  /* copy of parsefile->nleft */
     8492static int parselleft;                  /* copy of parsefile->lleft */
     8493/* next character in input buffer */
     8494static char *parsenextc;                /* copy of parsefile->nextc */
     8495
     8496static int checkkwd;
     8497/* values of checkkwd variable */
     8498#define CHKALIAS        0x1
     8499#define CHKKWD          0x2
     8500#define CHKNL           0x4
     8501
     8502static void
     8503popstring(void)
     8504{
     8505    struct strpush *sp = parsefile->strpush;
     8506
     8507    INT_OFF;
     8508#if ENABLE_ASH_ALIAS
     8509    if (sp->ap) {
     8510        if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
     8511            checkkwd |= CHKALIAS;
     8512        }
     8513        if (sp->string != sp->ap->val) {
     8514            free(sp->string);
     8515        }
     8516        sp->ap->flag &= ~ALIASINUSE;
     8517        if (sp->ap->flag & ALIASDEAD) {
     8518            unalias(sp->ap->name);
     8519        }
     8520    }
     8521#endif
     8522    parsenextc = sp->prevstring;
     8523    parsenleft = sp->prevnleft;
     8524/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
     8525    parsefile->strpush = sp->prev;
     8526    if (sp != &(parsefile->basestrpush))
     8527        free(sp);
     8528    INT_ON;
     8529}
     8530
     8531static int
     8532preadfd(void)
     8533{
     8534    int nr;
     8535    char *buf =  parsefile->buf;
     8536    parsenextc = buf;
     8537
     8538 retry:
     8539#if ENABLE_FEATURE_EDITING
     8540    if (!iflag || parsefile->fd)
     8541        nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
     8542    else {
     8543#if ENABLE_FEATURE_TAB_COMPLETION
     8544        line_input_state->path_lookup = pathval();
     8545#endif
     8546        nr = read_line_input(cmdedit_prompt, buf, BUFSIZ, line_input_state);
     8547        if (nr == 0) {
     8548            /* Ctrl+C pressed */
     8549            if (trap[SIGINT]) {
     8550                buf[0] = '\n';
     8551                buf[1] = '\0';
     8552                raise(SIGINT);
     8553                return 1;
     8554            }
     8555            goto retry;
     8556        }
     8557        if (nr < 0 && errno == 0) {
     8558            /* Ctrl+D presend */
     8559            nr = 0;
     8560        }
     8561    }
     8562#else
     8563    nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
     8564#endif
     8565
     8566    if (nr < 0) {
     8567        if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
     8568            int flags = fcntl(0, F_GETFL);
     8569            if (flags >= 0 && flags & O_NONBLOCK) {
     8570                flags &=~ O_NONBLOCK;
     8571                if (fcntl(0, F_SETFL, flags) >= 0) {
     8572                    out2str("sh: turning off NDELAY mode\n");
     8573                    goto retry;
     8574                }
     8575            }
     8576        }
     8577    }
     8578    return nr;
     8579}
     8580
     8581/*
     8582 * Refill the input buffer and return the next input character:
     8583 *
     8584 * 1) If a string was pushed back on the input, pop it;
     8585 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
     8586 *    from a string so we can't refill the buffer, return EOF.
     8587 * 3) If the is more stuff in this buffer, use it else call read to fill it.
     8588 * 4) Process input up to the next newline, deleting nul characters.
     8589 */
     8590static int
     8591preadbuffer(void)
     8592{
     8593    char *q;
     8594    int more;
     8595    char savec;
     8596
     8597    while (parsefile->strpush) {
     8598#if ENABLE_ASH_ALIAS
     8599        if (parsenleft == -1 && parsefile->strpush->ap &&
     8600            parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
     8601            return PEOA;
     8602        }
     8603#endif
     8604        popstring();
     8605        if (--parsenleft >= 0)
     8606            return signed_char2int(*parsenextc++);
     8607    }
     8608    if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
     8609        return PEOF;
     8610    flush_stdout_stderr();
     8611
     8612    more = parselleft;
     8613    if (more <= 0) {
     8614 again:
     8615        more = preadfd();
     8616        if (more <= 0) {
     8617            parselleft = parsenleft = EOF_NLEFT;
     8618            return PEOF;
     8619        }
     8620    }
     8621
     8622    q = parsenextc;
     8623
     8624    /* delete nul characters */
     8625    for (;;) {
     8626        int c;
     8627
     8628        more--;
     8629        c = *q;
     8630
     8631        if (!c)
     8632            memmove(q, q + 1, more);
     8633        else {
     8634            q++;
     8635            if (c == '\n') {
     8636                parsenleft = q - parsenextc - 1;
     8637                break;
     8638            }
     8639        }
     8640
     8641        if (more <= 0) {
     8642            parsenleft = q - parsenextc - 1;
     8643            if (parsenleft < 0)
     8644                goto again;
     8645            break;
     8646        }
     8647    }
     8648    parselleft = more;
     8649
     8650    savec = *q;
     8651    *q = '\0';
     8652
     8653    if (vflag) {
     8654        out2str(parsenextc);
     8655    }
     8656
     8657    *q = savec;
     8658
     8659    return signed_char2int(*parsenextc++);
     8660}
     8661
     8662#define pgetc_as_macro() (--parsenleft >= 0? signed_char2int(*parsenextc++) : preadbuffer())
     8663static int
     8664pgetc(void)
     8665{
     8666    return pgetc_as_macro();
     8667}
     8668
     8669#if ENABLE_ASH_OPTIMIZE_FOR_SIZE
     8670#define pgetc_macro() pgetc()
     8671#else
     8672#define pgetc_macro() pgetc_as_macro()
     8673#endif
     8674
     8675/*
     8676 * Same as pgetc(), but ignores PEOA.
     8677 */
     8678#if ENABLE_ASH_ALIAS
     8679static int
     8680pgetc2(void)
     8681{
     8682    int c;
     8683
     8684    do {
     8685        c = pgetc_macro();
     8686    } while (c == PEOA);
     8687    return c;
     8688}
     8689#else
     8690static int
     8691pgetc2(void)
     8692{
     8693    return pgetc_macro();
     8694}
     8695#endif
     8696
     8697/*
     8698 * Read a line from the script.
     8699 */
     8700static char *
     8701pfgets(char *line, int len)
     8702{
     8703    char *p = line;
     8704    int nleft = len;
     8705    int c;
     8706
     8707    while (--nleft > 0) {
     8708        c = pgetc2();
     8709        if (c == PEOF) {
     8710            if (p == line)
     8711                return NULL;
     8712            break;
     8713        }
     8714        *p++ = c;
     8715        if (c == '\n')
     8716            break;
     8717    }
     8718    *p = '\0';
     8719    return line;
     8720}
     8721
     8722/*
     8723 * Undo the last call to pgetc.  Only one character may be pushed back.
     8724 * PEOF may be pushed back.
     8725 */
     8726static void
     8727pungetc(void)
     8728{
     8729    parsenleft++;
     8730    parsenextc--;
     8731}
     8732
     8733/*
     8734 * Push a string back onto the input at this current parsefile level.
     8735 * We handle aliases this way.
     8736 */
     8737static void
     8738pushstring(char *s, void *ap)
     8739{
     8740    struct strpush *sp;
     8741    size_t len;
     8742
     8743    len = strlen(s);
     8744    INT_OFF;
     8745/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
     8746    if (parsefile->strpush) {
     8747        sp = ckmalloc(sizeof(struct strpush));
     8748        sp->prev = parsefile->strpush;
     8749        parsefile->strpush = sp;
     8750    } else
     8751        sp = parsefile->strpush = &(parsefile->basestrpush);
     8752    sp->prevstring = parsenextc;
     8753    sp->prevnleft = parsenleft;
     8754#if ENABLE_ASH_ALIAS
     8755    sp->ap = (struct alias *)ap;
     8756    if (ap) {
     8757        ((struct alias *)ap)->flag |= ALIASINUSE;
     8758        sp->string = s;
     8759    }
     8760#endif
     8761    parsenextc = s;
     8762    parsenleft = len;
     8763    INT_ON;
     8764}
     8765
     8766/*
     8767 * To handle the "." command, a stack of input files is used.  Pushfile
     8768 * adds a new entry to the stack and popfile restores the previous level.
     8769 */
     8770static void
     8771pushfile(void)
     8772{
     8773    struct parsefile *pf;
     8774
     8775    parsefile->nleft = parsenleft;
     8776    parsefile->lleft = parselleft;
     8777    parsefile->nextc = parsenextc;
     8778    parsefile->linno = plinno;
     8779    pf = ckmalloc(sizeof(*pf));
     8780    pf->prev = parsefile;
     8781    pf->fd = -1;
     8782    pf->strpush = NULL;
     8783    pf->basestrpush.prev = NULL;
     8784    parsefile = pf;
     8785}
     8786
     8787static void
     8788popfile(void)
     8789{
     8790    struct parsefile *pf = parsefile;
     8791
     8792    INT_OFF;
     8793    if (pf->fd >= 0)
     8794        close(pf->fd);
     8795    if (pf->buf)
     8796        free(pf->buf);
     8797    while (pf->strpush)
     8798        popstring();
     8799    parsefile = pf->prev;
     8800    free(pf);
     8801    parsenleft = parsefile->nleft;
     8802    parselleft = parsefile->lleft;
     8803    parsenextc = parsefile->nextc;
     8804    plinno = parsefile->linno;
     8805    INT_ON;
     8806}
     8807
     8808/*
     8809 * Return to top level.
     8810 */
     8811static void
     8812popallfiles(void)
     8813{
     8814    while (parsefile != &basepf)
     8815        popfile();
     8816}
     8817
     8818/*
     8819 * Close the file(s) that the shell is reading commands from.  Called
     8820 * after a fork is done.
     8821 */
     8822static void
     8823closescript(void)
     8824{
     8825    popallfiles();
     8826    if (parsefile->fd > 0) {
     8827        close(parsefile->fd);
     8828        parsefile->fd = 0;
     8829    }
     8830}
     8831
     8832/*
     8833 * Like setinputfile, but takes an open file descriptor.  Call this with
     8834 * interrupts off.
     8835 */
     8836static void
     8837setinputfd(int fd, int push)
     8838{
     8839    fcntl(fd, F_SETFD, FD_CLOEXEC);
     8840    if (push) {
     8841        pushfile();
     8842        parsefile->buf = 0;
     8843    }
     8844    parsefile->fd = fd;
     8845    if (parsefile->buf == NULL)
     8846        parsefile->buf = ckmalloc(IBUFSIZ);
     8847    parselleft = parsenleft = 0;
     8848    plinno = 1;
     8849}
     8850
     8851/*
     8852 * Set the input to take input from a file.  If push is set, push the
     8853 * old input onto the stack first.
     8854 */
     8855static int
     8856setinputfile(const char *fname, int flags)
     8857{
     8858    int fd;
     8859    int fd2;
     8860
     8861    INT_OFF;
     8862    fd = open(fname, O_RDONLY);
     8863    if (fd < 0) {
     8864        if (flags & INPUT_NOFILE_OK)
     8865            goto out;
     8866        ash_msg_and_raise_error("can't open %s", fname);
     8867    }
     8868    if (fd < 10) {
     8869        fd2 = copyfd(fd, 10);
     8870        close(fd);
     8871        if (fd2 < 0)
     8872            ash_msg_and_raise_error("out of file descriptors");
     8873        fd = fd2;
     8874    }
     8875    setinputfd(fd, flags & INPUT_PUSH_FILE);
     8876 out:
     8877    INT_ON;
     8878    return fd;
     8879}
     8880
     8881/*
     8882 * Like setinputfile, but takes input from a string.
     8883 */
     8884static void
     8885setinputstring(char *string)
     8886{
     8887    INT_OFF;
     8888    pushfile();
     8889    parsenextc = string;
     8890    parsenleft = strlen(string);
     8891    parsefile->buf = NULL;
     8892    plinno = 1;
     8893    INT_ON;
     8894}
     8895
     8896
     8897/* ============ mail.c
     8898 *
     8899 * Routines to check for mail.
     8900 */
     8901
     8902#if ENABLE_ASH_MAIL
    77768903
    77778904#define MAXMBOXES 10
     
    77828909static int mail_var_path_changed;
    77838910
    7784 
    7785 
    77868911/*
    77878912 * Print appropriate message(s) if mail has arrived.
     
    77908915 * so we just update the values.
    77918916 */
    7792 
    77938917static void
    77948918chkmail(void)
     
    78098933        if (*p == '\0')
    78108934            continue;
    7811         for (q = p ; *q ; q++);
    7812 #ifdef DEBUG
     8935        for (q = p; *q; q++);
     8936#if DEBUG
    78138937        if (q[-1] != '/')
    78148938            abort();
     
    78318955}
    78328956
    7833 
    78348957static void
    78358958changemail(const char *val)
     
    78388961}
    78398962
    7840 #endif /* CONFIG_ASH_MAIL */
    7841 
    7842 /*      main.c       */
    7843 
    7844 
    7845 #if PROFILE
    7846 static short profile_buf[16384];
    7847 extern int etext();
    7848 #endif
    7849 
    7850 static int isloginsh;
    7851 
    7852 static void read_profile(const char *);
    7853 
    7854 /*
    7855  * Main routine.  We initialize things, parse the arguments, execute
    7856  * profiles if we're a login shell, and then call cmdloop to execute
    7857  * commands.  The setjmp call sets up the location to jump to when an
    7858  * exception occurs.  When an exception occurs the variable "state"
    7859  * is used to figure out how far we had gotten.
    7860  */
    7861 
    7862 int
    7863 ash_main(int argc, char **argv)
    7864 {
    7865     char *shinit;
    7866     volatile int state;
    7867     struct jmploc jmploc;
    7868     struct stackmark smark;
    7869 
    7870 #ifdef __GLIBC__
    7871     dash_errno = __errno_location();
    7872 #endif
    7873 
    7874 #if PROFILE
    7875     monitor(4, etext, profile_buf, sizeof profile_buf, 50);
    7876 #endif
    7877     state = 0;
    7878     if (setjmp(jmploc.loc)) {
    7879         int e;
    7880         int s;
    7881 
    7882         reset();
    7883 
    7884         e = exception;
    7885         if (e == EXERROR)
    7886             exitstatus = 2;
    7887         s = state;
    7888         if (e == EXEXIT || s == 0 || iflag == 0 || shlvl)
    7889             exitshell();
    7890 
    7891         if (e == EXINT) {
    7892             outcslow('\n', stderr);
    7893         }
    7894         popstackmark(&smark);
    7895         FORCEINTON;                             /* enable interrupts */
    7896         if (s == 1)
    7897             goto state1;
    7898         else if (s == 2)
    7899             goto state2;
    7900         else if (s == 3)
    7901             goto state3;
    7902         else
    7903             goto state4;
    7904     }
    7905     handler = &jmploc;
    7906 #ifdef DEBUG
    7907     opentrace();
    7908     trputs("Shell args:  ");  trargs(argv);
    7909 #endif
    7910     rootpid = getpid();
    7911 
    7912 #ifdef CONFIG_ASH_RANDOM_SUPPORT
    7913     rseed = rootpid + ((time_t)time((time_t *)0));
    7914 #endif
    7915     init();
    7916     setstackmark(&smark);
    7917     procargs(argc, argv);
    7918 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
    7919     if ( iflag ) {
    7920         const char *hp = lookupvar("HISTFILE");
    7921 
    7922         if(hp == NULL ) {
    7923             hp = lookupvar("HOME");
    7924             if(hp != NULL) {
    7925                 char *defhp = concat_path_file(hp, ".ash_history");
    7926                 setvar("HISTFILE", defhp, 0);
    7927                 free(defhp);
    7928             }
    7929         }
    7930     }
    7931 #endif
    7932     if (argv[0] && argv[0][0] == '-')
    7933         isloginsh = 1;
    7934     if (isloginsh) {
    7935         state = 1;
    7936         read_profile("/etc/profile");
    7937 state1:
    7938         state = 2;
    7939         read_profile(".profile");
    7940     }
    7941 state2:
    7942     state = 3;
    7943     if (
    7944 #ifndef linux
    7945         getuid() == geteuid() && getgid() == getegid() &&
    7946 #endif
    7947         iflag
    7948     ) {
    7949         if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
    7950             read_profile(shinit);
    7951         }
    7952     }
    7953 state3:
    7954     state = 4;
    7955     if (minusc)
    7956         evalstring(minusc, 0);
    7957 
    7958     if (sflag || minusc == NULL) {
    7959 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
    7960         if ( iflag ) {
    7961         const char *hp = lookupvar("HISTFILE");
    7962 
    7963         if(hp != NULL )
    7964             load_history ( hp );
    7965         }
    7966 #endif
    7967 state4: /* XXX ??? - why isn't this before the "if" statement */
    7968         cmdloop(1);
    7969     }
    7970 #if PROFILE
    7971     monitor(0);
    7972 #endif
    7973 #if GPROF
    7974     {
    7975         extern void _mcleanup(void);
    7976         _mcleanup();
    7977     }
    7978 #endif
    7979     exitshell();
    7980     /* NOTREACHED */
    7981 }
    7982 
    7983 
    7984 /*
    7985  * Read and execute commands.  "Top" is nonzero for the top level command
    7986  * loop; it turns on prompting if the shell is interactive.
    7987  */
    7988 
    7989 static int
    7990 cmdloop(int top)
    7991 {
    7992     union node *n;
    7993     struct stackmark smark;
    7994     int inter;
    7995     int numeof = 0;
    7996 
    7997     TRACE(("cmdloop(%d) called\n", top));
    7998     for (;;) {
    7999         int skip;
    8000 
    8001         setstackmark(&smark);
    8002 #if JOBS
    8003         if (jobctl)
    8004             showjobs(stderr, SHOW_CHANGED);
    8005 #endif
    8006         inter = 0;
    8007         if (iflag && top) {
    8008             inter++;
    8009 #ifdef CONFIG_ASH_MAIL
    8010             chkmail();
    8011 #endif
    8012         }
    8013         n = parsecmd(inter);
    8014         /* showtree(n); DEBUG */
    8015         if (n == NEOF) {
    8016             if (!top || numeof >= 50)
    8017                 break;
    8018             if (!stoppedjobs()) {
    8019                 if (!Iflag)
    8020                     break;
    8021                 out2str("\nUse \"exit\" to leave shell.\n");
    8022             }
    8023             numeof++;
    8024         } else if (nflag == 0) {
    8025             job_warning = (job_warning == 2) ? 1 : 0;
    8026             numeof = 0;
    8027             evaltree(n, 0);
    8028         }
    8029         popstackmark(&smark);
    8030         skip = evalskip;
    8031 
    8032         if (skip) {
    8033             evalskip = 0;
    8034             return skip & SKIPEVAL;
    8035         }
    8036     }
    8037 
    8038     return 0;
    8039 }
    8040 
    8041 
    8042 /*
    8043  * Read /etc/profile or .profile.  Return on error.
    8044  */
    8045 
    8046 static void
    8047 read_profile(const char *name)
    8048 {
    8049     int skip;
    8050 
    8051     if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
    8052         return;
    8053 
    8054     skip = cmdloop(0);
    8055     popfile();
    8056 
    8057     if (skip)
    8058         exitshell();
    8059 }
    8060 
    8061 
    8062 /*
    8063  * Read a file containing shell functions.
    8064  */
    8065 
    8066 static void
    8067 readcmdfile(char *name)
    8068 {
    8069     setinputfile(name, INPUT_PUSH_FILE);
    8070     cmdloop(0);
    8071     popfile();
    8072 }
    8073 
    8074 
    8075 /*
    8076  * Take commands from a file.  To be compatible we should do a path
    8077  * search for the file, which is necessary to find sub-commands.
    8078  */
    8079 
    8080 static inline char *
    8081 find_dot_file(char *name)
    8082 {
    8083     char *fullname;
    8084     const char *path = pathval();
    8085     struct stat statb;
    8086 
    8087     /* don't try this for absolute or relative paths */
    8088     if (strchr(name, '/'))
    8089         return name;
    8090 
    8091     while ((fullname = padvance(&path, name)) != NULL) {
    8092         if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
    8093             /*
    8094              * Don't bother freeing here, since it will
    8095              * be freed by the caller.
    8096              */
    8097             return fullname;
    8098         }
    8099         stunalloc(fullname);
    8100     }
    8101 
    8102     /* not found in the PATH */
    8103     sh_error(not_found_msg, name);
    8104     /* NOTREACHED */
    8105 }
    8106 
    8107 static int dotcmd(int argc, char **argv)
    8108 {
    8109     struct strlist *sp;
    8110     volatile struct shparam saveparam;
    8111     int status = 0;
    8112 
    8113     for (sp = cmdenviron; sp; sp = sp->next)
    8114         setvareq(bb_xstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
    8115 
    8116     if (argc >= 2) {        /* That's what SVR2 does */
    8117         char *fullname;
    8118 
    8119         fullname = find_dot_file(argv[1]);
    8120 
    8121         if (argc > 2) {
    8122             saveparam = shellparam;
    8123             shellparam.malloc = 0;
    8124             shellparam.nparam = argc - 2;
    8125             shellparam.p = argv + 2;
    8126         };
    8127 
    8128         setinputfile(fullname, INPUT_PUSH_FILE);
    8129         commandname = fullname;
    8130         cmdloop(0);
    8131         popfile();
    8132 
    8133         if (argc > 2) {
    8134             freeparam(&shellparam);
    8135             shellparam = saveparam;
    8136         };
    8137         status = exitstatus;
    8138     }
    8139     return status;
    8140 }
    8141 
    8142 
    8143 static int
    8144 exitcmd(int argc, char **argv)
    8145 {
    8146     if (stoppedjobs())
    8147         return 0;
    8148     if (argc > 1)
    8149         exitstatus = number(argv[1]);
    8150     exraise(EXEXIT);
    8151     /* NOTREACHED */
    8152 }
    8153 
    8154 #ifdef CONFIG_ASH_BUILTIN_ECHO
    8155 static int
    8156 echocmd(int argc, char **argv)
    8157 {
    8158     return bb_echo(argc, argv);
    8159 }
    8160 #endif
    8161 
    8162 #ifdef CONFIG_ASH_BUILTIN_TEST
    8163 static int
    8164 testcmd(int argc, char **argv)
    8165 {
    8166     return bb_test(argc, argv);
    8167 }
    8168 #endif
    8169 
    8170 /*      memalloc.c        */
    8171 
    8172 /*
    8173  * Same for malloc, realloc, but returns an error when out of space.
    8174  */
    8175 
    8176 static pointer
    8177 ckrealloc(pointer p, size_t nbytes)
    8178 {
    8179     p = realloc(p, nbytes);
    8180     if (p == NULL)
    8181         sh_error(bb_msg_memory_exhausted);
    8182     return p;
    8183 }
    8184 
    8185 static pointer
    8186 ckmalloc(size_t nbytes)
    8187 {
    8188     return ckrealloc(NULL, nbytes);
    8189 }
    8190 
    8191 /*
    8192  * Make a copy of a string in safe storage.
    8193  */
    8194 
    8195 static char *
    8196 savestr(const char *s)
    8197 {
    8198     char *p = strdup(s);
    8199     if (!p)
    8200         sh_error(bb_msg_memory_exhausted);
    8201     return p;
    8202 }
    8203 
    8204 
    8205 /*
    8206  * Parse trees for commands are allocated in lifo order, so we use a stack
    8207  * to make this more efficient, and also to avoid all sorts of exception
    8208  * handling code to handle interrupts in the middle of a parse.
    8209  *
    8210  * The size 504 was chosen because the Ultrix malloc handles that size
    8211  * well.
    8212  */
    8213 
    8214 
    8215 static pointer
    8216 stalloc(size_t nbytes)
    8217 {
    8218     char *p;
    8219     size_t aligned;
    8220 
    8221     aligned = SHELL_ALIGN(nbytes);
    8222     if (aligned > stacknleft) {
    8223         size_t len;
    8224         size_t blocksize;
    8225         struct stack_block *sp;
    8226 
    8227         blocksize = aligned;
    8228         if (blocksize < MINSIZE)
    8229             blocksize = MINSIZE;
    8230         len = sizeof(struct stack_block) - MINSIZE + blocksize;
    8231         if (len < blocksize)
    8232             sh_error(bb_msg_memory_exhausted);
    8233         INTOFF;
    8234         sp = ckmalloc(len);
    8235         sp->prev = stackp;
    8236         stacknxt = sp->space;
    8237         stacknleft = blocksize;
    8238         sstrend = stacknxt + blocksize;
    8239         stackp = sp;
    8240         INTON;
    8241     }
    8242     p = stacknxt;
    8243     stacknxt += aligned;
    8244     stacknleft -= aligned;
    8245     return p;
    8246 }
    8247 
    8248 
    8249 void
    8250 stunalloc(pointer p)
    8251 {
    8252 #ifdef DEBUG
    8253     if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
    8254         write(2, "stunalloc\n", 10);
    8255         abort();
    8256     }
    8257 #endif
    8258     stacknleft += stacknxt - (char *)p;
    8259     stacknxt = p;
    8260 }
    8261 
    8262 
    8263 void
    8264 setstackmark(struct stackmark *mark)
    8265 {
    8266     mark->stackp = stackp;
    8267     mark->stacknxt = stacknxt;
    8268     mark->stacknleft = stacknleft;
    8269     mark->marknext = markp;
    8270     markp = mark;
    8271 }
    8272 
    8273 
    8274 void
    8275 popstackmark(struct stackmark *mark)
    8276 {
    8277     struct stack_block *sp;
    8278 
    8279     INTOFF;
    8280     markp = mark->marknext;
    8281     while (stackp != mark->stackp) {
    8282         sp = stackp;
    8283         stackp = sp->prev;
    8284         ckfree(sp);
    8285     }
    8286     stacknxt = mark->stacknxt;
    8287     stacknleft = mark->stacknleft;
    8288     sstrend = mark->stacknxt + mark->stacknleft;
    8289     INTON;
    8290 }
    8291 
    8292 
    8293 /*
    8294  * When the parser reads in a string, it wants to stick the string on the
    8295  * stack and only adjust the stack pointer when it knows how big the
    8296  * string is.  Stackblock (defined in stack.h) returns a pointer to a block
    8297  * of space on top of the stack and stackblocklen returns the length of
    8298  * this block.  Growstackblock will grow this space by at least one byte,
    8299  * possibly moving it (like realloc).  Grabstackblock actually allocates the
    8300  * part of the block that has been used.
    8301  */
    8302 
    8303 void
    8304 growstackblock(void)
    8305 {
    8306     size_t newlen;
    8307 
    8308     newlen = stacknleft * 2;
    8309     if (newlen < stacknleft)
    8310         sh_error(bb_msg_memory_exhausted);
    8311     if (newlen < 128)
    8312         newlen += 128;
    8313 
    8314     if (stacknxt == stackp->space && stackp != &stackbase) {
    8315         struct stack_block *oldstackp;
    8316         struct stackmark *xmark;
    8317         struct stack_block *sp;
    8318         struct stack_block *prevstackp;
    8319         size_t grosslen;
    8320 
    8321         INTOFF;
    8322         oldstackp = stackp;
    8323         sp = stackp;
    8324         prevstackp = sp->prev;
    8325         grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
    8326         sp = ckrealloc((pointer)sp, grosslen);
    8327         sp->prev = prevstackp;
    8328         stackp = sp;
    8329         stacknxt = sp->space;
    8330         stacknleft = newlen;
    8331         sstrend = sp->space + newlen;
    8332 
    8333         /*
    8334          * Stack marks pointing to the start of the old block
    8335          * must be relocated to point to the new block
    8336          */
    8337         xmark = markp;
    8338         while (xmark != NULL && xmark->stackp == oldstackp) {
    8339             xmark->stackp = stackp;
    8340             xmark->stacknxt = stacknxt;
    8341             xmark->stacknleft = stacknleft;
    8342             xmark = xmark->marknext;
    8343         }
    8344         INTON;
    8345     } else {
    8346         char *oldspace = stacknxt;
    8347         int oldlen = stacknleft;
    8348         char *p = stalloc(newlen);
    8349 
    8350         /* free the space we just allocated */
    8351         stacknxt = memcpy(p, oldspace, oldlen);
    8352         stacknleft += newlen;
    8353     }
    8354 }
    8355 
    8356 static inline void
    8357 grabstackblock(size_t len)
    8358 {
    8359     len = SHELL_ALIGN(len);
    8360     stacknxt += len;
    8361     stacknleft -= len;
    8362 }
    8363 
    8364 /*
    8365  * The following routines are somewhat easier to use than the above.
    8366  * The user declares a variable of type STACKSTR, which may be declared
    8367  * to be a register.  The macro STARTSTACKSTR initializes things.  Then
    8368  * the user uses the macro STPUTC to add characters to the string.  In
    8369  * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
    8370  * grown as necessary.  When the user is done, she can just leave the
    8371  * string there and refer to it using stackblock().  Or she can allocate
    8372  * the space for it using grabstackstr().  If it is necessary to allow
    8373  * someone else to use the stack temporarily and then continue to grow
    8374  * the string, the user should use grabstack to allocate the space, and
    8375  * then call ungrabstr(p) to return to the previous mode of operation.
    8376  *
    8377  * USTPUTC is like STPUTC except that it doesn't check for overflow.
    8378  * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
    8379  * is space for at least one character.
    8380  */
    8381 
    8382 void *
    8383 growstackstr(void)
    8384 {
    8385     size_t len = stackblocksize();
    8386     if (herefd >= 0 && len >= 1024) {
    8387         bb_full_write(herefd, stackblock(), len);
    8388         return stackblock();
    8389     }
    8390     growstackblock();
    8391     return stackblock() + len;
    8392 }
    8393 
    8394 /*
    8395  * Called from CHECKSTRSPACE.
    8396  */
    8397 
    8398 char *
    8399 makestrspace(size_t newlen, char *p)
    8400 {
    8401     size_t len = p - stacknxt;
    8402     size_t size = stackblocksize();
    8403 
    8404     for (;;) {
    8405         size_t nleft;
    8406 
    8407         size = stackblocksize();
    8408         nleft = size - len;
    8409         if (nleft >= newlen)
    8410             break;
    8411         growstackblock();
    8412     }
    8413     return stackblock() + len;
    8414 }
    8415 
    8416 char *
    8417 stnputs(const char *s, size_t n, char *p)
    8418 {
    8419     p = makestrspace(n, p);
    8420     p = mempcpy(p, s, n);
    8421     return p;
    8422 }
    8423 
    8424 char *
    8425 stputs(const char *s, char *p)
    8426 {
    8427     return stnputs(s, strlen(s), p);
    8428 }
    8429 
    8430 /*      mystring.c   */
    8431 
    8432 /*
    8433  * String functions.
    8434  *
    8435  *      number(s)               Convert a string of digits to an integer.
    8436  *      is_number(s)            Return true if s is a string of digits.
    8437  */
    8438 
    8439 /*
    8440  * prefix -- see if pfx is a prefix of string.
    8441  */
    8442 
    8443 char *
    8444 prefix(const char *string, const char *pfx)
    8445 {
    8446     while (*pfx) {
    8447         if (*pfx++ != *string++)
    8448             return 0;
    8449     }
    8450     return (char *) string;
    8451 }
    8452 
    8453 
    8454 /*
    8455  * Convert a string of digits to an integer, printing an error message on
    8456  * failure.
    8457  */
    8458 
    8459 int
    8460 number(const char *s)
    8461 {
    8462 
    8463     if (! is_number(s))
    8464         sh_error(illnum, s);
    8465     return atoi(s);
    8466 }
    8467 
    8468 
    8469 /*
    8470  * Check for a valid number.  This should be elsewhere.
    8471  */
    8472 
    8473 int
    8474 is_number(const char *p)
    8475 {
    8476     do {
    8477         if (! is_digit(*p))
    8478             return 0;
    8479     } while (*++p != '\0');
    8480     return 1;
    8481 }
    8482 
    8483 
    8484 /*
    8485  * Produce a possibly single quoted string suitable as input to the shell.
    8486  * The return string is allocated on the stack.
    8487  */
    8488 
    8489 char *
    8490 single_quote(const char *s) {
    8491     char *p;
    8492 
    8493     STARTSTACKSTR(p);
    8494 
    8495     do {
    8496         char *q;
    8497         size_t len;
    8498 
    8499         len = strchrnul(s, '\'') - s;
    8500 
    8501         q = p = makestrspace(len + 3, p);
    8502 
    8503         *q++ = '\'';
    8504         q = mempcpy(q, s, len);
    8505         *q++ = '\'';
    8506         s += len;
    8507 
    8508         STADJUST(q - p, p);
    8509 
    8510         len = strspn(s, "'");
    8511         if (!len)
    8512             break;
    8513 
    8514         q = p = makestrspace(len + 3, p);
    8515 
    8516         *q++ = '"';
    8517         q = mempcpy(q, s, len);
    8518         *q++ = '"';
    8519         s += len;
    8520 
    8521         STADJUST(q - p, p);
    8522     } while (*s);
    8523 
    8524     USTPUTC(0, p);
    8525 
    8526     return stackblock();
    8527 }
    8528 
    8529 /*
    8530  * Like strdup but works with the ash stack.
    8531  */
    8532 
    8533 char *
    8534 sstrdup(const char *p)
    8535 {
    8536     size_t len = strlen(p) + 1;
    8537     return memcpy(stalloc(len), p, len);
    8538 }
    8539 
    8540 
    8541 static void
    8542 calcsize(union node *n)
    8543 {
    8544       if (n == NULL)
    8545         return;
    8546       funcblocksize += nodesize[n->type];
    8547       switch (n->type) {
    8548       case NCMD:
    8549         calcsize(n->ncmd.redirect);
    8550         calcsize(n->ncmd.args);
    8551         calcsize(n->ncmd.assign);
    8552         break;
    8553       case NPIPE:
    8554         sizenodelist(n->npipe.cmdlist);
    8555         break;
    8556       case NREDIR:
    8557       case NBACKGND:
    8558       case NSUBSHELL:
    8559         calcsize(n->nredir.redirect);
    8560         calcsize(n->nredir.n);
    8561         break;
    8562       case NAND:
    8563       case NOR:
    8564       case NSEMI:
    8565       case NWHILE:
    8566       case NUNTIL:
    8567         calcsize(n->nbinary.ch2);
    8568         calcsize(n->nbinary.ch1);
    8569         break;
    8570       case NIF:
    8571         calcsize(n->nif.elsepart);
    8572         calcsize(n->nif.ifpart);
    8573         calcsize(n->nif.test);
    8574         break;
    8575       case NFOR:
    8576         funcstringsize += strlen(n->nfor.var) + 1;
    8577         calcsize(n->nfor.body);
    8578         calcsize(n->nfor.args);
    8579         break;
    8580       case NCASE:
    8581         calcsize(n->ncase.cases);
    8582         calcsize(n->ncase.expr);
    8583         break;
    8584       case NCLIST:
    8585         calcsize(n->nclist.body);
    8586         calcsize(n->nclist.pattern);
    8587         calcsize(n->nclist.next);
    8588         break;
    8589       case NDEFUN:
    8590       case NARG:
    8591         sizenodelist(n->narg.backquote);
    8592         funcstringsize += strlen(n->narg.text) + 1;
    8593         calcsize(n->narg.next);
    8594         break;
    8595       case NTO:
    8596       case NCLOBBER:
    8597       case NFROM:
    8598       case NFROMTO:
    8599       case NAPPEND:
    8600         calcsize(n->nfile.fname);
    8601         calcsize(n->nfile.next);
    8602         break;
    8603       case NTOFD:
    8604       case NFROMFD:
    8605         calcsize(n->ndup.vname);
    8606         calcsize(n->ndup.next);
    8607         break;
    8608       case NHERE:
    8609       case NXHERE:
    8610         calcsize(n->nhere.doc);
    8611         calcsize(n->nhere.next);
    8612         break;
    8613       case NNOT:
    8614         calcsize(n->nnot.com);
    8615         break;
    8616       };
    8617 }
    8618 
    8619 
    8620 static void
    8621 sizenodelist(struct nodelist *lp)
    8622 {
    8623     while (lp) {
    8624         funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
    8625         calcsize(lp->n);
    8626         lp = lp->next;
    8627     }
    8628 }
    8629 
    8630 
    8631 static union node *
    8632 copynode(union node *n)
    8633 {
    8634       union node *new;
    8635 
    8636       if (n == NULL)
    8637         return NULL;
    8638       new = funcblock;
    8639       funcblock = (char *) funcblock + nodesize[n->type];
    8640       switch (n->type) {
    8641       case NCMD:
    8642         new->ncmd.redirect = copynode(n->ncmd.redirect);
    8643         new->ncmd.args = copynode(n->ncmd.args);
    8644         new->ncmd.assign = copynode(n->ncmd.assign);
    8645         break;
    8646       case NPIPE:
    8647         new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
    8648         new->npipe.backgnd = n->npipe.backgnd;
    8649         break;
    8650       case NREDIR:
    8651       case NBACKGND:
    8652       case NSUBSHELL:
    8653         new->nredir.redirect = copynode(n->nredir.redirect);
    8654         new->nredir.n = copynode(n->nredir.n);
    8655         break;
    8656       case NAND:
    8657       case NOR:
    8658       case NSEMI:
    8659       case NWHILE:
    8660       case NUNTIL:
    8661         new->nbinary.ch2 = copynode(n->nbinary.ch2);
    8662         new->nbinary.ch1 = copynode(n->nbinary.ch1);
    8663         break;
    8664       case NIF:
    8665         new->nif.elsepart = copynode(n->nif.elsepart);
    8666         new->nif.ifpart = copynode(n->nif.ifpart);
    8667         new->nif.test = copynode(n->nif.test);
    8668         break;
    8669       case NFOR:
    8670         new->nfor.var = nodesavestr(n->nfor.var);
    8671         new->nfor.body = copynode(n->nfor.body);
    8672         new->nfor.args = copynode(n->nfor.args);
    8673         break;
    8674       case NCASE:
    8675         new->ncase.cases = copynode(n->ncase.cases);
    8676         new->ncase.expr = copynode(n->ncase.expr);
    8677         break;
    8678       case NCLIST:
    8679         new->nclist.body = copynode(n->nclist.body);
    8680         new->nclist.pattern = copynode(n->nclist.pattern);
    8681         new->nclist.next = copynode(n->nclist.next);
    8682         break;
    8683       case NDEFUN:
    8684       case NARG:
    8685         new->narg.backquote = copynodelist(n->narg.backquote);
    8686         new->narg.text = nodesavestr(n->narg.text);
    8687         new->narg.next = copynode(n->narg.next);
    8688         break;
    8689       case NTO:
    8690       case NCLOBBER:
    8691       case NFROM:
    8692       case NFROMTO:
    8693       case NAPPEND:
    8694         new->nfile.fname = copynode(n->nfile.fname);
    8695         new->nfile.fd = n->nfile.fd;
    8696         new->nfile.next = copynode(n->nfile.next);
    8697         break;
    8698       case NTOFD:
    8699       case NFROMFD:
    8700         new->ndup.vname = copynode(n->ndup.vname);
    8701         new->ndup.dupfd = n->ndup.dupfd;
    8702         new->ndup.fd = n->ndup.fd;
    8703         new->ndup.next = copynode(n->ndup.next);
    8704         break;
    8705       case NHERE:
    8706       case NXHERE:
    8707         new->nhere.doc = copynode(n->nhere.doc);
    8708         new->nhere.fd = n->nhere.fd;
    8709         new->nhere.next = copynode(n->nhere.next);
    8710         break;
    8711       case NNOT:
    8712         new->nnot.com = copynode(n->nnot.com);
    8713         break;
    8714       };
    8715       new->type = n->type;
    8716     return new;
    8717 }
    8718 
    8719 
    8720 static struct nodelist *
    8721 copynodelist(struct nodelist *lp)
    8722 {
    8723     struct nodelist *start;
    8724     struct nodelist **lpp;
    8725 
    8726     lpp = &start;
    8727     while (lp) {
    8728         *lpp = funcblock;
    8729         funcblock = (char *) funcblock +
    8730             SHELL_ALIGN(sizeof(struct nodelist));
    8731         (*lpp)->n = copynode(lp->n);
    8732         lp = lp->next;
    8733         lpp = &(*lpp)->next;
    8734     }
    8735     *lpp = NULL;
    8736     return start;
    8737 }
    8738 
    8739 
    8740 static char *
    8741 nodesavestr(char   *s)
    8742 {
    8743     char   *rtn = funcstring;
    8744 
    8745     funcstring = stpcpy(funcstring, s) + 1;
    8746     return rtn;
    8747 }
    8748 
    8749 
    8750 /*
    8751  * Free a parse tree.
    8752  */
    8753 
    8754 static void
    8755 freefunc(struct funcnode *f)
    8756 {
    8757     if (f && --f->count < 0)
    8758         ckfree(f);
    8759 }
    8760 
    8761 
    8762 static void options(int);
    8763 static void setoption(int, int);
    8764 
    8765 
    8766 /*
    8767  * Process the shell command line arguments.
    8768  */
    8769 
    8770 void
    8771 procargs(int argc, char **argv)
    8772 {
    8773     int i;
    8774     const char *xminusc;
    8775     char **xargv;
    8776 
    8777     xargv = argv;
    8778     arg0 = xargv[0];
    8779     if (argc > 0)
    8780         xargv++;
    8781     for (i = 0; i < NOPTS; i++)
    8782         optlist[i] = 2;
    8783     argptr = xargv;
    8784     options(1);
    8785     xargv = argptr;
    8786     xminusc = minusc;
    8787     if (*xargv == NULL) {
    8788         if (xminusc)
    8789             sh_error(bb_msg_requires_arg, "-c");
    8790         sflag = 1;
    8791     }
    8792     if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
    8793         iflag = 1;
    8794     if (mflag == 2)
    8795         mflag = iflag;
    8796     for (i = 0; i < NOPTS; i++)
    8797         if (optlist[i] == 2)
    8798             optlist[i] = 0;
    8799 #if DEBUG == 2
    8800     debug = 1;
    8801 #endif
    8802     /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
    8803     if (xminusc) {
    8804         minusc = *xargv++;
    8805         if (*xargv)
    8806             goto setarg0;
    8807     } else if (!sflag) {
    8808         setinputfile(*xargv, 0);
    8809 setarg0:
    8810         arg0 = *xargv++;
    8811         commandname = arg0;
    8812     }
    8813 
    8814     shellparam.p = xargv;
    8815 #ifdef CONFIG_ASH_GETOPTS
     8963#endif /* ASH_MAIL */
     8964
     8965
     8966/* ============ ??? */
     8967
     8968/*
     8969 * Set the shell parameters.
     8970 */
     8971static void
     8972setparam(char **argv)
     8973{
     8974    char **newparam;
     8975    char **ap;
     8976    int nparam;
     8977
     8978    for (nparam = 0; argv[nparam]; nparam++);
     8979    ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
     8980    while (*argv) {
     8981        *ap++ = ckstrdup(*argv++);
     8982    }
     8983    *ap = NULL;
     8984    freeparam(&shellparam);
     8985    shellparam.malloc = 1;
     8986    shellparam.nparam = nparam;
     8987    shellparam.p = newparam;
     8988#if ENABLE_ASH_GETOPTS
    88168989    shellparam.optind = 1;
    88178990    shellparam.optoff = -1;
    88188991#endif
    8819     /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
    8820     while (*xargv) {
    8821         shellparam.nparam++;
    8822         xargv++;
    8823     }
    8824     optschanged();
    8825 }
    8826 
    8827 
    8828 void
    8829 optschanged(void)
    8830 {
    8831 #ifdef DEBUG
    8832     opentrace();
    8833 #endif
    8834     setinteractive(iflag);
    8835     setjobctl(mflag);
    8836     setvimode(viflag);
    8837 }
    8838 
    8839 static inline void
     8992}
     8993
     8994/*
     8995 * Process shell options.  The global variable argptr contains a pointer
     8996 * to the argument list; we advance it past the options.
     8997 */
     8998static void
    88408999minus_o(char *name, int val)
    88419000{
    88429001    int i;
    88439002
    8844     if (name == NULL) {
    8845         out1str("Current option settings\n");
    8846         for (i = 0; i < NOPTS; i++)
    8847             out1fmt("%-16s%s\n", optnames(i),
    8848                 optlist[i] ? "on" : "off");
    8849     } else {
    8850         for (i = 0; i < NOPTS; i++)
    8851             if (equal(name, optnames(i))) {
     9003    if (name) {
     9004        for (i = 0; i < NOPTS; i++) {
     9005            if (strcmp(name, optnames(i)) == 0) {
    88529006                optlist[i] = val;
    88539007                return;
    88549008            }
    8855         sh_error("Illegal option -o %s", name);
    8856     }
    8857 }
    8858 
    8859 /*
    8860  * Process shell options.  The global variable argptr contains a pointer
    8861  * to the argument list; we advance it past the options.
    8862  */
    8863 
     9009        }
     9010        ash_msg_and_raise_error("illegal option -o %s", name);
     9011    }
     9012    out1str("Current option settings\n");
     9013    for (i = 0; i < NOPTS; i++)
     9014        out1fmt("%-16s%s\n", optnames(i),
     9015                optlist[i] ? "on" : "off");
     9016}
     9017static void
     9018setoption(int flag, int val)
     9019{
     9020    int i;
     9021
     9022    for (i = 0; i < NOPTS; i++) {
     9023        if (optletters(i) == flag) {
     9024            optlist[i] = val;
     9025            return;
     9026        }
     9027    }
     9028    ash_msg_and_raise_error("illegal option -%c", flag);
     9029    /* NOTREACHED */
     9030}
    88649031static void
    88659032options(int cmdline)
     
    88729039        minusc = NULL;
    88739040    while ((p = *argptr) != NULL) {
     9041        c = *p++;
     9042        if (c != '-' && c != '+')
     9043            break;
    88749044        argptr++;
    8875         if ((c = *p++) == '-') {
     9045        val = 0; /* val = 0 if c == '+' */
     9046        if (c == '-') {
    88769047            val = 1;
    8877             if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
     9048            if (p[0] == '\0' || LONE_DASH(p)) {
    88789049                if (!cmdline) {
    88799050                    /* "-" means turn off -x and -v */
     
    88869057                break;    /* "-" or  "--" terminates options */
    88879058            }
    8888         } else if (c == '+') {
    8889             val = 0;
    8890         } else {
    8891             argptr--;
    8892             break;
    8893         }
     9059        }
     9060        /* first char was + or - */
    88949061        while ((c = *p++) != '\0') {
     9062            /* bash 3.2 indeed handles -c CMD and +c CMD the same */
    88959063            if (c == 'c' && cmdline) {
    8896                 minusc = p;     /* command is after shell args*/
     9064                minusc = p;     /* command is after shell args */
    88979065            } else if (c == 'o') {
    88989066                minus_o(*argptr, val);
    88999067                if (*argptr)
    89009068                    argptr++;
    8901             } else if (cmdline && (c == '-')) {     // long options
     9069            } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
     9070                isloginsh = 1;
     9071            /* bash does not accept +-login, we also won't */
     9072            } else if (cmdline && val && (c == '-')) { /* long options */
    89029073                if (strcmp(p, "login") == 0)
    89039074                    isloginsh = 1;
     
    89109081}
    89119082
    8912 
    8913 static void
    8914 setoption(int flag, int val)
    8915 {
    8916     int i;
    8917 
    8918     for (i = 0; i < NOPTS; i++)
    8919         if (optletters(i) == flag) {
    8920             optlist[i] = val;
    8921             return;
    8922         }
    8923     sh_error("Illegal option -%c", flag);
    8924     /* NOTREACHED */
    8925 }
    8926 
    8927 
    8928 
    8929 /*
    8930  * Set the shell parameters.
    8931  */
    8932 
    8933 void
    8934 setparam(char **argv)
    8935 {
    8936     char **newparam;
    8937     char **ap;
    8938     int nparam;
    8939 
    8940     for (nparam = 0 ; argv[nparam] ; nparam++);
    8941     ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
    8942     while (*argv) {
    8943         *ap++ = savestr(*argv++);
    8944     }
    8945     *ap = NULL;
    8946     freeparam(&shellparam);
    8947     shellparam.malloc = 1;
    8948     shellparam.nparam = nparam;
    8949     shellparam.p = newparam;
    8950 #ifdef CONFIG_ASH_GETOPTS
    8951     shellparam.optind = 1;
    8952     shellparam.optoff = -1;
    8953 #endif
    8954 }
    8955 
    8956 
    8957 /*
    8958  * Free the list of positional parameters.
    8959  */
    8960 
    8961 void
    8962 freeparam(volatile struct shparam *param)
    8963 {
    8964     char **ap;
    8965 
    8966     if (param->malloc) {
    8967         for (ap = param->p ; *ap ; ap++)
    8968             ckfree(*ap);
    8969         ckfree(param->p);
    8970     }
    8971 }
    8972 
    8973 
    8974 
    89759083/*
    89769084 * The shift builtin command.
    89779085 */
    8978 
    8979 int
     9086static int
    89809087shiftcmd(int argc, char **argv)
    89819088{
     
    89879094        n = number(argv[1]);
    89889095    if (n > shellparam.nparam)
    8989         sh_error("can't shift that many");
    8990     INTOFF;
     9096        ash_msg_and_raise_error("can't shift that many");
     9097    INT_OFF;
    89919098    shellparam.nparam -= n;
    8992     for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
     9099    for (ap1 = shellparam.p; --n >= 0; ap1++) {
    89939100        if (shellparam.malloc)
    8994             ckfree(*ap1);
     9101            free(*ap1);
    89959102    }
    89969103    ap2 = shellparam.p;
    89979104    while ((*ap2++ = *ap1++) != NULL);
    8998 #ifdef CONFIG_ASH_GETOPTS
     9105#if ENABLE_ASH_GETOPTS
    89999106    shellparam.optind = 1;
    90009107    shellparam.optoff = -1;
    90019108#endif
    9002     INTON;
     9109    INT_ON;
    90039110    return 0;
    90049111}
    90059112
    9006 
     9113/*
     9114 * POSIX requires that 'set' (but not export or readonly) output the
     9115 * variables in lexicographic order - by the locale's collating order (sigh).
     9116 * Maybe we could keep them in an ordered balanced binary tree
     9117 * instead of hashed lists.
     9118 * For now just roll 'em through qsort for printing...
     9119 */
     9120static int
     9121showvars(const char *sep_prefix, int on, int off)
     9122{
     9123    const char *sep;
     9124    char **ep, **epend;
     9125
     9126    ep = listvars(on, off, &epend);
     9127    qsort(ep, epend - ep, sizeof(char *), vpcmp);
     9128
     9129    sep = *sep_prefix ? " " : sep_prefix;
     9130
     9131    for (; ep < epend; ep++) {
     9132        const char *p;
     9133        const char *q;
     9134
     9135        p = strchrnul(*ep, '=');
     9136        q = nullstr;
     9137        if (*p)
     9138            q = single_quote(++p);
     9139        out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
     9140    }
     9141    return 0;
     9142}
    90079143
    90089144/*
    90099145 * The set command builtin.
    90109146 */
    9011 
    9012 int
     9147static int
    90139148setcmd(int argc, char **argv)
    90149149{
    90159150    if (argc == 1)
    90169151        return showvars(nullstr, 0, VUNSET);
    9017     INTOFF;
     9152    INT_OFF;
    90189153    options(0);
    90199154    optschanged();
     
    90219156        setparam(argptr);
    90229157    }
    9023     INTON;
     9158    INT_ON;
    90249159    return 0;
    90259160}
    90269161
    9027 
    9028 #ifdef CONFIG_ASH_GETOPTS
    9029 static void
    9030 getoptsreset(const char *value)
    9031 {
    9032     shellparam.optind = number(value);
    9033     shellparam.optoff = -1;
    9034 }
    9035 #endif
    9036 
    9037 #ifdef CONFIG_LOCALE_SUPPORT
    9038 static void change_lc_all(const char *value)
    9039 {
    9040     if (value != 0 && *value != 0)
    9041         setlocale(LC_ALL, value);
    9042 }
    9043 
    9044 static void change_lc_ctype(const char *value)
    9045 {
    9046     if (value != 0 && *value != 0)
    9047         setlocale(LC_CTYPE, value);
    9048 }
    9049 
    9050 #endif
    9051 
    9052 #ifdef CONFIG_ASH_RANDOM_SUPPORT
     9162#if ENABLE_ASH_RANDOM_SUPPORT
    90539163/* Roughly copied from bash.. */
    9054 static void change_random(const char *value)
    9055 {
    9056     if(value == NULL) {
     9164static void
     9165change_random(const char *value)
     9166{
     9167    if (value == NULL) {
    90579168        /* "get", generate */
    90589169        char buf[16];
     
    90709181#endif
    90719182
    9072 
    9073 #ifdef CONFIG_ASH_GETOPTS
     9183#if ENABLE_ASH_GETOPTS
    90749184static int
    90759185getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
     
    90829192    char **optnext;
    90839193
    9084     if(*param_optind < 1)
     9194    if (*param_optind < 1)
    90859195        return 1;
    90869196    optnext = optfirst + *param_optind - 1;
     
    90949204        p = *optnext;
    90959205        if (p == NULL || *p != '-' || *++p == '\0') {
    9096 atend:
     9206 atend:
    90979207            p = NULL;
    90989208            done = 1;
     
    91009210        }
    91019211        optnext++;
    9102         if (p[0] == '-' && p[1] == '\0')        /* check for "--" */
     9212        if (LONE_DASH(p))        /* check for "--" */
    91039213            goto atend;
    91049214    }
     
    91139223            } else {
    91149224                fprintf(stderr, "Illegal option -%c\n", c);
    9115                 (void) unsetvar("OPTARG");
     9225                unsetvar("OPTARG");
    91169226            }
    91179227            c = '?';
     
    91319241            } else {
    91329242                fprintf(stderr, "No arg for -%c option\n", c);
    9133                 (void) unsetvar("OPTARG");
     9243                unsetvar("OPTARG");
    91349244                c = '?';
    91359245            }
     
    91439253    } else
    91449254        err |= setvarsafe("OPTARG", nullstr, 0);
    9145 
    9146 out:
     9255 out:
    91479256    *optoff = p ? p - *(optnext - 1) : -1;
    91489257    *param_optind = optnext - optfirst + 1;
     
    91559264        *param_optind = 1;
    91569265        *optoff = -1;
    9157         flushall();
    9158         exraise(EXERROR);
     9266        flush_stdout_stderr();
     9267        raise_exception(EXERROR);
    91599268    }
    91609269    return done;
     
    91679276 * then it's the first time getopts has been called.
    91689277 */
    9169 
    9170 int
     9278static int
    91719279getoptscmd(int argc, char **argv)
    91729280{
     
    91749282
    91759283    if (argc < 3)
    9176         sh_error("Usage: getopts optstring var [arg]");
    9177     else if (argc == 3) {
     9284        ash_msg_and_raise_error("usage: getopts optstring var [arg]");
     9285    if (argc == 3) {
    91789286        optbase = shellparam.p;
    91799287        if (shellparam.optind > shellparam.nparam + 1) {
     
    91819289            shellparam.optoff = -1;
    91829290        }
    9183     }
    9184     else {
     9291    } else {
    91859292        optbase = &argv[3];
    91869293        if (shellparam.optind > argc - 2) {
     
    91919298
    91929299    return getopts(argv[1], argv[2], optbase, &shellparam.optind,
    9193                &shellparam.optoff);
    9194 }
    9195 #endif /* CONFIG_ASH_GETOPTS */
    9196 
    9197 /*
    9198  * XXX - should get rid of.  have all builtins use getopt(3).  the
    9199  * library getopt must have the BSD extension static variable "optreset"
    9200  * otherwise it can't be used within the shell safely.
    9201  *
    9202  * Standard option processing (a la getopt) for builtin routines.  The
    9203  * only argument that is passed to nextopt is the option string; the
    9204  * other arguments are unnecessary.  It return the character, or '\0' on
    9205  * end of input.
    9206  */
    9207 
    9208 static int
    9209 nextopt(const char *optstring)
    9210 {
    9211     char *p;
    9212     const char *q;
    9213     char c;
    9214 
    9215     if ((p = optptr) == NULL || *p == '\0') {
    9216         p = *argptr;
    9217         if (p == NULL || *p != '-' || *++p == '\0')
    9218             return '\0';
    9219         argptr++;
    9220         if (p[0] == '-' && p[1] == '\0')        /* check for "--" */
    9221             return '\0';
    9222     }
    9223     c = *p++;
    9224     for (q = optstring ; *q != c ; ) {
    9225         if (*q == '\0')
    9226             sh_error("Illegal option -%c", c);
    9227         if (*++q == ':')
    9228             q++;
    9229     }
    9230     if (*++q == ':') {
    9231         if (*p == '\0' && (p = *argptr++) == NULL)
    9232             sh_error("No arg for -%c option", c);
    9233         optionarg = p;
    9234         p = NULL;
    9235     }
    9236     optptr = p;
    9237     return c;
    9238 }
    9239 
    9240 
    9241 /*      output.c     */
    9242 
    9243 void
    9244 outstr(const char *p, FILE *file)
    9245 {
    9246     INTOFF;
    9247     fputs(p, file);
    9248     INTON;
    9249 }
    9250 
    9251 void
    9252 flushall(void)
    9253 {
    9254     INTOFF;
    9255     fflush(stdout);
    9256     fflush(stderr);
    9257     INTON;
    9258 }
    9259 
    9260 void
    9261 flusherr(void)
    9262 {
    9263     INTOFF;
    9264     fflush(stderr);
    9265     INTON;
    9266 }
    9267 
    9268 static void
    9269 outcslow(int c, FILE *dest)
    9270 {
    9271     INTOFF;
    9272     putc(c, dest);
    9273     fflush(dest);
    9274     INTON;
    9275 }
    9276 
    9277 
    9278 static int
    9279 out1fmt(const char *fmt, ...)
    9280 {
    9281     va_list ap;
    9282     int r;
    9283 
    9284     INTOFF;
    9285     va_start(ap, fmt);
    9286     r = vprintf(fmt, ap);
    9287     va_end(ap);
    9288     INTON;
    9289     return r;
    9290 }
    9291 
    9292 
    9293 int
    9294 fmtstr(char *outbuf, size_t length, const char *fmt, ...)
    9295 {
    9296     va_list ap;
    9297     int ret;
    9298 
    9299     va_start(ap, fmt);
    9300     INTOFF;
    9301     ret = vsnprintf(outbuf, length, fmt, ap);
    9302     va_end(ap);
    9303     INTON;
    9304     return ret;
    9305 }
    9306 
    9307 
    9308 
    9309 /*      parser.c     */
    9310 
    9311 
    9312 /*
    9313  * Shell command parser.
    9314  */
     9300            &shellparam.optoff);
     9301}
     9302#endif /* ASH_GETOPTS */
     9303
     9304
     9305/* ============ Shell parser */
     9306
     9307static int tokpushback;                /* last token pushed back */
     9308#define NEOF ((union node *)&tokpushback)
     9309static int parsebackquote;             /* nonzero if we are inside backquotes */
     9310static int lasttoken;                  /* last token read */
     9311static char *wordtext;                 /* text of last word returned by readtoken */
     9312static struct nodelist *backquotelist;
     9313static union node *redirnode;
     9314static struct heredoc *heredoc;
     9315static int quoteflag;                  /* set if (part of) last token was quoted */
     9316
     9317static void raise_error_syntax(const char *) ATTRIBUTE_NORETURN;
     9318static void
     9319raise_error_syntax(const char *msg)
     9320{
     9321    ash_msg_and_raise_error("syntax error: %s", msg);
     9322    /* NOTREACHED */
     9323}
     9324
     9325/*
     9326 * Called when an unexpected token is read during the parse.  The argument
     9327 * is the token that is expected, or -1 if more than one type of token can
     9328 * occur at this point.
     9329 */
     9330static void raise_error_unexpected_syntax(int) ATTRIBUTE_NORETURN;
     9331static void
     9332raise_error_unexpected_syntax(int token)
     9333{
     9334    char msg[64];
     9335    int l;
     9336
     9337    l = sprintf(msg, "%s unexpected", tokname(lasttoken));
     9338    if (token >= 0)
     9339        sprintf(msg + l, " (expecting %s)", tokname(token));
     9340    raise_error_syntax(msg);
     9341    /* NOTREACHED */
     9342}
    93159343
    93169344#define EOFMARKLEN 79
    9317 
    93189345
    93199346struct heredoc {
     
    93249351};
    93259352
    9326 
    9327 
    93289353static struct heredoc *heredoclist;    /* list of here documents to read */
    93299354
    9330 
    9331 static union node *list(int);
     9355/* parsing is heavily cross-recursive, need these forward decls */
    93329356static union node *andor(void);
    93339357static union node *pipeline(void);
    9334 static union node *command(void);
    9335 static union node *simplecmd(void);
    9336 static union node *makename(void);
    9337 static void parsefname(void);
     9358static union node *parse_command(void);
    93389359static void parseheredoc(void);
    93399360static char peektoken(void);
    93409361static int readtoken(void);
    9341 static int xxreadtoken(void);
    9342 static int readtoken1(int firstc, int syntax, char *eofmark, int striptabs);
    9343 static int noexpand(char *);
    9344 static void synexpect(int) ATTRIBUTE_NORETURN;
    9345 static void synerror(const char *) ATTRIBUTE_NORETURN;
    9346 static void setprompt(int);
    9347 
    9348 
    9349 
    9350 
    9351 /*
    9352  * Read and parse a command.  Returns NEOF on end of file.  (NULL is a
    9353  * valid parse tree indicating a blank line.)
    9354  */
    9355 
    9356 union node *
    9357 parsecmd(int interact)
    9358 {
    9359     int t;
    9360 
    9361     tokpushback = 0;
    9362     doprompt = interact;
    9363     if (doprompt)
    9364         setprompt(doprompt);
    9365     needprompt = 0;
    9366     t = readtoken();
    9367     if (t == TEOF)
    9368         return NEOF;
    9369     if (t == TNL)
    9370         return NULL;
    9371     tokpushback++;
    9372     return list(1);
    9373 }
    9374 
    93759362
    93769363static union node *
     
    94029389        if (n1 == NULL) {
    94039390            n1 = n2;
    9404         }
    9405         else {
    9406             n3 = (union node *)stalloc(sizeof (struct nbinary));
     9391        } else {
     9392            n3 = stalloc(sizeof(struct nbinary));
    94079393            n3->type = NSEMI;
    94089394            n3->nbinary.ch1 = n1;
     
    94359421        default:
    94369422            if (nlflag == 1)
    9437                 synexpect(-1);
     9423                raise_error_unexpected_syntax(-1);
    94389424            tokpushback++;
    94399425            return n1;
     
    94429428}
    94439429
    9444 
    9445 
    94469430static union node *
    94479431andor(void)
     
    94529436    n1 = pipeline();
    94539437    for (;;) {
    9454         if ((t = readtoken()) == TAND) {
     9438        t = readtoken();
     9439        if (t == TAND) {
    94559440            t = NAND;
    94569441        } else if (t == TOR) {
     
    94629447        checkkwd = CHKNL | CHKKWD | CHKALIAS;
    94639448        n2 = pipeline();
    9464         n3 = (union node *)stalloc(sizeof (struct nbinary));
     9449        n3 = stalloc(sizeof(struct nbinary));
    94659450        n3->type = t;
    94669451        n3->nbinary.ch1 = n1;
     
    94699454    }
    94709455}
    9471 
    9472 
    94739456
    94749457static union node *
     
    94869469    } else
    94879470        tokpushback++;
    9488     n1 = command();
     9471    n1 = parse_command();
    94899472    if (readtoken() == TPIPE) {
    9490         pipenode = (union node *)stalloc(sizeof (struct npipe));
     9473        pipenode = stalloc(sizeof(struct npipe));
    94919474        pipenode->type = NPIPE;
    94929475        pipenode->npipe.backgnd = 0;
    9493         lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
     9476        lp = stalloc(sizeof(struct nodelist));
    94949477        pipenode->npipe.cmdlist = lp;
    94959478        lp->n = n1;
    94969479        do {
    94979480            prev = lp;
    9498             lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
     9481            lp = stalloc(sizeof(struct nodelist));
    94999482            checkkwd = CHKNL | CHKKWD | CHKALIAS;
    9500             lp->n = command();
     9483            lp->n = parse_command();
    95019484            prev->next = lp;
    95029485        } while (readtoken() == TPIPE);
     
    95069489    tokpushback++;
    95079490    if (negate) {
    9508         n2 = (union node *)stalloc(sizeof (struct nnot));
     9491        n2 = stalloc(sizeof(struct nnot));
    95099492        n2->type = NNOT;
    95109493        n2->nnot.com = n1;
    95119494        return n2;
    9512     } else
    9513         return n1;
    9514 }
    9515 
    9516 
     9495    }
     9496    return n1;
     9497}
    95179498
    95189499static union node *
    9519 command(void)
    9520 {
    9521     union node *n1, *n2;
    9522     union node *ap, **app;
    9523     union node *cp, **cpp;
    9524     union node *redir, **rpp;
    9525     union node **rpp2;
    9526     int t;
    9527 
    9528     redir = NULL;
    9529     rpp2 = &redir;
    9530 
    9531     switch (readtoken()) {
    9532     default:
    9533         synexpect(-1);
    9534         /* NOTREACHED */
    9535     case TIF:
    9536         n1 = (union node *)stalloc(sizeof (struct nif));
    9537         n1->type = NIF;
    9538         n1->nif.test = list(0);
    9539         if (readtoken() != TTHEN)
    9540             synexpect(TTHEN);
    9541         n1->nif.ifpart = list(0);
    9542         n2 = n1;
    9543         while (readtoken() == TELIF) {
    9544             n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
    9545             n2 = n2->nif.elsepart;
    9546             n2->type = NIF;
    9547             n2->nif.test = list(0);
    9548             if (readtoken() != TTHEN)
    9549                 synexpect(TTHEN);
    9550             n2->nif.ifpart = list(0);
    9551         }
    9552         if (lasttoken == TELSE)
    9553             n2->nif.elsepart = list(0);
     9500makename(void)
     9501{
     9502    union node *n;
     9503
     9504    n = stalloc(sizeof(struct narg));
     9505    n->type = NARG;
     9506    n->narg.next = NULL;
     9507    n->narg.text = wordtext;
     9508    n->narg.backquote = backquotelist;
     9509    return n;
     9510}
     9511
     9512static void
     9513fixredir(union node *n, const char *text, int err)
     9514{
     9515    TRACE(("Fix redir %s %d\n", text, err));
     9516    if (!err)
     9517        n->ndup.vname = NULL;
     9518
     9519    if (isdigit(text[0]) && text[1] == '\0')
     9520        n->ndup.dupfd = text[0] - '0';
     9521    else if (LONE_DASH(text))
     9522        n->ndup.dupfd = -1;
     9523    else {
     9524        if (err)
     9525            raise_error_syntax("Bad fd number");
     9526        n->ndup.vname = makename();
     9527    }
     9528}
     9529
     9530/*
     9531 * Returns true if the text contains nothing to expand (no dollar signs
     9532 * or backquotes).
     9533 */
     9534static int
     9535noexpand(char *text)
     9536{
     9537    char *p;
     9538    char c;
     9539
     9540    p = text;
     9541    while ((c = *p++) != '\0') {
     9542        if (c == CTLQUOTEMARK)
     9543            continue;
     9544        if (c == CTLESC)
     9545            p++;
     9546        else if (SIT(c, BASESYNTAX) == CCTL)
     9547            return 0;
     9548    }
     9549    return 1;
     9550}
     9551
     9552static void
     9553parsefname(void)
     9554{
     9555    union node *n = redirnode;
     9556
     9557    if (readtoken() != TWORD)
     9558        raise_error_unexpected_syntax(-1);
     9559    if (n->type == NHERE) {
     9560        struct heredoc *here = heredoc;
     9561        struct heredoc *p;
     9562        int i;
     9563
     9564        if (quoteflag == 0)
     9565            n->type = NXHERE;
     9566        TRACE(("Here document %d\n", n->type));
     9567        if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
     9568            raise_error_syntax("Illegal eof marker for << redirection");
     9569        rmescapes(wordtext);
     9570        here->eofmark = wordtext;
     9571        here->next = NULL;
     9572        if (heredoclist == NULL)
     9573            heredoclist = here;
    95549574        else {
    9555             n2->nif.elsepart = NULL;
    9556             tokpushback++;
    9557         }
    9558         t = TFI;
    9559         break;
    9560     case TWHILE:
    9561     case TUNTIL: {
    9562         int got;
    9563         n1 = (union node *)stalloc(sizeof (struct nbinary));
    9564         n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
    9565         n1->nbinary.ch1 = list(0);
    9566         if ((got=readtoken()) != TDO) {
    9567 TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
    9568             synexpect(TDO);
    9569         }
    9570         n1->nbinary.ch2 = list(0);
    9571         t = TDONE;
    9572         break;
    9573     }
    9574     case TFOR:
    9575         if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
    9576             synerror("Bad for loop variable");
    9577         n1 = (union node *)stalloc(sizeof (struct nfor));
    9578         n1->type = NFOR;
    9579         n1->nfor.var = wordtext;
    9580         checkkwd = CHKKWD | CHKALIAS;
    9581         if (readtoken() == TIN) {
    9582             app = &ap;
    9583             while (readtoken() == TWORD) {
    9584                 n2 = (union node *)stalloc(sizeof (struct narg));
    9585                 n2->type = NARG;
    9586                 n2->narg.text = wordtext;
    9587                 n2->narg.backquote = backquotelist;
    9588                 *app = n2;
    9589                 app = &n2->narg.next;
    9590             }
    9591             *app = NULL;
    9592             n1->nfor.args = ap;
    9593             if (lasttoken != TNL && lasttoken != TSEMI)
    9594                 synexpect(-1);
    9595         } else {
    9596             n2 = (union node *)stalloc(sizeof (struct narg));
    9597             n2->type = NARG;
    9598             n2->narg.text = (char *)dolatstr;
    9599             n2->narg.backquote = NULL;
    9600             n2->narg.next = NULL;
    9601             n1->nfor.args = n2;
    9602             /*
    9603              * Newline or semicolon here is optional (but note
    9604              * that the original Bourne shell only allowed NL).
    9605              */
    9606             if (lasttoken != TNL && lasttoken != TSEMI)
    9607                 tokpushback++;
    9608         }
    9609         checkkwd = CHKNL | CHKKWD | CHKALIAS;
    9610         if (readtoken() != TDO)
    9611             synexpect(TDO);
    9612         n1->nfor.body = list(0);
    9613         t = TDONE;
    9614         break;
    9615     case TCASE:
    9616         n1 = (union node *)stalloc(sizeof (struct ncase));
    9617         n1->type = NCASE;
    9618         if (readtoken() != TWORD)
    9619             synexpect(TWORD);
    9620         n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
    9621         n2->type = NARG;
    9622         n2->narg.text = wordtext;
    9623         n2->narg.backquote = backquotelist;
    9624         n2->narg.next = NULL;
    9625         do {
    9626             checkkwd = CHKKWD | CHKALIAS;
    9627         } while (readtoken() == TNL);
    9628         if (lasttoken != TIN)
    9629             synexpect(TIN);
    9630         cpp = &n1->ncase.cases;
    9631 next_case:
    9632         checkkwd = CHKNL | CHKKWD;
    9633         t = readtoken();
    9634         while(t != TESAC) {
    9635             if (lasttoken == TLP)
    9636                 readtoken();
    9637             *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
    9638             cp->type = NCLIST;
    9639             app = &cp->nclist.pattern;
    9640             for (;;) {
    9641                 *app = ap = (union node *)stalloc(sizeof (struct narg));
    9642                 ap->type = NARG;
    9643                 ap->narg.text = wordtext;
    9644                 ap->narg.backquote = backquotelist;
    9645                 if (readtoken() != TPIPE)
    9646                     break;
    9647                 app = &ap->narg.next;
    9648                 readtoken();
    9649             }
    9650             ap->narg.next = NULL;
    9651             if (lasttoken != TRP)
    9652                 synexpect(TRP);
    9653             cp->nclist.body = list(2);
    9654 
    9655             cpp = &cp->nclist.next;
    9656 
    9657             checkkwd = CHKNL | CHKKWD;
    9658             if ((t = readtoken()) != TESAC) {
    9659                 if (t != TENDCASE)
    9660                     synexpect(TENDCASE);
    9661                 else
    9662                     goto next_case;
    9663             }
    9664         }
    9665         *cpp = NULL;
    9666         goto redir;
    9667     case TLP:
    9668         n1 = (union node *)stalloc(sizeof (struct nredir));
    9669         n1->type = NSUBSHELL;
    9670         n1->nredir.n = list(0);
    9671         n1->nredir.redirect = NULL;
    9672         t = TRP;
    9673         break;
    9674     case TBEGIN:
    9675         n1 = list(0);
    9676         t = TEND;
    9677         break;
    9678     case TWORD:
    9679     case TREDIR:
    9680         tokpushback++;
    9681         return simplecmd();
    9682     }
    9683 
    9684     if (readtoken() != t)
    9685         synexpect(t);
    9686 
    9687 redir:
    9688     /* Now check for redirection which may follow command */
    9689     checkkwd = CHKKWD | CHKALIAS;
    9690     rpp = rpp2;
    9691     while (readtoken() == TREDIR) {
    9692         *rpp = n2 = redirnode;
    9693         rpp = &n2->nfile.next;
    9694         parsefname();
    9695     }
    9696     tokpushback++;
    9697     *rpp = NULL;
    9698     if (redir) {
    9699         if (n1->type != NSUBSHELL) {
    9700             n2 = (union node *)stalloc(sizeof (struct nredir));
    9701             n2->type = NREDIR;
    9702             n2->nredir.n = n1;
    9703             n1 = n2;
    9704         }
    9705         n1->nredir.redirect = redir;
    9706     }
    9707 
    9708     return n1;
    9709 }
    9710 
     9575            for (p = heredoclist; p->next; p = p->next);
     9576            p->next = here;
     9577        }
     9578    } else if (n->type == NTOFD || n->type == NFROMFD) {
     9579        fixredir(n, wordtext, 0);
     9580    } else {
     9581        n->nfile.fname = makename();
     9582    }
     9583}
    97119584
    97129585static union node *
    9713 simplecmd(void) {
     9586simplecmd(void)
     9587{
    97149588    union node *args, **app;
    97159589    union node *n = NULL;
     
    97309604        switch (readtoken()) {
    97319605        case TWORD:
    9732             n = (union node *)stalloc(sizeof (struct narg));
     9606            n = stalloc(sizeof(struct narg));
    97339607            n->type = NARG;
    97349608            n->narg.text = wordtext;
     
    97499623            break;
    97509624        case TLP:
    9751             if (
    9752                 args && app == &args->narg.next &&
    9753                 !vars && !redir
     9625            if (args && app == &args->narg.next
     9626             && !vars && !redir
    97549627            ) {
    97559628                struct builtincmd *bcmd;
     
    97589631                /* We have a function */
    97599632                if (readtoken() != TRP)
    9760                     synexpect(TRP);
     9633                    raise_error_unexpected_syntax(TRP);
    97619634                name = n->narg.text;
    9762                 if (
    9763                     !goodname(name) || (
    9764                         (bcmd = find_builtin(name)) &&
    9765                         IS_BUILTIN_SPECIAL(bcmd)
    9766                     )
    9767                 )
    9768                     synerror("Bad function name");
     9635                if (!goodname(name)
     9636                 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
     9637                ) {
     9638                    raise_error_syntax("Bad function name");
     9639                }
    97699640                n->type = NDEFUN;
    97709641                checkkwd = CHKNL | CHKKWD | CHKALIAS;
    9771                 n->narg.next = command();
     9642                n->narg.next = parse_command();
    97729643                return n;
    97739644            }
     
    97789649        }
    97799650    }
    9780 out:
     9651 out:
    97819652    *app = NULL;
    97829653    *vpp = NULL;
    97839654    *rpp = NULL;
    9784     n = (union node *)stalloc(sizeof (struct ncmd));
     9655    n = stalloc(sizeof(struct ncmd));
    97859656    n->type = NCMD;
    97869657    n->ncmd.args = args;
     
    97919662
    97929663static union node *
    9793 makename(void)
    9794 {
    9795     union node *n;
    9796 
    9797     n = (union node *)stalloc(sizeof (struct narg));
    9798     n->type = NARG;
    9799     n->narg.next = NULL;
    9800     n->narg.text = wordtext;
    9801     n->narg.backquote = backquotelist;
    9802     return n;
    9803 }
    9804 
    9805 void fixredir(union node *n, const char *text, int err)
    9806 {
    9807     TRACE(("Fix redir %s %d\n", text, err));
    9808     if (!err)
    9809         n->ndup.vname = NULL;
    9810 
    9811     if (is_digit(text[0]) && text[1] == '\0')
    9812         n->ndup.dupfd = digit_val(text[0]);
    9813     else if (text[0] == '-' && text[1] == '\0')
    9814         n->ndup.dupfd = -1;
    9815     else {
    9816 
    9817         if (err)
    9818             synerror("Bad fd number");
    9819         else
    9820             n->ndup.vname = makename();
    9821     }
    9822 }
    9823 
    9824 
    9825 static void
    9826 parsefname(void)
    9827 {
    9828     union node *n = redirnode;
    9829 
    9830     if (readtoken() != TWORD)
    9831         synexpect(-1);
    9832     if (n->type == NHERE) {
    9833         struct heredoc *here = heredoc;
    9834         struct heredoc *p;
    9835         int i;
    9836 
    9837         if (quoteflag == 0)
    9838             n->type = NXHERE;
    9839         TRACE(("Here document %d\n", n->type));
    9840         if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
    9841             synerror("Illegal eof marker for << redirection");
    9842         rmescapes(wordtext);
    9843         here->eofmark = wordtext;
    9844         here->next = NULL;
    9845         if (heredoclist == NULL)
    9846             heredoclist = here;
     9664parse_command(void)
     9665{
     9666    union node *n1, *n2;
     9667    union node *ap, **app;
     9668    union node *cp, **cpp;
     9669    union node *redir, **rpp;
     9670    union node **rpp2;
     9671    int t;
     9672
     9673    redir = NULL;
     9674    rpp2 = &redir;
     9675
     9676    switch (readtoken()) {
     9677    default:
     9678        raise_error_unexpected_syntax(-1);
     9679        /* NOTREACHED */
     9680    case TIF:
     9681        n1 = stalloc(sizeof(struct nif));
     9682        n1->type = NIF;
     9683        n1->nif.test = list(0);
     9684        if (readtoken() != TTHEN)
     9685            raise_error_unexpected_syntax(TTHEN);
     9686        n1->nif.ifpart = list(0);
     9687        n2 = n1;
     9688        while (readtoken() == TELIF) {
     9689            n2->nif.elsepart = stalloc(sizeof(struct nif));
     9690            n2 = n2->nif.elsepart;
     9691            n2->type = NIF;
     9692            n2->nif.test = list(0);
     9693            if (readtoken() != TTHEN)
     9694                raise_error_unexpected_syntax(TTHEN);
     9695            n2->nif.ifpart = list(0);
     9696        }
     9697        if (lasttoken == TELSE)
     9698            n2->nif.elsepart = list(0);
    98479699        else {
    9848             for (p = heredoclist ; p->next ; p = p->next);
    9849             p->next = here;
    9850         }
    9851     } else if (n->type == NTOFD || n->type == NFROMFD) {
    9852         fixredir(n, wordtext, 0);
    9853     } else {
    9854         n->nfile.fname = makename();
    9855     }
    9856 }
    9857 
    9858 
    9859 /*
    9860  * Input any here documents.
    9861  */
    9862 
    9863 static void
    9864 parseheredoc(void)
    9865 {
    9866     struct heredoc *here;
    9867     union node *n;
    9868 
    9869     here = heredoclist;
    9870     heredoclist = 0;
    9871 
    9872     while (here) {
    9873         if (needprompt) {
    9874             setprompt(2);
    9875         }
    9876         readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
    9877                 here->eofmark, here->striptabs);
    9878         n = (union node *)stalloc(sizeof (struct narg));
    9879         n->narg.type = NARG;
    9880         n->narg.next = NULL;
    9881         n->narg.text = wordtext;
    9882         n->narg.backquote = backquotelist;
    9883         here->here->nhere.doc = n;
    9884         here = here->next;
    9885     }
    9886 }
    9887 
    9888 static char peektoken(void)
    9889 {
    9890     int t;
    9891 
    9892     t = readtoken();
     9700            n2->nif.elsepart = NULL;
     9701            tokpushback++;
     9702        }
     9703        t = TFI;
     9704        break;
     9705    case TWHILE:
     9706    case TUNTIL: {
     9707        int got;
     9708        n1 = stalloc(sizeof(struct nbinary));
     9709        n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
     9710        n1->nbinary.ch1 = list(0);
     9711        got = readtoken();
     9712        if (got != TDO) {
     9713            TRACE(("expecting DO got %s %s\n", tokname(got),
     9714                    got == TWORD ? wordtext : ""));
     9715            raise_error_unexpected_syntax(TDO);
     9716        }
     9717        n1->nbinary.ch2 = list(0);
     9718        t = TDONE;
     9719        break;
     9720    }
     9721    case TFOR:
     9722        if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
     9723            raise_error_syntax("Bad for loop variable");
     9724        n1 = stalloc(sizeof(struct nfor));
     9725        n1->type = NFOR;
     9726        n1->nfor.var = wordtext;
     9727        checkkwd = CHKKWD | CHKALIAS;
     9728        if (readtoken() == TIN) {
     9729            app = &ap;
     9730            while (readtoken() == TWORD) {
     9731                n2 = stalloc(sizeof(struct narg));
     9732                n2->type = NARG;
     9733                n2->narg.text = wordtext;
     9734                n2->narg.backquote = backquotelist;
     9735                *app = n2;
     9736                app = &n2->narg.next;
     9737            }
     9738            *app = NULL;
     9739            n1->nfor.args = ap;
     9740            if (lasttoken != TNL && lasttoken != TSEMI)
     9741                raise_error_unexpected_syntax(-1);
     9742        } else {
     9743            n2 = stalloc(sizeof(struct narg));
     9744            n2->type = NARG;
     9745            n2->narg.text = (char *)dolatstr;
     9746            n2->narg.backquote = NULL;
     9747            n2->narg.next = NULL;
     9748            n1->nfor.args = n2;
     9749            /*
     9750             * Newline or semicolon here is optional (but note
     9751             * that the original Bourne shell only allowed NL).
     9752             */
     9753            if (lasttoken != TNL && lasttoken != TSEMI)
     9754                tokpushback++;
     9755        }
     9756        checkkwd = CHKNL | CHKKWD | CHKALIAS;
     9757        if (readtoken() != TDO)
     9758            raise_error_unexpected_syntax(TDO);
     9759        n1->nfor.body = list(0);
     9760        t = TDONE;
     9761        break;
     9762    case TCASE:
     9763        n1 = stalloc(sizeof(struct ncase));
     9764        n1->type = NCASE;
     9765        if (readtoken() != TWORD)
     9766            raise_error_unexpected_syntax(TWORD);
     9767        n1->ncase.expr = n2 = stalloc(sizeof(struct narg));
     9768        n2->type = NARG;
     9769        n2->narg.text = wordtext;
     9770        n2->narg.backquote = backquotelist;
     9771        n2->narg.next = NULL;
     9772        do {
     9773            checkkwd = CHKKWD | CHKALIAS;
     9774        } while (readtoken() == TNL);
     9775        if (lasttoken != TIN)
     9776            raise_error_unexpected_syntax(TIN);
     9777        cpp = &n1->ncase.cases;
     9778 next_case:
     9779        checkkwd = CHKNL | CHKKWD;
     9780        t = readtoken();
     9781        while (t != TESAC) {
     9782            if (lasttoken == TLP)
     9783                readtoken();
     9784            *cpp = cp = stalloc(sizeof(struct nclist));
     9785            cp->type = NCLIST;
     9786            app = &cp->nclist.pattern;
     9787            for (;;) {
     9788                *app = ap = stalloc(sizeof(struct narg));
     9789                ap->type = NARG;
     9790                ap->narg.text = wordtext;
     9791                ap->narg.backquote = backquotelist;
     9792                if (readtoken() != TPIPE)
     9793                    break;
     9794                app = &ap->narg.next;
     9795                readtoken();
     9796            }
     9797            ap->narg.next = NULL;
     9798            if (lasttoken != TRP)
     9799                raise_error_unexpected_syntax(TRP);
     9800            cp->nclist.body = list(2);
     9801
     9802            cpp = &cp->nclist.next;
     9803
     9804            checkkwd = CHKNL | CHKKWD;
     9805            t = readtoken();
     9806            if (t != TESAC) {
     9807                if (t != TENDCASE)
     9808                    raise_error_unexpected_syntax(TENDCASE);
     9809                goto next_case;
     9810            }
     9811        }
     9812        *cpp = NULL;
     9813        goto redir;
     9814    case TLP:
     9815        n1 = stalloc(sizeof(struct nredir));
     9816        n1->type = NSUBSHELL;
     9817        n1->nredir.n = list(0);
     9818        n1->nredir.redirect = NULL;
     9819        t = TRP;
     9820        break;
     9821    case TBEGIN:
     9822        n1 = list(0);
     9823        t = TEND;
     9824        break;
     9825    case TWORD:
     9826    case TREDIR:
     9827        tokpushback++;
     9828        return simplecmd();
     9829    }
     9830
     9831    if (readtoken() != t)
     9832        raise_error_unexpected_syntax(t);
     9833
     9834 redir:
     9835    /* Now check for redirection which may follow command */
     9836    checkkwd = CHKKWD | CHKALIAS;
     9837    rpp = rpp2;
     9838    while (readtoken() == TREDIR) {
     9839        *rpp = n2 = redirnode;
     9840        rpp = &n2->nfile.next;
     9841        parsefname();
     9842    }
    98939843    tokpushback++;
    9894     return tokname_array[t][0];
    9895 }
    9896 
    9897 static int
    9898 readtoken(void)
    9899 {
    9900     int t;
    9901 #ifdef DEBUG
    9902     int alreadyseen = tokpushback;
    9903 #endif
    9904 
    9905 #ifdef CONFIG_ASH_ALIAS
    9906 top:
    9907 #endif
    9908 
    9909     t = xxreadtoken();
    9910 
    9911     /*
    9912      * eat newlines
    9913      */
    9914     if (checkkwd & CHKNL) {
    9915         while (t == TNL) {
    9916             parseheredoc();
    9917             t = xxreadtoken();
    9918         }
    9919     }
    9920 
    9921     if (t != TWORD || quoteflag) {
    9922         goto out;
    9923     }
    9924 
    9925     /*
    9926      * check for keywords
    9927      */
    9928     if (checkkwd & CHKKWD) {
    9929         const char *const *pp;
    9930 
    9931         if ((pp = findkwd(wordtext))) {
    9932             lasttoken = t = pp - tokname_array;
    9933             TRACE(("keyword %s recognized\n", tokname(t)));
    9934             goto out;
    9935         }
    9936     }
    9937 
    9938     if (checkkwd & CHKALIAS) {
    9939 #ifdef CONFIG_ASH_ALIAS
    9940         struct alias *ap;
    9941         if ((ap = lookupalias(wordtext, 1)) != NULL) {
    9942             if (*ap->val) {
    9943                 pushstring(ap->val, ap);
    9944             }
    9945             goto top;
    9946         }
    9947 #endif
    9948     }
    9949 out:
    9950     checkkwd = 0;
    9951 #ifdef DEBUG
    9952     if (!alreadyseen)
    9953         TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
    9954     else
    9955         TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
    9956 #endif
    9957     return (t);
    9958 }
    9959 
    9960 
    9961 /*
    9962  * Read the next input token.
    9963  * If the token is a word, we set backquotelist to the list of cmds in
    9964  *      backquotes.  We set quoteflag to true if any part of the word was
    9965  *      quoted.
    9966  * If the token is TREDIR, then we set redirnode to a structure containing
    9967  *      the redirection.
    9968  * In all cases, the variable startlinno is set to the number of the line
    9969  *      on which the token starts.
    9970  *
    9971  * [Change comment:  here documents and internal procedures]
    9972  * [Readtoken shouldn't have any arguments.  Perhaps we should make the
    9973  *  word parsing code into a separate routine.  In this case, readtoken
    9974  *  doesn't need to have any internal procedures, but parseword does.
    9975  *  We could also make parseoperator in essence the main routine, and
    9976  *  have parseword (readtoken1?) handle both words and redirection.]
    9977  */
    9978 
    9979 #define NEW_xxreadtoken
    9980 #ifdef NEW_xxreadtoken
    9981 
    9982 /* singles must be first! */
    9983 static const char xxreadtoken_chars[7] = { '\n', '(', ')', '&', '|', ';', 0 };
    9984 
    9985 static const char xxreadtoken_tokens[] = {
    9986     TNL, TLP, TRP,          /* only single occurrence allowed */
    9987     TBACKGND, TPIPE, TSEMI, /* if single occurrence */
    9988     TEOF,                   /* corresponds to trailing nul */
    9989     TAND, TOR, TENDCASE,    /* if double occurrence */
    9990 };
    9991 
    9992 #define xxreadtoken_doubles \
    9993     (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
    9994 #define xxreadtoken_singles \
    9995     (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
    9996 
    9997 static int xxreadtoken(void)
    9998 {
    9999     int c;
    10000 
    10001     if (tokpushback) {
    10002         tokpushback = 0;
    10003         return lasttoken;
    10004     }
    10005     if (needprompt) {
    10006         setprompt(2);
    10007     }
    10008     startlinno = plinno;
    10009     for (;;) {                      /* until token or start of word found */
    10010         c = pgetc_macro();
    10011 
    10012         if ((c != ' ') && (c != '\t')
    10013 #ifdef CONFIG_ASH_ALIAS
    10014             && (c != PEOA)
    10015 #endif
    10016             ) {
    10017             if (c == '#') {
    10018                 while ((c = pgetc()) != '\n' && c != PEOF);
    10019                 pungetc();
    10020             } else if (c == '\\') {
    10021                 if (pgetc() != '\n') {
    10022                     pungetc();
    10023                     goto READTOKEN1;
    10024                 }
    10025                 startlinno = ++plinno;
    10026                 if (doprompt)
    10027                     setprompt(2);
    10028             } else {
    10029                 const char *p
    10030                     = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
    10031 
    10032                 if (c != PEOF) {
    10033                     if (c == '\n') {
    10034                         plinno++;
    10035                         needprompt = doprompt;
    10036                     }
    10037 
    10038                     p = strchr(xxreadtoken_chars, c);
    10039                     if (p == NULL) {
    10040                       READTOKEN1:
    10041                         return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
    10042                     }
    10043 
    10044                     if (p - xxreadtoken_chars >= xxreadtoken_singles) {
    10045                         if (pgetc() == *p) {    /* double occurrence? */
    10046                             p += xxreadtoken_doubles + 1;
    10047                         } else {
    10048                             pungetc();
    10049                         }
    10050                     }
    10051                 }
    10052 
    10053                 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
    10054             }
    10055         }
    10056     }
    10057 }
    10058 
    10059 
    10060 #else
    10061 #define RETURN(token)   return lasttoken = token
    10062 
    10063 static int
    10064 xxreadtoken(void)
    10065 {
    10066     int c;
    10067 
    10068     if (tokpushback) {
    10069         tokpushback = 0;
    10070         return lasttoken;
    10071     }
    10072     if (needprompt) {
    10073         setprompt(2);
    10074     }
    10075     startlinno = plinno;
    10076     for (;;) {      /* until token or start of word found */
    10077         c = pgetc_macro();
    10078         switch (c) {
    10079         case ' ': case '\t':
    10080 #ifdef CONFIG_ASH_ALIAS
    10081         case PEOA:
    10082 #endif
    10083             continue;
    10084         case '#':
    10085             while ((c = pgetc()) != '\n' && c != PEOF);
    10086             pungetc();
    10087             continue;
    10088         case '\\':
    10089             if (pgetc() == '\n') {
    10090                 startlinno = ++plinno;
    10091                 if (doprompt)
    10092                     setprompt(2);
    10093                 continue;
    10094             }
    10095             pungetc();
    10096             goto breakloop;
    10097         case '\n':
    10098             plinno++;
    10099             needprompt = doprompt;
    10100             RETURN(TNL);
    10101         case PEOF:
    10102             RETURN(TEOF);
    10103         case '&':
    10104             if (pgetc() == '&')
    10105                 RETURN(TAND);
    10106             pungetc();
    10107             RETURN(TBACKGND);
    10108         case '|':
    10109             if (pgetc() == '|')
    10110                 RETURN(TOR);
    10111             pungetc();
    10112             RETURN(TPIPE);
    10113         case ';':
    10114             if (pgetc() == ';')
    10115                 RETURN(TENDCASE);
    10116             pungetc();
    10117             RETURN(TSEMI);
    10118         case '(':
    10119             RETURN(TLP);
    10120         case ')':
    10121             RETURN(TRP);
    10122         default:
    10123             goto breakloop;
    10124         }
    10125     }
    10126 breakloop:
    10127     return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
    10128 #undef RETURN
    10129 }
    10130 #endif /* NEW_xxreadtoken */
    10131 
     9844    *rpp = NULL;
     9845    if (redir) {
     9846        if (n1->type != NSUBSHELL) {
     9847            n2 = stalloc(sizeof(struct nredir));
     9848            n2->type = NREDIR;
     9849            n2->nredir.n = n1;
     9850            n1 = n2;
     9851        }
     9852        n1->nredir.redirect = redir;
     9853    }
     9854    return n1;
     9855}
    101329856
    101339857/*
     
    101429866 * will run code that appears at the end of readtoken1.
    101439867 */
     9868
     9869static int parsebackquote;             /* nonzero if we are inside backquotes */
    101449870
    101459871#define CHECKEND()      {goto checkend; checkend_return:;}
     
    101969922        for (;;) {      /* until end of line or end of word */
    101979923            CHECKSTRSPACE(4, out);  /* permit 4 calls to USTPUTC */
    10198             switch(SIT(c, syntax)) {
     9924            switch (SIT(c, syntax)) {
    101999925            case CNL:       /* '\n' */
    102009926                if (syntax == BASESYNTAX)
     
    102419967            case CSQUOTE:
    102429968                syntax = SQSYNTAX;
    10243 quotemark:
     9969 quotemark:
    102449970                if (eofmark == NULL) {
    102459971                    USTPUTC(CTLQUOTEMARK, out);
     
    102519977                goto quotemark;
    102529978            case CENDQUOTE:
    10253                 if (eofmark != NULL && arinest == 0 &&
    10254                     varnest == 0) {
     9979                if (eofmark != NULL && arinest == 0
     9980                 && varnest == 0
     9981                ) {
    102559982                    USTPUTC(c, out);
    102569983                } else {
     
    1027710004                }
    1027810005                break;
    10279 #ifdef CONFIG_ASH_MATH_SUPPORT
     10006#if ENABLE_ASH_MATH_SUPPORT
    1028010007            case CLP:       /* '(' in arithmetic */
    1028110008                parenlevel++;
     
    1031810045                if (varnest == 0)
    1031910046                    goto endword;   /* exit outer loop */
    10320 #ifdef CONFIG_ASH_ALIAS
     10047#if ENABLE_ASH_ALIAS
    1032110048                if (c != PEOA)
    1032210049#endif
     
    1032710054        }
    1032810055    }
    10329 endword:
    10330 #ifdef CONFIG_ASH_MATH_SUPPORT
     10056 endword:
     10057#if ENABLE_ASH_MATH_SUPPORT
    1033110058    if (syntax == ARISYNTAX)
    10332         synerror("Missing '))'");
    10333 #endif
    10334     if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
    10335         synerror("Unterminated quoted string");
     10059        raise_error_syntax("Missing '))'");
     10060#endif
     10061    if (syntax != BASESYNTAX && !parsebackquote && eofmark == NULL)
     10062        raise_error_syntax("Unterminated quoted string");
    1033610063    if (varnest != 0) {
    1033710064        startlinno = plinno;
    1033810065        /* { */
    10339         synerror("Missing '}'");
     10066        raise_error_syntax("Missing '}'");
    1034010067    }
    1034110068    USTPUTC('\0', out);
     
    1034610073         && quotef == 0
    1034710074         && len <= 2
    10348          && (*out == '\0' || is_digit(*out))) {
     10075         && (*out == '\0' || isdigit(*out))) {
    1034910076            PARSEREDIR();
    1035010077            return lasttoken = TREDIR;
     
    1035710084    grabstackblock(len);
    1035810085    wordtext = out;
    10359     return lasttoken = TWORD;
     10086    lasttoken = TWORD;
     10087    return lasttoken;
    1036010088/* end of readtoken routine */
    10361 
    10362 
    1036310089
    1036410090/*
     
    1036710093 * we are at the end of the here document, this routine sets the c to PEOF.
    1036810094 */
    10369 
    1037010095checkend: {
    1037110096    if (eofmark) {
    10372 #ifdef CONFIG_ASH_ALIAS
     10097#if ENABLE_ASH_ALIAS
    1037310098        if (c == PEOA) {
    1037410099            c = pgetc2();
     
    1038110106        }
    1038210107        if (c == *eofmark) {
    10383             if (pfgets(line, sizeof line) != NULL) {
     10108            if (pfgets(line, sizeof(line)) != NULL) {
    1038410109                char *p, *q;
    1038510110
    1038610111                p = line;
    10387                 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
     10112                for (q = eofmark + 1; *q && *p == *q; p++, q++);
    1038810113                if (*p == '\n' && *q == '\0') {
    1038910114                    c = PEOF;
     
    1039910124}
    1040010125
    10401 
    1040210126/*
    1040310127 * Parse a redirection operator.  The variable "out" points to a string
     
    1040510129 * first character of the redirection operator.
    1040610130 */
    10407 
    1040810131parseredir: {
    1040910132    char fd = *out;
    1041010133    union node *np;
    1041110134
    10412     np = (union node *)stalloc(sizeof (struct nfile));
     10135    np = stalloc(sizeof(struct nfile));
    1041310136    if (c == '>') {
    1041410137        np->nfile.fd = 1;
     
    1042610149    } else {        /* c == '<' */
    1042710150        np->nfile.fd = 0;
    10428         switch (c = pgetc()) {
     10151        c = pgetc();
     10152        switch (c) {
    1042910153        case '<':
    10430             if (sizeof (struct nfile) != sizeof (struct nhere)) {
    10431                 np = (union node *)stalloc(sizeof (struct nhere));
     10154            if (sizeof(struct nfile) != sizeof(struct nhere)) {
     10155                np = stalloc(sizeof(struct nhere));
    1043210156                np->nfile.fd = 0;
    1043310157            }
    1043410158            np->type = NHERE;
    10435             heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
     10159            heredoc = stalloc(sizeof(struct heredoc));
    1043610160            heredoc->here = np;
    10437             if ((c = pgetc()) == '-') {
     10161            c = pgetc();
     10162            if (c == '-') {
    1043810163                heredoc->striptabs = 1;
    1043910164            } else {
     
    1045810183    }
    1045910184    if (fd != '\0')
    10460         np->nfile.fd = digit_val(fd);
     10185        np->nfile.fd = fd - '0';
    1046110186    redirnode = np;
    1046210187    goto parseredir_return;
    1046310188}
    1046410189
    10465 
    1046610190/*
    1046710191 * Parse a substitution.  At this point, we have read the dollar sign
     
    1046910193 */
    1047010194
     10195/* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
     10196 * (assuming ascii char codes, as the original implementation did) */
     10197#define is_special(c) \
     10198    ((((unsigned int)c) - 33 < 32) \
     10199            && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1))
    1047110200parsesub: {
    1047210201    int subtype;
     
    1047410203    int flags;
    1047510204    char *p;
    10476     static const char types[] = "}-+?=";
     10205    static const char types[] ALIGN1 = "}-+?=";
    1047710206
    1047810207    c = pgetc();
     
    1048510214    } else if (c == '(') {  /* $(command) or $((arith)) */
    1048610215        if (pgetc() == '(') {
    10487 #ifdef CONFIG_ASH_MATH_SUPPORT
     10216#if ENABLE_ASH_MATH_SUPPORT
    1048810217            PARSEARITH();
    1048910218#else
    10490             synerror("We unsupport $((arith))");
     10219            raise_error_syntax("We unsupport $((arith))");
    1049110220#endif
    1049210221        } else {
     
    1050210231            c = pgetc();
    1050310232            if (c == '#') {
    10504                 if ((c = pgetc()) == '}')
     10233                c = pgetc();
     10234                if (c == '}')
    1050510235                    c = '#';
    1050610236                else
    1050710237                    subtype = VSLENGTH;
    10508             }
    10509             else
     10238            } else
    1051010239                subtype = 0;
    1051110240        }
     
    1051510244                c = pgetc();
    1051610245            } while (c > PEOA_OR_PEOF && is_in_name(c));
    10517         } else if (is_digit(c)) {
     10246        } else if (isdigit(c)) {
    1051810247            do {
    1051910248                STPUTC(c, out);
    1052010249                c = pgetc();
    10521             } while (is_digit(c));
    10522         }
    10523         else if (is_special(c)) {
     10250            } while (isdigit(c));
     10251        } else if (is_special(c)) {
    1052410252            USTPUTC(c, out);
    1052510253            c = pgetc();
    10526         }
    10527         else
    10528 badsub:                 synerror("Bad substitution");
     10254        } else
     10255 badsub:        raise_error_syntax("Bad substitution");
    1052910256
    1053010257        STPUTC('=', out);
     
    1054710274                    int cc = c;
    1054810275                    subtype = c == '#' ? VSTRIMLEFT :
    10549                                  VSTRIMRIGHT;
     10276                                         VSTRIMRIGHT;
    1055010277                    c = pgetc();
    1055110278                    if (c == cc)
     
    1057210299}
    1057310300
    10574 
    1057510301/*
    1057610302 * Called to parse command substitutions.  Newstyle is set if the command
     
    1057910305 * characters on the top of the stack which must be preserved.
    1058010306 */
    10581 
    1058210307parsebackq: {
    1058310308    struct nodelist **nlpp;
     
    1059610321    if (setjmp(jmploc.loc)) {
    1059710322        if (str)
    10598             ckfree(str);
     10323            free(str);
    1059910324        parsebackquote = 0;
    10600         handler = savehandler;
    10601         longjmp(handler->loc, 1);
    10602     }
    10603     INTOFF;
     10325        exception_handler = savehandler;
     10326        longjmp(exception_handler->loc, 1);
     10327    }
     10328    INT_OFF;
    1060410329    str = NULL;
    1060510330    savelen = out - (char *)stackblock();
     
    1060810333        memcpy(str, stackblock(), savelen);
    1060910334    }
    10610     savehandler = handler;
    10611     handler = &jmploc;
    10612     INTON;
     10335    savehandler = exception_handler;
     10336    exception_handler = &jmploc;
     10337    INT_ON;
    1061310338    if (oldstyle) {
    1061410339        /* We must read until the closing backquote, giving special
     
    1062610351                setprompt(2);
    1062710352            }
    10628             switch (pc = pgetc()) {
     10353            pc = pgetc();
     10354            switch (pc) {
    1062910355            case '`':
    1063010356                goto done;
    1063110357
    1063210358            case '\\':
    10633                 if ((pc = pgetc()) == '\n') {
     10359                pc = pgetc();
     10360                if (pc == '\n') {
    1063410361                    plinno++;
    1063510362                    if (doprompt)
     
    1064410371                }
    1064510372                if (pc != '\\' && pc != '`' && pc != '$'
    10646                     && (!dblquote || pc != '"'))
     10373                 && (!dblquote || pc != '"'))
    1064710374                    STPUTC('\\', pout);
    1064810375                if (pc > PEOA_OR_PEOF) {
     
    1065210379
    1065310380            case PEOF:
    10654 #ifdef CONFIG_ASH_ALIAS
     10381#if ENABLE_ASH_ALIAS
    1065510382            case PEOA:
    1065610383#endif
    1065710384                startlinno = plinno;
    10658                 synerror("EOF in backquote substitution");
     10385                raise_error_syntax("EOF in backquote substitution");
    1065910386
    1066010387            case '\n':
     
    1066810395            STPUTC(pc, pout);
    1066910396        }
    10670 done:
     10397 done:
    1067110398        STPUTC('\0', pout);
    1067210399        psavelen = pout - (char *)stackblock();
     
    1067910406    while (*nlpp)
    1068010407        nlpp = &(*nlpp)->next;
    10681     *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
     10408    *nlpp = stalloc(sizeof(**nlpp));
    1068210409    (*nlpp)->next = NULL;
    1068310410    parsebackquote = oldstyle;
     
    1069210419    if (oldstyle)
    1069310420        doprompt = saveprompt;
    10694     else {
    10695         if (readtoken() != TRP)
    10696             synexpect(TRP);
    10697     }
     10421    else if (readtoken() != TRP)
     10422        raise_error_unexpected_syntax(TRP);
    1069810423
    1069910424    (*nlpp)->n = n;
     
    1071210437        memcpy(out, str, savelen);
    1071310438        STADJUST(savelen, out);
    10714         INTOFF;
    10715         ckfree(str);
     10439        INT_OFF;
     10440        free(str);
    1071610441        str = NULL;
    10717         INTON;
     10442        INT_ON;
    1071810443    }
    1071910444    parsebackquote = savepbq;
    10720     handler = savehandler;
     10445    exception_handler = savehandler;
    1072110446    if (arinest || dblquote)
    1072210447        USTPUTC(CTLBACKQ | CTLQUOTE, out);
     
    1072510450    if (oldstyle)
    1072610451        goto parsebackq_oldreturn;
    10727     else
    10728         goto parsebackq_newreturn;
    10729 }
    10730 
    10731 #ifdef CONFIG_ASH_MATH_SUPPORT
     10452    goto parsebackq_newreturn;
     10453}
     10454
     10455#if ENABLE_ASH_MATH_SUPPORT
    1073210456/*
    1073310457 * Parse an arithmetic expansion (indicate start of one and set state)
    1073410458 */
    1073510459parsearith: {
    10736 
    1073710460    if (++arinest == 1) {
    1073810461        prevsyntax = syntax;
     
    1074010463        USTPUTC(CTLARI, out);
    1074110464        if (dblquote)
    10742             USTPUTC('"',out);
     10465            USTPUTC('"', out);
    1074310466        else
    10744             USTPUTC(' ',out);
     10467            USTPUTC(' ', out);
    1074510468    } else {
    1074610469        /*
     
    1075610479} /* end of readtoken */
    1075710480
    10758 
    10759 
    10760 /*
    10761  * Returns true if the text contains nothing to expand (no dollar signs
    10762  * or backquotes).
    10763  */
     10481/*
     10482 * Read the next input token.
     10483 * If the token is a word, we set backquotelist to the list of cmds in
     10484 *      backquotes.  We set quoteflag to true if any part of the word was
     10485 *      quoted.
     10486 * If the token is TREDIR, then we set redirnode to a structure containing
     10487 *      the redirection.
     10488 * In all cases, the variable startlinno is set to the number of the line
     10489 *      on which the token starts.
     10490 *
     10491 * [Change comment:  here documents and internal procedures]
     10492 * [Readtoken shouldn't have any arguments.  Perhaps we should make the
     10493 *  word parsing code into a separate routine.  In this case, readtoken
     10494 *  doesn't need to have any internal procedures, but parseword does.
     10495 *  We could also make parseoperator in essence the main routine, and
     10496 *  have parseword (readtoken1?) handle both words and redirection.]
     10497 */
     10498#define NEW_xxreadtoken
     10499#ifdef NEW_xxreadtoken
     10500/* singles must be first! */
     10501static const char xxreadtoken_chars[7] ALIGN1 = {
     10502    '\n', '(', ')', '&', '|', ';', 0
     10503};
     10504
     10505static const char xxreadtoken_tokens[] ALIGN1 = {
     10506    TNL, TLP, TRP,          /* only single occurrence allowed */
     10507    TBACKGND, TPIPE, TSEMI, /* if single occurrence */
     10508    TEOF,                   /* corresponds to trailing nul */
     10509    TAND, TOR, TENDCASE     /* if double occurrence */
     10510};
     10511
     10512#define xxreadtoken_doubles \
     10513    (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
     10514#define xxreadtoken_singles \
     10515    (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
    1076410516
    1076510517static int
    10766 noexpand(char *text)
    10767 {
    10768     char *p;
    10769     char c;
    10770 
    10771     p = text;
    10772     while ((c = *p++) != '\0') {
    10773         if (c == CTLQUOTEMARK)
     10518xxreadtoken(void)
     10519{
     10520    int c;
     10521
     10522    if (tokpushback) {
     10523        tokpushback = 0;
     10524        return lasttoken;
     10525    }
     10526    if (needprompt) {
     10527        setprompt(2);
     10528    }
     10529    startlinno = plinno;
     10530    for (;;) {                      /* until token or start of word found */
     10531        c = pgetc_macro();
     10532
     10533        if ((c != ' ') && (c != '\t')
     10534#if ENABLE_ASH_ALIAS
     10535         && (c != PEOA)
     10536#endif
     10537        ) {
     10538            if (c == '#') {
     10539                while ((c = pgetc()) != '\n' && c != PEOF);
     10540                pungetc();
     10541            } else if (c == '\\') {
     10542                if (pgetc() != '\n') {
     10543                    pungetc();
     10544                    goto READTOKEN1;
     10545                }
     10546                startlinno = ++plinno;
     10547                if (doprompt)
     10548                    setprompt(2);
     10549            } else {
     10550                const char *p
     10551                    = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
     10552
     10553                if (c != PEOF) {
     10554                    if (c == '\n') {
     10555                        plinno++;
     10556                        needprompt = doprompt;
     10557                    }
     10558
     10559                    p = strchr(xxreadtoken_chars, c);
     10560                    if (p == NULL) {
     10561 READTOKEN1:
     10562                        return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
     10563                    }
     10564
     10565                    if (p - xxreadtoken_chars >= xxreadtoken_singles) {
     10566                        if (pgetc() == *p) {    /* double occurrence? */
     10567                            p += xxreadtoken_doubles + 1;
     10568                        } else {
     10569                            pungetc();
     10570                        }
     10571                    }
     10572                }
     10573                return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
     10574            }
     10575        }
     10576    } /* for */
     10577}
     10578#else
     10579#define RETURN(token)   return lasttoken = token
     10580static int
     10581xxreadtoken(void)
     10582{
     10583    int c;
     10584
     10585    if (tokpushback) {
     10586        tokpushback = 0;
     10587        return lasttoken;
     10588    }
     10589    if (needprompt) {
     10590        setprompt(2);
     10591    }
     10592    startlinno = plinno;
     10593    for (;;) {      /* until token or start of word found */
     10594        c = pgetc_macro();
     10595        switch (c) {
     10596        case ' ': case '\t':
     10597#if ENABLE_ASH_ALIAS
     10598        case PEOA:
     10599#endif
    1077410600            continue;
    10775         if (c == CTLESC)
    10776             p++;
    10777         else if (SIT(c, BASESYNTAX) == CCTL)
    10778             return 0;
    10779     }
    10780     return 1;
    10781 }
    10782 
    10783 
    10784 /*
    10785  * Return of a legal variable name (a letter or underscore followed by zero or
    10786  * more letters, underscores, and digits).
    10787  */
    10788 
    10789 static char *
    10790 endofname(const char *name)
    10791 {
    10792     char *p;
    10793 
    10794     p = (char *) name;
    10795     if (! is_name(*p))
    10796         return p;
    10797     while (*++p) {
    10798         if (! is_in_name(*p))
    10799             break;
    10800     }
    10801     return p;
    10802 }
    10803 
    10804 
    10805 /*
    10806  * Called when an unexpected token is read during the parse.  The argument
    10807  * is the token that is expected, or -1 if more than one type of token can
    10808  * occur at this point.
    10809  */
    10810 
    10811 static void synexpect(int token)
    10812 {
    10813     char msg[64];
    10814     int l;
    10815 
    10816     l = sprintf(msg, "%s unexpected", tokname(lasttoken));
    10817     if (token >= 0)
    10818         sprintf(msg + l, " (expecting %s)", tokname(token));
    10819     synerror(msg);
    10820     /* NOTREACHED */
    10821 }
    10822 
    10823 static void
    10824 synerror(const char *msg)
    10825 {
    10826     sh_error("Syntax error: %s", msg);
    10827     /* NOTREACHED */
    10828 }
    10829 
    10830 
    10831 /*
    10832  * called by editline -- any expansions to the prompt
    10833  *    should be added here.
    10834  */
    10835 
    10836 #ifdef CONFIG_ASH_EXPAND_PRMT
     10601        case '#':
     10602            while ((c = pgetc()) != '\n' && c != PEOF);
     10603            pungetc();
     10604            continue;
     10605        case '\\':
     10606            if (pgetc() == '\n') {
     10607                startlinno = ++plinno;
     10608                if (doprompt)
     10609                    setprompt(2);
     10610                continue;
     10611            }
     10612            pungetc();
     10613            goto breakloop;
     10614        case '\n':
     10615            plinno++;
     10616            needprompt = doprompt;
     10617            RETURN(TNL);
     10618        case PEOF:
     10619            RETURN(TEOF);
     10620        case '&':
     10621            if (pgetc() == '&')
     10622                RETURN(TAND);
     10623            pungetc();
     10624            RETURN(TBACKGND);
     10625        case '|':
     10626            if (pgetc() == '|')
     10627                RETURN(TOR);
     10628            pungetc();
     10629            RETURN(TPIPE);
     10630        case ';':
     10631            if (pgetc() == ';')
     10632                RETURN(TENDCASE);
     10633            pungetc();
     10634            RETURN(TSEMI);
     10635        case '(':
     10636            RETURN(TLP);
     10637        case ')':
     10638            RETURN(TRP);
     10639        default:
     10640            goto breakloop;
     10641        }
     10642    }
     10643 breakloop:
     10644    return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
     10645#undef RETURN
     10646}
     10647#endif /* NEW_xxreadtoken */
     10648
     10649static int
     10650readtoken(void)
     10651{
     10652    int t;
     10653#if DEBUG
     10654    int alreadyseen = tokpushback;
     10655#endif
     10656
     10657#if ENABLE_ASH_ALIAS
     10658 top:
     10659#endif
     10660
     10661    t = xxreadtoken();
     10662
     10663    /*
     10664     * eat newlines
     10665     */
     10666    if (checkkwd & CHKNL) {
     10667        while (t == TNL) {
     10668            parseheredoc();
     10669            t = xxreadtoken();
     10670        }
     10671    }
     10672
     10673    if (t != TWORD || quoteflag) {
     10674        goto out;
     10675    }
     10676
     10677    /*
     10678     * check for keywords
     10679     */
     10680    if (checkkwd & CHKKWD) {
     10681        const char *const *pp;
     10682
     10683        pp = findkwd(wordtext);
     10684        if (pp) {
     10685            lasttoken = t = pp - tokname_array;
     10686            TRACE(("keyword %s recognized\n", tokname(t)));
     10687            goto out;
     10688        }
     10689    }
     10690
     10691    if (checkkwd & CHKALIAS) {
     10692#if ENABLE_ASH_ALIAS
     10693        struct alias *ap;
     10694        ap = lookupalias(wordtext, 1);
     10695        if (ap != NULL) {
     10696            if (*ap->val) {
     10697                pushstring(ap->val, ap);
     10698            }
     10699            goto top;
     10700        }
     10701#endif
     10702    }
     10703 out:
     10704    checkkwd = 0;
     10705#if DEBUG
     10706    if (!alreadyseen)
     10707        TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
     10708    else
     10709        TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
     10710#endif
     10711    return t;
     10712}
     10713
     10714static char
     10715peektoken(void)
     10716{
     10717    int t;
     10718
     10719    t = readtoken();
     10720    tokpushback++;
     10721    return tokname_array[t][0];
     10722}
     10723
     10724/*
     10725 * Read and parse a command.  Returns NEOF on end of file.  (NULL is a
     10726 * valid parse tree indicating a blank line.)
     10727 */
     10728static union node *
     10729parsecmd(int interact)
     10730{
     10731    int t;
     10732
     10733    tokpushback = 0;
     10734    doprompt = interact;
     10735    if (doprompt)
     10736        setprompt(doprompt);
     10737    needprompt = 0;
     10738    t = readtoken();
     10739    if (t == TEOF)
     10740        return NEOF;
     10741    if (t == TNL)
     10742        return NULL;
     10743    tokpushback++;
     10744    return list(1);
     10745}
     10746
     10747/*
     10748 * Input any here documents.
     10749 */
     10750static void
     10751parseheredoc(void)
     10752{
     10753    struct heredoc *here;
     10754    union node *n;
     10755
     10756    here = heredoclist;
     10757    heredoclist = 0;
     10758
     10759    while (here) {
     10760        if (needprompt) {
     10761            setprompt(2);
     10762        }
     10763        readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
     10764                here->eofmark, here->striptabs);
     10765        n = stalloc(sizeof(struct narg));
     10766        n->narg.type = NARG;
     10767        n->narg.next = NULL;
     10768        n->narg.text = wordtext;
     10769        n->narg.backquote = backquotelist;
     10770        here->here->nhere.doc = n;
     10771        here = here->next;
     10772    }
     10773}
     10774
     10775
     10776/*
     10777 * called by editline -- any expansions to the prompt should be added here.
     10778 */
     10779#if ENABLE_ASH_EXPAND_PRMT
    1083710780static const char *
    1083810781expandstr(const char *ps)
     
    1085510798#endif
    1085610799
    10857 static void setprompt(int whichprompt)
    10858 {
    10859     const char *prompt;
    10860 #ifdef CONFIG_ASH_EXPAND_PRMT
     10800/*
     10801 * Execute a command or commands contained in a string.
     10802 */
     10803static int
     10804evalstring(char *s, int mask)
     10805{
     10806    union node *n;
    1086110807    struct stackmark smark;
    10862 #endif
    10863 
    10864     needprompt = 0;
    10865 
    10866     switch (whichprompt) {
    10867     case 1:
    10868         prompt = ps1val();
    10869         break;
    10870     case 2:
    10871         prompt = ps2val();
    10872         break;
    10873     default:                        /* 0 */
    10874         prompt = nullstr;
    10875     }
    10876 #ifdef CONFIG_ASH_EXPAND_PRMT
     10808    int skip;
     10809
     10810    setinputstring(s);
    1087710811    setstackmark(&smark);
    10878     stalloc(stackblocksize());
    10879 #endif
    10880     putprompt(expandstr(prompt));
    10881 #ifdef CONFIG_ASH_EXPAND_PRMT
    10882     popstackmark(&smark);
    10883 #endif
    10884 }
    10885 
    10886 
    10887 static const char *const *findkwd(const char *s)
    10888 {
    10889     return bsearch(s, tokname_array + KWDOFFSET,
    10890                (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
    10891                    sizeof(const char *), pstrcmp);
    10892 }
    10893 
    10894 /*      redir.c      */
    10895 
    10896 /*
    10897  * Code for dealing with input/output redirection.
    10898  */
    10899 
    10900 #define EMPTY -2                /* marks an unused slot in redirtab */
    10901 #ifndef PIPE_BUF
    10902 # define PIPESIZE 4096          /* amount of buffering in a pipe */
    10903 #else
    10904 # define PIPESIZE PIPE_BUF
    10905 #endif
    10906 
    10907 /*
    10908  * Open a file in noclobber mode.
    10909  * The code was copied from bash.
    10910  */
    10911 static inline int
    10912 noclobberopen(const char *fname)
    10913 {
    10914     int r, fd;
    10915     struct stat finfo, finfo2;
    10916 
    10917     /*
    10918      * If the file exists and is a regular file, return an error
    10919      * immediately.
    10920      */
    10921     r = stat(fname, &finfo);
    10922     if (r == 0 && S_ISREG(finfo.st_mode)) {
    10923         errno = EEXIST;
    10924         return -1;
    10925     }
    10926 
    10927     /*
    10928      * If the file was not present (r != 0), make sure we open it
    10929      * exclusively so that if it is created before we open it, our open
    10930      * will fail.  Make sure that we do not truncate an existing file.
    10931      * Note that we don't turn on O_EXCL unless the stat failed -- if the
    10932      * file was not a regular file, we leave O_EXCL off.
    10933      */
    10934     if (r != 0)
    10935         return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
    10936     fd = open(fname, O_WRONLY|O_CREAT, 0666);
    10937 
    10938     /* If the open failed, return the file descriptor right away. */
    10939     if (fd < 0)
    10940         return fd;
    10941 
    10942     /*
    10943      * OK, the open succeeded, but the file may have been changed from a
    10944      * non-regular file to a regular file between the stat and the open.
    10945      * We are assuming that the O_EXCL open handles the case where FILENAME
    10946      * did not exist and is symlinked to an existing file between the stat
    10947      * and open.
    10948      */
    10949 
    10950     /*
    10951      * If we can open it and fstat the file descriptor, and neither check
    10952      * revealed that it was a regular file, and the file has not been
    10953      * replaced, return the file descriptor.
    10954      */
    10955      if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
    10956          finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
    10957         return fd;
    10958 
    10959     /* The file has been replaced.  badness. */
    10960     close(fd);
    10961     errno = EEXIST;
    10962     return -1;
    10963 }
    10964 
    10965 /*
    10966  * Handle here documents.  Normally we fork off a process to write the
    10967  * data to a pipe.  If the document is short, we can stuff the data in
    10968  * the pipe without forking.
    10969  */
    10970 
    10971 static inline int
    10972 openhere(union node *redir)
    10973 {
    10974     int pip[2];
    10975     size_t len = 0;
    10976 
    10977     if (pipe(pip) < 0)
    10978         sh_error("Pipe call failed");
    10979     if (redir->type == NHERE) {
    10980         len = strlen(redir->nhere.doc->narg.text);
    10981         if (len <= PIPESIZE) {
    10982             bb_full_write(pip[1], redir->nhere.doc->narg.text, len);
    10983             goto out;
    10984         }
    10985     }
    10986     if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
    10987         close(pip[0]);
    10988         signal(SIGINT, SIG_IGN);
    10989         signal(SIGQUIT, SIG_IGN);
    10990         signal(SIGHUP, SIG_IGN);
    10991 #ifdef SIGTSTP
    10992         signal(SIGTSTP, SIG_IGN);
    10993 #endif
    10994         signal(SIGPIPE, SIG_DFL);
    10995         if (redir->type == NHERE)
    10996             bb_full_write(pip[1], redir->nhere.doc->narg.text, len);
     10812
     10813    skip = 0;
     10814    while ((n = parsecmd(0)) != NEOF) {
     10815        evaltree(n, 0);
     10816        popstackmark(&smark);
     10817        skip = evalskip;
     10818        if (skip)
     10819            break;
     10820    }
     10821    popfile();
     10822
     10823    skip &= mask;
     10824    evalskip = skip;
     10825    return skip;
     10826}
     10827
     10828/*
     10829 * The eval command.
     10830 */
     10831static int
     10832evalcmd(int argc, char **argv)
     10833{
     10834    char *p;
     10835    char *concat;
     10836    char **ap;
     10837
     10838    if (argc > 1) {
     10839        p = argv[1];
     10840        if (argc > 2) {
     10841            STARTSTACKSTR(concat);
     10842            ap = argv + 2;
     10843            for (;;) {
     10844                concat = stack_putstr(p, concat);
     10845                p = *ap++;
     10846                if (p == NULL)
     10847                    break;
     10848                STPUTC(' ', concat);
     10849            }
     10850            STPUTC('\0', concat);
     10851            p = grabstackstr(concat);
     10852        }
     10853        evalstring(p, ~SKIPEVAL);
     10854
     10855    }
     10856    return exitstatus;
     10857}
     10858
     10859/*
     10860 * Read and execute commands.  "Top" is nonzero for the top level command
     10861 * loop; it turns on prompting if the shell is interactive.
     10862 */
     10863static int
     10864cmdloop(int top)
     10865{
     10866    union node *n;
     10867    struct stackmark smark;
     10868    int inter;
     10869    int numeof = 0;
     10870
     10871    TRACE(("cmdloop(%d) called\n", top));
     10872    for (;;) {
     10873        int skip;
     10874
     10875        setstackmark(&smark);
     10876#if JOBS
     10877        if (jobctl)
     10878            showjobs(stderr, SHOW_CHANGED);
     10879#endif
     10880        inter = 0;
     10881        if (iflag && top) {
     10882            inter++;
     10883#if ENABLE_ASH_MAIL
     10884            chkmail();
     10885#endif
     10886        }
     10887        n = parsecmd(inter);
     10888        /* showtree(n); DEBUG */
     10889        if (n == NEOF) {
     10890            if (!top || numeof >= 50)
     10891                break;
     10892            if (!stoppedjobs()) {
     10893                if (!Iflag)
     10894                    break;
     10895                out2str("\nUse \"exit\" to leave shell.\n");
     10896            }
     10897            numeof++;
     10898        } else if (nflag == 0) {
     10899            /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
     10900            job_warning >>= 1;
     10901            numeof = 0;
     10902            evaltree(n, 0);
     10903        }
     10904        popstackmark(&smark);
     10905        skip = evalskip;
     10906
     10907        if (skip) {
     10908            evalskip = 0;
     10909            return skip & SKIPEVAL;
     10910        }
     10911    }
     10912    return 0;
     10913}
     10914
     10915/*
     10916 * Take commands from a file.  To be compatible we should do a path
     10917 * search for the file, which is necessary to find sub-commands.
     10918 */
     10919static char *
     10920find_dot_file(char *name)
     10921{
     10922    char *fullname;
     10923    const char *path = pathval();
     10924    struct stat statb;
     10925
     10926    /* don't try this for absolute or relative paths */
     10927    if (strchr(name, '/'))
     10928        return name;
     10929
     10930    while ((fullname = padvance(&path, name)) != NULL) {
     10931        if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
     10932            /*
     10933             * Don't bother freeing here, since it will
     10934             * be freed by the caller.
     10935             */
     10936            return fullname;
     10937        }
     10938        stunalloc(fullname);
     10939    }
     10940
     10941    /* not found in the PATH */
     10942    ash_msg_and_raise_error("%s: not found", name);
     10943    /* NOTREACHED */
     10944}
     10945
     10946static int
     10947dotcmd(int argc, char **argv)
     10948{
     10949    struct strlist *sp;
     10950    volatile struct shparam saveparam;
     10951    int status = 0;
     10952
     10953    for (sp = cmdenviron; sp; sp = sp->next)
     10954        setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
     10955
     10956    if (argc >= 2) {        /* That's what SVR2 does */
     10957        char *fullname;
     10958
     10959        fullname = find_dot_file(argv[1]);
     10960
     10961        if (argc > 2) {
     10962            saveparam = shellparam;
     10963            shellparam.malloc = 0;
     10964            shellparam.nparam = argc - 2;
     10965            shellparam.p = argv + 2;
     10966        };
     10967
     10968        setinputfile(fullname, INPUT_PUSH_FILE);
     10969        commandname = fullname;
     10970        cmdloop(0);
     10971        popfile();
     10972
     10973        if (argc > 2) {
     10974            freeparam(&shellparam);
     10975            shellparam = saveparam;
     10976        };
     10977        status = exitstatus;
     10978    }
     10979    return status;
     10980}
     10981
     10982static int
     10983exitcmd(int argc, char **argv)
     10984{
     10985    if (stoppedjobs())
     10986        return 0;
     10987    if (argc > 1)
     10988        exitstatus = number(argv[1]);
     10989    raise_exception(EXEXIT);
     10990    /* NOTREACHED */
     10991}
     10992
     10993#if ENABLE_ASH_BUILTIN_ECHO
     10994static int
     10995echocmd(int argc, char **argv)
     10996{
     10997    return bb_echo(argv);
     10998}
     10999#endif
     11000
     11001#if ENABLE_ASH_BUILTIN_TEST
     11002static int
     11003testcmd(int argc, char **argv)
     11004{
     11005    return test_main(argc, argv);
     11006}
     11007#endif
     11008
     11009/*
     11010 * Read a file containing shell functions.
     11011 */
     11012static void
     11013readcmdfile(char *name)
     11014{
     11015    setinputfile(name, INPUT_PUSH_FILE);
     11016    cmdloop(0);
     11017    popfile();
     11018}
     11019
     11020
     11021/* ============ find_command inplementation */
     11022
     11023/*
     11024 * Resolve a command name.  If you change this routine, you may have to
     11025 * change the shellexec routine as well.
     11026 */
     11027static void
     11028find_command(char *name, struct cmdentry *entry, int act, const char *path)
     11029{
     11030    struct tblentry *cmdp;
     11031    int idx;
     11032    int prev;
     11033    char *fullname;
     11034    struct stat statb;
     11035    int e;
     11036    int updatetbl;
     11037    struct builtincmd *bcmd;
     11038
     11039    /* If name contains a slash, don't use PATH or hash table */
     11040    if (strchr(name, '/') != NULL) {
     11041        entry->u.index = -1;
     11042        if (act & DO_ABS) {
     11043            while (stat(name, &statb) < 0) {
     11044#ifdef SYSV
     11045                if (errno == EINTR)
     11046                    continue;
     11047#endif
     11048                entry->cmdtype = CMDUNKNOWN;
     11049                return;
     11050            }
     11051        }
     11052        entry->cmdtype = CMDNORMAL;
     11053        return;
     11054    }
     11055
     11056/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
     11057
     11058    updatetbl = (path == pathval());
     11059    if (!updatetbl) {
     11060        act |= DO_ALTPATH;
     11061        if (strstr(path, "%builtin") != NULL)
     11062            act |= DO_ALTBLTIN;
     11063    }
     11064
     11065    /* If name is in the table, check answer will be ok */
     11066    cmdp = cmdlookup(name, 0);
     11067    if (cmdp != NULL) {
     11068        int bit;
     11069
     11070        switch (cmdp->cmdtype) {
     11071        default:
     11072#if DEBUG
     11073            abort();
     11074#endif
     11075        case CMDNORMAL:
     11076            bit = DO_ALTPATH;
     11077            break;
     11078        case CMDFUNCTION:
     11079            bit = DO_NOFUNC;
     11080            break;
     11081        case CMDBUILTIN:
     11082            bit = DO_ALTBLTIN;
     11083            break;
     11084        }
     11085        if (act & bit) {
     11086            updatetbl = 0;
     11087            cmdp = NULL;
     11088        } else if (cmdp->rehash == 0)
     11089            /* if not invalidated by cd, we're done */
     11090            goto success;
     11091    }
     11092
     11093    /* If %builtin not in path, check for builtin next */
     11094    bcmd = find_builtin(name);
     11095    if (bcmd) {
     11096        if (IS_BUILTIN_REGULAR(bcmd))
     11097            goto builtin_success;
     11098        if (act & DO_ALTPATH) {
     11099            if (!(act & DO_ALTBLTIN))
     11100                goto builtin_success;
     11101        } else if (builtinloc <= 0) {
     11102            goto builtin_success;
     11103        }
     11104    }
     11105
     11106#if ENABLE_FEATURE_SH_STANDALONE
     11107    if (find_applet_by_name(name)) {
     11108        entry->cmdtype = CMDNORMAL;
     11109        entry->u.index = -1;
     11110        return;
     11111    }
     11112#endif
     11113
     11114    /* We have to search path. */
     11115    prev = -1;              /* where to start */
     11116    if (cmdp && cmdp->rehash) {     /* doing a rehash */
     11117        if (cmdp->cmdtype == CMDBUILTIN)
     11118            prev = builtinloc;
    1099711119        else
    10998             expandhere(redir->nhere.doc, pip[1]);
    10999         _exit(0);
    11000     }
    11001 out:
    11002     close(pip[1]);
    11003     return pip[0];
    11004 }
    11005 
     11120            prev = cmdp->param.index;
     11121    }
     11122
     11123    e = ENOENT;
     11124    idx = -1;
     11125 loop:
     11126    while ((fullname = padvance(&path, name)) != NULL) {
     11127        stunalloc(fullname);
     11128        /* NB: code below will still use fullname
     11129         * despite it being "unallocated" */
     11130        idx++;
     11131        if (pathopt) {
     11132            if (prefix(pathopt, "builtin")) {
     11133                if (bcmd)
     11134                    goto builtin_success;
     11135                continue;
     11136            } else if (!(act & DO_NOFUNC)
     11137             && prefix(pathopt, "func")) {
     11138                /* handled below */
     11139            } else {
     11140                /* ignore unimplemented options */
     11141                continue;
     11142            }
     11143        }
     11144        /* if rehash, don't redo absolute path names */
     11145        if (fullname[0] == '/' && idx <= prev) {
     11146            if (idx < prev)
     11147                continue;
     11148            TRACE(("searchexec \"%s\": no change\n", name));
     11149            goto success;
     11150        }
     11151        while (stat(fullname, &statb) < 0) {
     11152#ifdef SYSV
     11153            if (errno == EINTR)
     11154                continue;
     11155#endif
     11156            if (errno != ENOENT && errno != ENOTDIR)
     11157                e = errno;
     11158            goto loop;
     11159        }
     11160        e = EACCES;     /* if we fail, this will be the error */
     11161        if (!S_ISREG(statb.st_mode))
     11162            continue;
     11163        if (pathopt) {          /* this is a %func directory */
     11164            stalloc(strlen(fullname) + 1);
     11165            /* NB: stalloc will return space pointed by fullname
     11166             * (because we don't have any intervening allocations
     11167             * between stunalloc above and this stalloc) */
     11168            readcmdfile(fullname);
     11169            cmdp = cmdlookup(name, 0);
     11170            if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
     11171                ash_msg_and_raise_error("%s not defined in %s", name, fullname);
     11172            stunalloc(fullname);
     11173            goto success;
     11174        }
     11175        TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
     11176        if (!updatetbl) {
     11177            entry->cmdtype = CMDNORMAL;
     11178            entry->u.index = idx;
     11179            return;
     11180        }
     11181        INT_OFF;
     11182        cmdp = cmdlookup(name, 1);
     11183        cmdp->cmdtype = CMDNORMAL;
     11184        cmdp->param.index = idx;
     11185        INT_ON;
     11186        goto success;
     11187    }
     11188
     11189    /* We failed.  If there was an entry for this command, delete it */
     11190    if (cmdp && updatetbl)
     11191        delete_cmd_entry();
     11192    if (act & DO_ERR)
     11193        ash_msg("%s: %s", name, errmsg(e, "not found"));
     11194    entry->cmdtype = CMDUNKNOWN;
     11195    return;
     11196
     11197 builtin_success:
     11198    if (!updatetbl) {
     11199        entry->cmdtype = CMDBUILTIN;
     11200        entry->u.cmd = bcmd;
     11201        return;
     11202    }
     11203    INT_OFF;
     11204    cmdp = cmdlookup(name, 1);
     11205    cmdp->cmdtype = CMDBUILTIN;
     11206    cmdp->param.cmd = bcmd;
     11207    INT_ON;
     11208 success:
     11209    cmdp->rehash = 0;
     11210    entry->cmdtype = cmdp->cmdtype;
     11211    entry->u = cmdp->param;
     11212}
     11213
     11214
     11215/* ============ trap.c */
     11216
     11217/*
     11218 * The trap builtin.
     11219 */
    1100611220static int
    11007 openredirect(union node *redir)
    11008 {
    11009     char *fname;
    11010     int f;
    11011 
    11012     switch (redir->nfile.type) {
    11013     case NFROM:
    11014         fname = redir->nfile.expfname;
    11015         if ((f = open(fname, O_RDONLY)) < 0)
    11016             goto eopen;
    11017         break;
    11018     case NFROMTO:
    11019         fname = redir->nfile.expfname;
    11020         if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
    11021             goto ecreate;
    11022         break;
    11023     case NTO:
    11024         /* Take care of noclobber mode. */
    11025         if (Cflag) {
    11026             fname = redir->nfile.expfname;
    11027             if ((f = noclobberopen(fname)) < 0)
    11028                 goto ecreate;
    11029             break;
    11030         }
    11031         /* FALLTHROUGH */
    11032     case NCLOBBER:
    11033         fname = redir->nfile.expfname;
    11034         if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
    11035             goto ecreate;
    11036         break;
    11037     case NAPPEND:
    11038         fname = redir->nfile.expfname;
    11039         if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
    11040             goto ecreate;
    11041         break;
    11042     default:
    11043 #ifdef DEBUG
    11044         abort();
    11045 #endif
    11046         /* Fall through to eliminate warning. */
    11047     case NTOFD:
    11048     case NFROMFD:
    11049         f = -1;
    11050         break;
    11051     case NHERE:
    11052     case NXHERE:
    11053         f = openhere(redir);
    11054         break;
    11055     }
    11056 
    11057     return f;
    11058 ecreate:
    11059     sh_error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
    11060 eopen:
    11061     sh_error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
    11062 }
    11063 
    11064 static inline void
    11065 dupredirect(union node *redir, int f)
    11066 {
    11067     int fd = redir->nfile.fd;
    11068 
    11069     if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
    11070         if (redir->ndup.dupfd >= 0) {   /* if not ">&-" */
    11071                 copyfd(redir->ndup.dupfd, fd);
    11072         }
    11073         return;
    11074     }
    11075 
    11076     if (f != fd) {
    11077         copyfd(f, fd);
    11078         close(f);
    11079     }
    11080     return;
    11081 }
    11082 
    11083 /*
    11084  * Process a list of redirection commands.  If the REDIR_PUSH flag is set,
    11085  * old file descriptors are stashed away so that the redirection can be
    11086  * undone by calling popredir.  If the REDIR_BACKQ flag is set, then the
    11087  * standard output, and the standard error if it becomes a duplicate of
    11088  * stdout, is saved in memory.
    11089  */
    11090 
    11091 static void
    11092 redirect(union node *redir, int flags)
    11093 {
    11094     union node *n;
    11095     struct redirtab *sv;
    11096     int i;
    11097     int fd;
    11098     int newfd;
    11099     int *p;
    11100     nullredirs++;
    11101     if (!redir) {
    11102         return;
    11103     }
    11104     sv = NULL;
    11105     INTOFF;
    11106     if (flags & REDIR_PUSH) {
    11107         struct redirtab *q;
    11108         q = ckmalloc(sizeof (struct redirtab));
    11109         q->next = redirlist;
    11110         redirlist = q;
    11111         q->nullredirs = nullredirs - 1;
    11112         for (i = 0 ; i < 10 ; i++)
    11113             q->renamed[i] = EMPTY;
    11114         nullredirs = 0;
    11115         sv = q;
    11116     }
    11117     n = redir;
    11118     do {
    11119         fd = n->nfile.fd;
    11120         if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
    11121             n->ndup.dupfd == fd)
    11122             continue; /* redirect from/to same file descriptor */
    11123 
    11124         newfd = openredirect(n);
    11125         if (fd == newfd)
    11126             continue;
    11127         if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
    11128             i = fcntl(fd, F_DUPFD, 10);
    11129 
    11130             if (i == -1) {
    11131                 i = errno;
    11132                 if (i != EBADF) {
    11133                     close(newfd);
    11134                     errno = i;
    11135                     sh_error("%d: %m", fd);
    11136                     /* NOTREACHED */
    11137                 }
    11138             } else {
    11139                 *p = i;
    11140                 close(fd);
    11141             }
    11142         } else {
    11143             close(fd);
    11144         }
    11145         dupredirect(n, newfd);
    11146     } while ((n = n->nfile.next));
    11147     INTON;
    11148     if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0)
    11149         preverrout_fd = sv->renamed[2];
    11150 }
    11151 
    11152 
    11153 /*
    11154  * Undo the effects of the last redirection.
    11155  */
    11156 
    11157 void
    11158 popredir(int drop)
    11159 {
    11160     struct redirtab *rp;
    11161     int i;
    11162 
    11163     if (--nullredirs >= 0)
    11164         return;
    11165     INTOFF;
    11166     rp = redirlist;
    11167     for (i = 0 ; i < 10 ; i++) {
    11168         if (rp->renamed[i] != EMPTY) {
    11169             if (!drop) {
    11170                 close(i);
    11171                 copyfd(rp->renamed[i], i);
    11172             }
    11173             close(rp->renamed[i]);
    11174         }
    11175     }
    11176     redirlist = rp->next;
    11177     nullredirs = rp->nullredirs;
    11178     ckfree(rp);
    11179     INTON;
    11180 }
    11181 
    11182 /*
    11183  * Undo all redirections.  Called on error or interrupt.
    11184  */
    11185 
    11186 /*
    11187  * Discard all saved file descriptors.
    11188  */
    11189 
    11190 void
    11191 clearredir(int drop)
    11192 {
    11193     for (;;) {
    11194         nullredirs = 0;
    11195         if (!redirlist)
    11196             break;
    11197         popredir(drop);
    11198     }
    11199 }
    11200 
    11201 
    11202 /*
    11203  * Copy a file descriptor to be >= to.  Returns -1
    11204  * if the source file descriptor is closed, EMPTY if there are no unused
    11205  * file descriptors left.
    11206  */
    11207 
    11208 int
    11209 copyfd(int from, int to)
    11210 {
    11211     int newfd;
    11212 
    11213     newfd = fcntl(from, F_DUPFD, to);
    11214     if (newfd < 0) {
    11215         if (errno == EMFILE)
    11216             return EMPTY;
    11217         else
    11218             sh_error("%d: %m", from);
    11219     }
    11220     return newfd;
    11221 }
    11222 
    11223 
    11224 int
    11225 redirectsafe(union node *redir, int flags)
    11226 {
    11227     int err;
    11228     volatile int saveint;
    11229     struct jmploc *volatile savehandler = handler;
    11230     struct jmploc jmploc;
    11231 
    11232     SAVEINT(saveint);
    11233     if (!(err = setjmp(jmploc.loc) * 2)) {
    11234         handler = &jmploc;
    11235         redirect(redir, flags);
    11236     }
    11237     handler = savehandler;
    11238     if (err && exception != EXERROR)
    11239         longjmp(handler->loc, 1);
    11240     RESTOREINT(saveint);
    11241     return err;
    11242 }
    11243 
    11244 /*      show.c    */
    11245 
    11246 #ifdef DEBUG
    11247 static void shtree(union node *, int, char *, FILE*);
    11248 static void shcmd(union node *, FILE *);
    11249 static void sharg(union node *, FILE *);
    11250 static void indent(int, char *, FILE *);
    11251 static void trstring(char *);
    11252 
    11253 
    11254 void
    11255 showtree(union node *n)
    11256 {
    11257     trputs("showtree called\n");
    11258     shtree(n, 1, NULL, stdout);
    11259 }
    11260 
    11261 
    11262 static void
    11263 shtree(union node *n, int ind, char *pfx, FILE *fp)
    11264 {
    11265     struct nodelist *lp;
    11266     const char *s;
    11267 
    11268     if (n == NULL)
    11269         return;
    11270 
    11271     indent(ind, pfx, fp);
    11272     switch(n->type) {
    11273     case NSEMI:
    11274         s = "; ";
    11275         goto binop;
    11276     case NAND:
    11277         s = " && ";
    11278         goto binop;
    11279     case NOR:
    11280         s = " || ";
    11281 binop:
    11282         shtree(n->nbinary.ch1, ind, NULL, fp);
    11283        /*    if (ind < 0) */
    11284             fputs(s, fp);
    11285         shtree(n->nbinary.ch2, ind, NULL, fp);
    11286         break;
    11287     case NCMD:
    11288         shcmd(n, fp);
    11289         if (ind >= 0)
    11290             putc('\n', fp);
    11291         break;
    11292     case NPIPE:
    11293         for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
    11294             shcmd(lp->n, fp);
    11295             if (lp->next)
    11296                 fputs(" | ", fp);
    11297         }
    11298         if (n->npipe.backgnd)
    11299             fputs(" &", fp);
    11300         if (ind >= 0)
    11301             putc('\n', fp);
    11302         break;
    11303     default:
    11304         fprintf(fp, "<node type %d>", n->type);
    11305         if (ind >= 0)
    11306             putc('\n', fp);
    11307         break;
    11308     }
    11309 }
    11310 
    11311 
    11312 static void
    11313 shcmd(union node *cmd, FILE *fp)
    11314 {
    11315     union node *np;
    11316     int first;
    11317     const char *s;
    11318     int dftfd;
    11319 
    11320     first = 1;
    11321     for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
    11322         if (! first)
    11323             putchar(' ');
    11324         sharg(np, fp);
    11325         first = 0;
    11326     }
    11327     for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
    11328         if (! first)
    11329             putchar(' ');
    11330         switch (np->nfile.type) {
    11331             case NTO:       s = ">";  dftfd = 1; break;
    11332             case NCLOBBER:  s = ">|"; dftfd = 1; break;
    11333             case NAPPEND:   s = ">>"; dftfd = 1; break;
    11334             case NTOFD:     s = ">&"; dftfd = 1; break;
    11335             case NFROM:     s = "<";  dftfd = 0; break;
    11336             case NFROMFD:   s = "<&"; dftfd = 0; break;
    11337             case NFROMTO:   s = "<>"; dftfd = 0; break;
    11338             default:        s = "*error*"; dftfd = 0; break;
    11339         }
    11340         if (np->nfile.fd != dftfd)
    11341             fprintf(fp, "%d", np->nfile.fd);
    11342         fputs(s, fp);
    11343         if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
    11344             fprintf(fp, "%d", np->ndup.dupfd);
    11345         } else {
    11346             sharg(np->nfile.fname, fp);
    11347         }
    11348         first = 0;
    11349     }
    11350 }
    11351 
    11352 
    11353 
    11354 static void
    11355 sharg(union node *arg, FILE *fp)
    11356 {
    11357     char *p;
    11358     struct nodelist *bqlist;
    11359     int subtype;
    11360 
    11361     if (arg->type != NARG) {
    11362         out1fmt("<node type %d>\n", arg->type);
    11363         abort();
    11364     }
    11365     bqlist = arg->narg.backquote;
    11366     for (p = arg->narg.text ; *p ; p++) {
    11367         switch (*p) {
    11368         case CTLESC:
    11369             putc(*++p, fp);
    11370             break;
    11371         case CTLVAR:
    11372             putc('$', fp);
    11373             putc('{', fp);
    11374             subtype = *++p;
    11375             if (subtype == VSLENGTH)
    11376                 putc('#', fp);
    11377 
    11378             while (*p != '=')
    11379                 putc(*p++, fp);
    11380 
    11381             if (subtype & VSNUL)
    11382                 putc(':', fp);
    11383 
    11384             switch (subtype & VSTYPE) {
    11385             case VSNORMAL:
    11386                 putc('}', fp);
    11387                 break;
    11388             case VSMINUS:
    11389                 putc('-', fp);
    11390                 break;
    11391             case VSPLUS:
    11392                 putc('+', fp);
    11393                 break;
    11394             case VSQUESTION:
    11395                 putc('?', fp);
    11396                 break;
    11397             case VSASSIGN:
    11398                 putc('=', fp);
    11399                 break;
    11400             case VSTRIMLEFT:
    11401                 putc('#', fp);
    11402                 break;
    11403             case VSTRIMLEFTMAX:
    11404                 putc('#', fp);
    11405                 putc('#', fp);
    11406                 break;
    11407             case VSTRIMRIGHT:
    11408                 putc('%', fp);
    11409                 break;
    11410             case VSTRIMRIGHTMAX:
    11411                 putc('%', fp);
    11412                 putc('%', fp);
    11413                 break;
    11414             case VSLENGTH:
    11415                 break;
    11416             default:
    11417                 out1fmt("<subtype %d>", subtype);
    11418             }
    11419             break;
    11420         case CTLENDVAR:
    11421              putc('}', fp);
    11422              break;
    11423         case CTLBACKQ:
    11424         case CTLBACKQ|CTLQUOTE:
    11425             putc('$', fp);
    11426             putc('(', fp);
    11427             shtree(bqlist->n, -1, NULL, fp);
    11428             putc(')', fp);
    11429             break;
    11430         default:
    11431             putc(*p, fp);
    11432             break;
    11433         }
    11434     }
    11435 }
    11436 
    11437 
    11438 static void
    11439 indent(int amount, char *pfx, FILE *fp)
    11440 {
    11441     int i;
    11442 
    11443     for (i = 0 ; i < amount ; i++) {
    11444         if (pfx && i == amount - 1)
    11445             fputs(pfx, fp);
    11446         putc('\t', fp);
    11447     }
    11448 }
    11449 
    11450 
    11451 
    11452 /*
    11453  * Debugging stuff.
    11454  */
    11455 
    11456 
    11457 FILE *tracefile;
    11458 
    11459 
    11460 void
    11461 trputc(int c)
    11462 {
    11463     if (debug != 1)
    11464         return;
    11465     putc(c, tracefile);
    11466 }
    11467 
    11468 void
    11469 trace(const char *fmt, ...)
    11470 {
    11471     va_list va;
    11472 
    11473     if (debug != 1)
    11474         return;
    11475     va_start(va, fmt);
    11476     (void) vfprintf(tracefile, fmt, va);
    11477     va_end(va);
    11478 }
    11479 
    11480 void
    11481 tracev(const char *fmt, va_list va)
    11482 {
    11483     if (debug != 1)
    11484         return;
    11485     (void) vfprintf(tracefile, fmt, va);
    11486 }
    11487 
    11488 
    11489 void
    11490 trputs(const char *s)
    11491 {
    11492     if (debug != 1)
    11493         return;
    11494     fputs(s, tracefile);
    11495 }
    11496 
    11497 
    11498 static void
    11499 trstring(char *s)
    11500 {
    11501     char *p;
    11502     char c;
    11503 
    11504     if (debug != 1)
    11505         return;
    11506     putc('"', tracefile);
    11507     for (p = s ; *p ; p++) {
    11508         switch (*p) {
    11509         case '\n':  c = 'n';  goto backslash;
    11510         case '\t':  c = 't';  goto backslash;
    11511         case '\r':  c = 'r';  goto backslash;
    11512         case '"':  c = '"';  goto backslash;
    11513         case '\\':  c = '\\';  goto backslash;
    11514         case CTLESC:  c = 'e';  goto backslash;
    11515         case CTLVAR:  c = 'v';  goto backslash;
    11516         case CTLVAR+CTLQUOTE:  c = 'V';  goto backslash;
    11517         case CTLBACKQ:  c = 'q';  goto backslash;
    11518         case CTLBACKQ+CTLQUOTE:  c = 'Q';  goto backslash;
    11519 backslash:        putc('\\', tracefile);
    11520             putc(c, tracefile);
    11521             break;
    11522         default:
    11523             if (*p >= ' ' && *p <= '~')
    11524                 putc(*p, tracefile);
    11525             else {
    11526                 putc('\\', tracefile);
    11527                 putc(*p >> 6 & 03, tracefile);
    11528                 putc(*p >> 3 & 07, tracefile);
    11529                 putc(*p & 07, tracefile);
    11530             }
    11531             break;
    11532         }
    11533     }
    11534     putc('"', tracefile);
    11535 }
    11536 
    11537 
    11538 void
    11539 trargs(char **ap)
    11540 {
    11541     if (debug != 1)
    11542         return;
    11543     while (*ap) {
    11544         trstring(*ap++);
    11545         if (*ap)
    11546             putc(' ', tracefile);
    11547         else
    11548             putc('\n', tracefile);
    11549     }
    11550 }
    11551 
    11552 
    11553 void
    11554 opentrace(void)
    11555 {
    11556     char s[100];
    11557 #ifdef O_APPEND
    11558     int flags;
    11559 #endif
    11560 
    11561     if (debug != 1) {
    11562         if (tracefile)
    11563             fflush(tracefile);
    11564         /* leave open because libedit might be using it */
    11565         return;
    11566     }
    11567     scopy("./trace", s);
    11568     if (tracefile) {
    11569         if (!freopen(s, "a", tracefile)) {
    11570             fprintf(stderr, "Can't re-open %s\n", s);
    11571             debug = 0;
    11572             return;
    11573         }
    11574     } else {
    11575         if ((tracefile = fopen(s, "a")) == NULL) {
    11576             fprintf(stderr, "Can't open %s\n", s);
    11577             debug = 0;
    11578             return;
    11579         }
    11580     }
    11581 #ifdef O_APPEND
    11582     if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
    11583         fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
    11584 #endif
    11585     setlinebuf(tracefile);
    11586     fputs("\nTracing started.\n", tracefile);
    11587 }
    11588 #endif /* DEBUG */
    11589 
    11590 
    11591 /*      trap.c       */
    11592 
    11593 /*
    11594  * Sigmode records the current value of the signal handlers for the various
    11595  * modes.  A value of zero means that the current handler is not known.
    11596  * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
    11597  */
    11598 
    11599 #define S_DFL 1                 /* default signal handling (SIG_DFL) */
    11600 #define S_CATCH 2               /* signal is caught */
    11601 #define S_IGN 3                 /* signal is ignored (SIG_IGN) */
    11602 #define S_HARD_IGN 4            /* signal is ignored permenantly */
    11603 #define S_RESET 5               /* temporary - to reset a hard ignored sig */
    11604 
    11605 
    11606 
    11607 /*
    11608  * The trap builtin.
    11609  */
    11610 
    11611 int
    1161211221trapcmd(int argc, char **argv)
    1161311222{
     
    1161911228    ap = argptr;
    1162011229    if (!*ap) {
    11621         for (signo = 0 ; signo < NSIG ; signo++) {
     11230        for (signo = 0; signo < NSIG; signo++) {
    1162211231            if (trap[signo] != NULL) {
    1162311232                const char *sn;
    1162411233
    11625                 sn = u_signal_names(0, &signo, 0);
    11626                 if (sn == NULL)
    11627                     sn = "???";
     11234                sn = get_signame(signo);
    1162811235                out1fmt("trap -- %s %s\n",
    1162911236                    single_quote(trap[signo]), sn);
     
    1163711244        action = *ap++;
    1163811245    while (*ap) {
    11639         if ((signo = decode_signal(*ap, 0)) < 0)
    11640             sh_error("%s: bad trap", *ap);
    11641         INTOFF;
     11246        signo = get_signum(*ap);
     11247        if (signo < 0)
     11248            ash_msg_and_raise_error("%s: bad trap", *ap);
     11249        INT_OFF;
    1164211250        if (action) {
    11643             if (action[0] == '-' && action[1] == '\0')
     11251            if (LONE_DASH(action))
    1164411252                action = NULL;
    1164511253            else
    11646                 action = savestr(action);
     11254                action = ckstrdup(action);
    1164711255        }
    1164811256        if (trap[signo])
    11649             ckfree(trap[signo]);
     11257            free(trap[signo]);
    1165011258        trap[signo] = action;
    1165111259        if (signo != 0)
    1165211260            setsignal(signo);
    11653         INTON;
     11261        INT_ON;
    1165411262        ap++;
    1165511263    }
     
    1165811266
    1165911267
    11660 /*
    11661  * Clear traps on a fork.
    11662  */
    11663 
    11664 void
    11665 clear_traps(void)
    11666 {
    11667     char **tp;
    11668 
    11669     for (tp = trap ; tp < &trap[NSIG] ; tp++) {
    11670         if (*tp && **tp) {      /* trap not NULL or SIG_IGN */
    11671             INTOFF;
    11672             ckfree(*tp);
    11673             *tp = NULL;
    11674             if (tp != &trap[0])
    11675                 setsignal(tp - trap);
    11676             INTON;
    11677         }
    11678     }
    11679 }
    11680 
    11681 
    11682 /*
    11683  * Set the signal handler for the specified signal.  The routine figures
    11684  * out what it should be set to.
    11685  */
    11686 
    11687 void
    11688 setsignal(int signo)
    11689 {
    11690     int action;
    11691     char *t, tsig;
    11692     struct sigaction act;
    11693 
    11694     if ((t = trap[signo]) == NULL)
    11695         action = S_DFL;
    11696     else if (*t != '\0')
    11697         action = S_CATCH;
    11698     else
    11699         action = S_IGN;
    11700     if (rootshell && action == S_DFL) {
    11701         switch (signo) {
    11702         case SIGINT:
    11703             if (iflag || minusc || sflag == 0)
    11704                 action = S_CATCH;
    11705             break;
    11706         case SIGQUIT:
    11707 #ifdef DEBUG
    11708             if (debug)
    11709                 break;
    11710 #endif
    11711             /* FALLTHROUGH */
    11712         case SIGTERM:
    11713             if (iflag)
    11714                 action = S_IGN;
    11715             break;
    11716 #if JOBS
    11717         case SIGTSTP:
    11718         case SIGTTOU:
    11719             if (mflag)
    11720                 action = S_IGN;
    11721             break;
    11722 #endif
    11723         }
    11724     }
    11725 
    11726     t = &sigmode[signo - 1];
    11727     tsig = *t;
    11728     if (tsig == 0) {
    11729         /*
    11730          * current setting unknown
    11731          */
    11732         if (sigaction(signo, 0, &act) == -1) {
    11733             /*
    11734              * Pretend it worked; maybe we should give a warning
    11735              * here, but other shells don't. We don't alter
    11736              * sigmode, so that we retry every time.
    11737              */
    11738             return;
    11739         }
    11740         if (act.sa_handler == SIG_IGN) {
    11741             if (mflag && (signo == SIGTSTP ||
    11742                  signo == SIGTTIN || signo == SIGTTOU)) {
    11743                 tsig = S_IGN;   /* don't hard ignore these */
    11744             } else
    11745                 tsig = S_HARD_IGN;
    11746         } else {
    11747             tsig = S_RESET; /* force to be set */
    11748         }
    11749     }
    11750     if (tsig == S_HARD_IGN || tsig == action)
    11751         return;
    11752     switch (action) {
    11753     case S_CATCH:
    11754         act.sa_handler = onsig;
    11755         break;
    11756     case S_IGN:
    11757         act.sa_handler = SIG_IGN;
    11758         break;
    11759     default:
    11760         act.sa_handler = SIG_DFL;
    11761     }
    11762     *t = action;
    11763     act.sa_flags = 0;
    11764     sigfillset(&act.sa_mask);
    11765     sigaction(signo, &act, 0);
    11766 }
    11767 
    11768 /*
    11769  * Ignore a signal.
    11770  */
    11771 
    11772 void
    11773 ignoresig(int signo)
    11774 {
    11775     if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
    11776         signal(signo, SIG_IGN);
    11777     }
    11778     sigmode[signo - 1] = S_HARD_IGN;
    11779 }
    11780 
    11781 
    11782 /*
    11783  * Signal handler.
    11784  */
    11785 
    11786 void
    11787 onsig(int signo)
    11788 {
    11789     gotsig[signo - 1] = 1;
    11790     pendingsigs = signo;
    11791 
    11792     if (exsig || (signo == SIGINT && !trap[SIGINT])) {
    11793         if (!suppressint)
    11794             onint();
    11795         intpending = 1;
    11796     }
    11797 }
    11798 
    11799 
    11800 /*
    11801  * Called to execute a trap.  Perhaps we should avoid entering new trap
    11802  * handlers while we are executing a trap handler.
    11803  */
    11804 
    11805 int
    11806 dotrap(void)
    11807 {
    11808     char *p;
    11809     char *q;
    11810     int i;
    11811     int savestatus;
    11812     int skip = 0;
    11813 
    11814     savestatus = exitstatus;
    11815     pendingsigs = 0;
    11816     xbarrier();
    11817 
    11818     for (i = 0, q = gotsig; i < NSIG - 1; i++, q++) {
    11819         if (!*q)
    11820             continue;
    11821         *q = 0;
    11822 
    11823         p = trap[i + 1];
    11824         if (!p)
    11825             continue;
    11826         skip = evalstring(p, SKIPEVAL);
    11827         exitstatus = savestatus;
    11828         if (skip)
    11829             break;
    11830     }
    11831 
    11832     return skip;
    11833 }
    11834 
    11835 
    11836 /*
    11837  * Controls whether the shell is interactive or not.
    11838  */
    11839 
    11840 void
    11841 setinteractive(int on)
    11842 {
    11843     static int is_interactive;
    11844 
    11845     if (++on == is_interactive)
    11846         return;
    11847     is_interactive = on;
    11848     setsignal(SIGINT);
    11849     setsignal(SIGQUIT);
    11850     setsignal(SIGTERM);
    11851 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
    11852         if(is_interactive > 1) {
    11853             /* Looks like they want an interactive shell */
    11854             static int do_banner;
    11855 
    11856                 if(!do_banner) {
    11857                     out1fmt(
    11858             "\n\n%s Built-in shell (ash)\n"
    11859             "Enter 'help' for a list of built-in commands.\n\n",
    11860                     BB_BANNER);
    11861                     do_banner++;
    11862                 }
    11863         }
    11864 #endif
    11865 }
    11866 
    11867 
    11868 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
    11869 /*** List the available builtins ***/
    11870 
    11871 static int helpcmd(int argc, char **argv)
     11268/* ============ Builtins */
     11269
     11270#if !ENABLE_FEATURE_SH_EXTRA_QUIET
     11271/*
     11272 * Lists available builtins
     11273 */
     11274static int
     11275helpcmd(int argc, char **argv)
    1187211276{
    1187311277    int col, i;
    1187411278
    1187511279    out1fmt("\nBuilt-in commands:\n-------------------\n");
    11876     for (col = 0, i = 0; i < NUMBUILTINS; i++) {
     11280    for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
    1187711281        col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
    11878                       builtincmd[i].name + 1);
     11282                    builtintab[i].name + 1);
    1187911283        if (col > 60) {
    1188011284            out1fmt("\n");
     
    1188211286        }
    1188311287    }
    11884 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
    11885     {
    11886         extern const struct BB_applet applets[];
    11887         extern const size_t NUM_APPLETS;
    11888 
    11889         for (i = 0; i < NUM_APPLETS; i++) {
    11890 
    11891             col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
    11892             if (col > 60) {
    11893                 out1fmt("\n");
    11894                 col = 0;
    11895             }
     11288#if ENABLE_FEATURE_SH_STANDALONE
     11289    for (i = 0; i < NUM_APPLETS; i++) {
     11290        col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
     11291        if (col > 60) {
     11292            out1fmt("\n");
     11293            col = 0;
    1189611294        }
    1189711295    }
     
    1190011298    return EXIT_SUCCESS;
    1190111299}
    11902 #endif /* CONFIG_FEATURE_SH_EXTRA_QUIET */
    11903 
    11904 /*
    11905  * Called to exit the shell.
    11906  */
    11907 
    11908 void
    11909 exitshell(void)
    11910 {
    11911     struct jmploc loc;
    11912     char *p;
    11913     int status;
    11914 
    11915     status = exitstatus;
    11916     TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
    11917     if (setjmp(loc.loc)) {
    11918         if (exception == EXEXIT)
    11919             _exit(exitstatus);
    11920         goto out;
    11921     }
    11922     handler = &loc;
    11923     if ((p = trap[0])) {
    11924         trap[0] = NULL;
    11925         evalstring(p, 0);
    11926     }
    11927     flushall();
    11928     setjobctl(0);
    11929 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
    11930     if (iflag && rootshell) {
    11931         const char *hp = lookupvar("HISTFILE");
    11932 
    11933         if(hp != NULL )
    11934             save_history ( hp );
    11935     }
    11936 #endif
    11937 out:
    11938     _exit(status);
    11939     /* NOTREACHED */
    11940 }
    11941 
    11942 static int decode_signal(const char *string, int minsig)
    11943 {
    11944     int signo;
    11945     const char *name = u_signal_names(string, &signo, minsig);
    11946 
    11947     return name ? signo : -1;
    11948 }
    11949 
    11950 /*      var.c     */
    11951 
    11952 static struct var *vartab[VTABSIZE];
    11953 
    11954 static int vpcmp(const void *, const void *);
    11955 static struct var **findvar(struct var **, const char *);
    11956 
    11957 /*
    11958  * Initialize the variable symbol tables and import the environment
    11959  */
    11960 
    11961 
    11962 #ifdef CONFIG_ASH_GETOPTS
    11963 /*
    11964  * Safe version of setvar, returns 1 on success 0 on failure.
    11965  */
    11966 
    11967 int
    11968 setvarsafe(const char *name, const char *val, int flags)
    11969 {
    11970     int err;
    11971     volatile int saveint;
    11972     struct jmploc *volatile savehandler = handler;
    11973     struct jmploc jmploc;
    11974 
    11975     SAVEINT(saveint);
    11976     if (setjmp(jmploc.loc))
    11977         err = 1;
    11978     else {
    11979         handler = &jmploc;
    11980         setvar(name, val, flags);
    11981         err = 0;
    11982     }
    11983     handler = savehandler;
    11984     RESTOREINT(saveint);
    11985     return err;
    11986 }
    11987 #endif
    11988 
    11989 /*
    11990  * Set the value of a variable.  The flags argument is ored with the
    11991  * flags of the variable.  If val is NULL, the variable is unset.
    11992  */
    11993 
    11994 static void
    11995 setvar(const char *name, const char *val, int flags)
    11996 {
    11997     char *p, *q;
    11998     size_t namelen;
    11999     char *nameeq;
    12000     size_t vallen;
    12001 
    12002     q = endofname(name);
    12003     p = strchrnul(q, '=');
    12004     namelen = p - name;
    12005     if (!namelen || p != q)
    12006         sh_error("%.*s: bad variable name", namelen, name);
    12007     vallen = 0;
    12008     if (val == NULL) {
    12009         flags |= VUNSET;
    12010     } else {
    12011         vallen = strlen(val);
    12012     }
    12013     INTOFF;
    12014     p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
    12015     if (val) {
    12016         *p++ = '=';
    12017         p = mempcpy(p, val, vallen);
    12018     }
    12019     *p = '\0';
    12020     setvareq(nameeq, flags | VNOSAVE);
    12021     INTON;
    12022 }
    12023 
    12024 
    12025 /*
    12026  * Same as setvar except that the variable and value are passed in
    12027  * the first argument as name=value.  Since the first argument will
    12028  * be actually stored in the table, it should not be a string that
    12029  * will go away.
    12030  * Called with interrupts off.
    12031  */
    12032 
    12033 void
    12034 setvareq(char *s, int flags)
    12035 {
    12036     struct var *vp, **vpp;
    12037 
    12038     vpp = hashvar(s);
    12039     flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
    12040     vp = *findvar(vpp, s);
    12041     if (vp) {
    12042         if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
    12043             const char *n;
    12044 
    12045             if (flags & VNOSAVE)
    12046                 free(s);
    12047             n = vp->text;
    12048             sh_error("%.*s: is read only", strchrnul(n, '=') - n, n);
    12049         }
    12050 
    12051         if (flags & VNOSET)
    12052             return;
    12053 
    12054         if (vp->func && (flags & VNOFUNC) == 0)
    12055             (*vp->func)(strchrnul(s, '=') + 1);
    12056 
    12057         if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
    12058             ckfree(vp->text);
    12059 
    12060         flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
    12061     } else {
    12062         if (flags & VNOSET)
    12063             return;
    12064         /* not found */
    12065         vp = ckmalloc(sizeof (*vp));
    12066         vp->next = *vpp;
    12067         vp->func = NULL;
    12068         *vpp = vp;
    12069     }
    12070     if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
    12071         s = savestr(s);
    12072     vp->text = s;
    12073     vp->flags = flags;
    12074 }
    12075 
    12076 
    12077 /*
    12078  * Process a linked list of variable assignments.
    12079  */
    12080 
    12081 static void
    12082 listsetvar(struct strlist *list_set_var, int flags)
    12083 {
    12084     struct strlist *lp = list_set_var;
    12085 
    12086     if (!lp)
    12087         return;
    12088     INTOFF;
    12089     do {
    12090         setvareq(lp->text, flags);
    12091     } while ((lp = lp->next));
    12092     INTON;
    12093 }
    12094 
    12095 
    12096 /*
    12097  * Find the value of a variable.  Returns NULL if not set.
    12098  */
    12099 
    12100 static char *
    12101 lookupvar(const char *name)
    12102 {
    12103     struct var *v;
    12104 
    12105     if ((v = *findvar(hashvar(name), name))) {
    12106 #ifdef DYNAMIC_VAR
    12107     /*
    12108      * Dynamic variables are implemented roughly the same way they are
    12109      * in bash. Namely, they're "special" so long as they aren't unset.
    12110      * As soon as they're unset, they're no longer dynamic, and dynamic
    12111      * lookup will no longer happen at that point. -- PFM.
    12112      */
    12113         if((v->flags & VDYNAMIC))
    12114             (*v->func)(NULL);
    12115 #endif
    12116         if(!(v->flags & VUNSET))
    12117             return strchrnul(v->text, '=') + 1;
    12118     }
    12119 
    12120     return NULL;
    12121 }
    12122 
    12123 
    12124 /*
    12125  * Search the environment of a builtin command.
    12126  */
    12127 
    12128 static char *
    12129 bltinlookup(const char *name)
    12130 {
    12131     struct strlist *sp;
    12132 
    12133     for (sp = cmdenviron ; sp ; sp = sp->next) {
    12134         if (varequal(sp->text, name))
    12135             return strchrnul(sp->text, '=') + 1;
    12136     }
    12137     return lookupvar(name);
    12138 }
    12139 
    12140 
    12141 /*
    12142  * Generate a list of variables satisfying the given conditions.
    12143  */
    12144 
    12145 static char **
    12146 listvars(int on, int off, char ***end)
    12147 {
    12148     struct var **vpp;
    12149     struct var *vp;
    12150     char **ep;
    12151     int mask;
    12152 
    12153     STARTSTACKSTR(ep);
    12154     vpp = vartab;
    12155     mask = on | off;
    12156     do {
    12157         for (vp = *vpp ; vp ; vp = vp->next)
    12158             if ((vp->flags & mask) == on) {
    12159                 if (ep == stackstrend())
    12160                     ep = growstackstr();
    12161                 *ep++ = (char *) vp->text;
    12162             }
    12163     } while (++vpp < vartab + VTABSIZE);
    12164     if (ep == stackstrend())
    12165         ep = growstackstr();
    12166     if (end)
    12167         *end = ep;
    12168     *ep++ = NULL;
    12169     return grabstackstr(ep);
    12170 }
    12171 
    12172 
    12173 /*
    12174  * POSIX requires that 'set' (but not export or readonly) output the
    12175  * variables in lexicographic order - by the locale's collating order (sigh).
    12176  * Maybe we could keep them in an ordered balanced binary tree
    12177  * instead of hashed lists.
    12178  * For now just roll 'em through qsort for printing...
    12179  */
    12180 
    12181 static int
    12182 showvars(const char *sep_prefix, int on, int off)
    12183 {
    12184     const char *sep;
    12185     char **ep, **epend;
    12186 
    12187     ep = listvars(on, off, &epend);
    12188     qsort(ep, epend - ep, sizeof(char *), vpcmp);
    12189 
    12190     sep = *sep_prefix ? spcstr : sep_prefix;
    12191 
    12192     for (; ep < epend; ep++) {
    12193         const char *p;
    12194         const char *q;
    12195 
    12196         p = strchrnul(*ep, '=');
    12197         q = nullstr;
    12198         if (*p)
    12199             q = single_quote(++p);
    12200 
    12201         out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
    12202     }
    12203 
    12204     return 0;
    12205 }
    12206 
    12207 
     11300#endif /* FEATURE_SH_EXTRA_QUIET */
    1220811301
    1220911302/*
    1221011303 * The export and readonly commands.
    1221111304 */
    12212 
    1221311305static int
    1221411306exportcmd(int argc, char **argv)
     
    1221911311    char **aptr;
    1222011312    int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
    12221     int notp;
    12222 
    12223     notp = nextopt("p") - 'p';
    12224     if (notp && ((name = *(aptr = argptr)))) {
    12225         do {
    12226             if ((p = strchr(name, '=')) != NULL) {
    12227                 p++;
    12228             } else {
    12229                 if ((vp = *findvar(hashvar(name), name))) {
    12230                     vp->flags |= flag;
    12231                     continue;
     11313
     11314    if (nextopt("p") != 'p') {
     11315        aptr = argptr;
     11316        name = *aptr;
     11317        if (name) {
     11318            do {
     11319                p = strchr(name, '=');
     11320                if (p != NULL) {
     11321                    p++;
     11322                } else {
     11323                    vp = *findvar(hashvar(name), name);
     11324                    if (vp) {
     11325                        vp->flags |= flag;
     11326                        continue;
     11327                    }
    1223211328                }
    12233             }
    12234             setvar(name, p, flag);
    12235         } while ((name = *++aptr) != NULL);
    12236     } else {
    12237         showvars(argv[0], flag, 0);
    12238     }
     11329                setvar(name, p, flag);
     11330            } while ((name = *++aptr) != NULL);
     11331            return 0;
     11332        }
     11333    }
     11334    showvars(argv[0], flag, 0);
    1223911335    return 0;
    1224011336}
    1224111337
    12242 
    12243 /*
    12244  * Make a variable a local variable.  When a variable is made local, it's
    12245  * value and flags are saved in a localvar structure.  The saved values
    12246  * will be restored when the shell function returns.  We handle the name
    12247  * "-" as a special case.
    12248  */
    12249 
    12250 static inline void
    12251 mklocal(char *name)
    12252 {
    12253     struct localvar *lvp;
    12254     struct var **vpp;
    12255     struct var *vp;
    12256 
    12257     INTOFF;
    12258     lvp = ckmalloc(sizeof (struct localvar));
    12259     if (name[0] == '-' && name[1] == '\0') {
    12260         char *p;
    12261         p = ckmalloc(sizeof(optlist));
    12262         lvp->text = memcpy(p, optlist, sizeof(optlist));
    12263         vp = NULL;
    12264     } else {
    12265         char *eq;
    12266 
    12267         vpp = hashvar(name);
    12268         vp = *findvar(vpp, name);
    12269         eq = strchr(name, '=');
    12270         if (vp == NULL) {
    12271             if (eq)
    12272                 setvareq(name, VSTRFIXED);
    12273             else
    12274                 setvar(name, NULL, VSTRFIXED);
    12275             vp = *vpp;      /* the new variable */
    12276             lvp->flags = VUNSET;
    12277         } else {
    12278             lvp->text = vp->text;
    12279             lvp->flags = vp->flags;
    12280             vp->flags |= VSTRFIXED|VTEXTFIXED;
    12281             if (eq)
    12282                 setvareq(name, 0);
    12283         }
    12284     }
    12285     lvp->vp = vp;
    12286     lvp->next = localvars;
    12287     localvars = lvp;
    12288     INTON;
    12289 }
    12290 
    12291 /*
    12292  * The "local" command.
    12293  */
    12294 
    12295 static int
    12296 localcmd(int argc, char **argv)
    12297 {
    12298     char *name;
    12299 
    12300     argv = argptr;
    12301     while ((name = *argv++) != NULL) {
    12302         mklocal(name);
    12303     }
    12304     return 0;
    12305 }
    12306 
    12307 
    12308 /*
    12309  * Called after a function returns.
    12310  * Interrupts must be off.
    12311  */
    12312 
    12313 static void
    12314 poplocalvars(void)
    12315 {
    12316     struct localvar *lvp;
    12317     struct var *vp;
    12318 
    12319     while ((lvp = localvars) != NULL) {
    12320         localvars = lvp->next;
    12321         vp = lvp->vp;
    12322         TRACE(("poplocalvar %s", vp ? vp->text : "-"));
    12323         if (vp == NULL) {       /* $- saved */
    12324             memcpy(optlist, lvp->text, sizeof(optlist));
    12325             ckfree(lvp->text);
    12326             optschanged();
    12327         } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
    12328             unsetvar(vp->text);
    12329         } else {
    12330             if (vp->func)
    12331                 (*vp->func)(strchrnul(lvp->text, '=') + 1);
    12332             if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
    12333                 ckfree(vp->text);
    12334             vp->flags = lvp->flags;
    12335             vp->text = lvp->text;
    12336         }
    12337         ckfree(lvp);
    12338     }
    12339 }
    12340 
     11338/*
     11339 * Delete a function if it exists.
     11340 */
     11341static void
     11342unsetfunc(const char *name)
     11343{
     11344    struct tblentry *cmdp;
     11345
     11346    cmdp = cmdlookup(name, 0);
     11347    if (cmdp!= NULL && cmdp->cmdtype == CMDFUNCTION)
     11348        delete_cmd_entry();
     11349}
    1234111350
    1234211351/*
     
    1234511354 * with the same name.
    1234611355 */
    12347 
    12348 int
     11356static int
    1234911357unsetcmd(int argc, char **argv)
    1235011358{
     
    1235811366    }
    1235911367
    12360     for (ap = argptr; *ap ; ap++) {
     11368    for (ap = argptr; *ap; ap++) {
    1236111369        if (flag != 'f') {
    1236211370            i = unsetvar(*ap);
     
    1237211380
    1237311381
    12374 /*
    12375  * Unset the specified variable.
    12376  */
    12377 
    12378 int
    12379 unsetvar(const char *s)
    12380 {
    12381     struct var **vpp;
    12382     struct var *vp;
    12383     int retval;
    12384 
    12385     vpp = findvar(hashvar(s), s);
    12386     vp = *vpp;
    12387     retval = 2;
    12388     if (vp) {
    12389         int flags = vp->flags;
    12390 
    12391         retval = 1;
    12392         if (flags & VREADONLY)
    12393             goto out;
    12394 #ifdef DYNAMIC_VAR
    12395         vp->flags &= ~VDYNAMIC;
    12396 #endif
    12397         if (flags & VUNSET)
    12398             goto ok;
    12399         if ((flags & VSTRFIXED) == 0) {
    12400             INTOFF;
    12401             if ((flags & (VTEXTFIXED|VSTACK)) == 0)
    12402                 ckfree(vp->text);
    12403             *vpp = vp->next;
    12404             ckfree(vp);
    12405             INTON;
    12406         } else {
    12407             setvar(s, 0, 0);
    12408             vp->flags &= ~VEXPORT;
    12409         }
    12410 ok:
    12411         retval = 0;
    12412     }
    12413 
    12414 out:
    12415     return retval;
    12416 }
    12417 
    12418 
    12419 
    12420 /*
    12421  * Find the appropriate entry in the hash table from the name.
    12422  */
    12423 
    12424 static struct var **
    12425 hashvar(const char *p)
    12426 {
    12427     unsigned int hashval;
    12428 
    12429     hashval = ((unsigned char) *p) << 4;
    12430     while (*p && *p != '=')
    12431         hashval += (unsigned char) *p++;
    12432     return &vartab[hashval % VTABSIZE];
    12433 }
    12434 
    12435 
    12436 
    12437 /*
    12438  * Compares two strings up to the first = or '\0'.  The first
    12439  * string must be terminated by '='; the second may be terminated by
    12440  * either '=' or '\0'.
    12441  */
    12442 
    12443 int
    12444 varcmp(const char *p, const char *q)
    12445 {
    12446     int c, d;
    12447 
    12448     while ((c = *p) == (d = *q)) {
    12449         if (!c || c == '=')
    12450             goto out;
    12451         p++;
    12452         q++;
    12453     }
    12454     if (c == '=')
    12455         c = 0;
    12456     if (d == '=')
    12457         d = 0;
    12458 out:
    12459     return c - d;
    12460 }
    12461 
    12462 static int
    12463 vpcmp(const void *a, const void *b)
    12464 {
    12465     return varcmp(*(const char **)a, *(const char **)b);
    12466 }
    12467 
    12468 static struct var **
    12469 findvar(struct var **vpp, const char *name)
    12470 {
    12471     for (; *vpp; vpp = &(*vpp)->next) {
    12472         if (varequal((*vpp)->text, name)) {
    12473             break;
    12474         }
    12475     }
    12476     return vpp;
    12477 }
    1247811382/*      setmode.c      */
    1247911383
    1248011384#include <sys/times.h>
    1248111385
    12482 static const unsigned char timescmd_str[] = {
     11386static const unsigned char timescmd_str[] ALIGN1 = {
    1248311387    ' ',  offsetof(struct tms, tms_utime),
    1248411388    '\n', offsetof(struct tms, tms_stime),
     
    1248811392};
    1248911393
    12490 static int timescmd(int ac, char **av)
    12491 {
    12492     long int clk_tck, s, t;
     11394static int
     11395timescmd(int ac, char **av)
     11396{
     11397    long clk_tck, s, t;
    1249311398    const unsigned char *p;
    1249411399    struct tms buf;
     
    1251011415}
    1251111416
    12512 #ifdef CONFIG_ASH_MATH_SUPPORT
     11417#if ENABLE_ASH_MATH_SUPPORT
    1251311418static arith_t
    1251411419dash_arith(const char *s)
     
    1251711422    int errcode = 0;
    1251811423
    12519     INTOFF;
     11424    INT_OFF;
    1252011425    result = arith(s, &errcode);
    1252111426    if (errcode < 0) {
    1252211427        if (errcode == -3)
    12523             sh_error("exponent less than 0");
    12524         else if (errcode == -2)
    12525             sh_error("divide by zero");
    12526         else if (errcode == -5)
    12527             sh_error("expression recursion loop detected");
    12528         else
    12529             synerror(s);
    12530     }
    12531     INTON;
    12532 
    12533     return (result);
    12534 }
    12535 
     11428            ash_msg_and_raise_error("exponent less than 0");
     11429        if (errcode == -2)
     11430            ash_msg_and_raise_error("divide by zero");
     11431        if (errcode == -5)
     11432            ash_msg_and_raise_error("expression recursion loop detected");
     11433        raise_error_syntax(s);
     11434    }
     11435    INT_ON;
     11436
     11437    return result;
     11438}
    1253611439
    1253711440/*
     
    1254111444 *  Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
    1254211445 */
    12543 
    1254411446static int
    1254511447letcmd(int argc, char **argv)
    1254611448{
    1254711449    char **ap;
    12548     arith_t i;
     11450    arith_t i = 0;
    1254911451
    1255011452    ap = argv + 1;
    12551     if(!*ap)
    12552         sh_error("expression expected");
     11453    if (!*ap)
     11454        ash_msg_and_raise_error("expression expected");
    1255311455    for (ap = argv + 1; *ap; ap++) {
    1255411456        i = dash_arith(*ap);
    1255511457    }
    1255611458
    12557     return (!i);
    12558 }
    12559 #endif /* CONFIG_ASH_MATH_SUPPORT */
    12560 
    12561 /*      miscbltin.c  */
    12562 
    12563 /*
     11459    return !i;
     11460}
     11461#endif /* ASH_MATH_SUPPORT */
     11462
     11463
     11464/* ============ miscbltin.c
     11465 *
    1256411466 * Miscellaneous builtins.
    1256511467 */
     
    1256711469#undef rflag
    1256811470
    12569 #ifdef __GLIBC__
    12570 #if __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
     11471#if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
    1257111472typedef enum __rlimit_resource rlim_t;
    1257211473#endif
    12573 #endif
    12574 
    1257511474
    1257611475/*
     
    1258011479 * This uses unbuffered input, which may be avoidable in some cases.
    1258111480 */
    12582 
    1258311481static int
    1258411482readcmd(int argc, char **argv)
     
    1259411492    int status;
    1259511493    int i;
    12596 #if defined(CONFIG_ASH_READ_NCHARS)
     11494#if ENABLE_ASH_READ_NCHARS
    1259711495    int nch_flag = 0;
    1259811496    int nchars = 0;
     
    1260011498    struct termios tty, old_tty;
    1260111499#endif
    12602 #if defined(CONFIG_ASH_READ_TIMEOUT)
     11500#if ENABLE_ASH_READ_TIMEOUT
    1260311501    fd_set set;
    1260411502    struct timeval ts;
     
    1260911507    rflag = 0;
    1261011508    prompt = NULL;
    12611 #if defined(CONFIG_ASH_READ_NCHARS) && defined(CONFIG_ASH_READ_TIMEOUT)
     11509#if ENABLE_ASH_READ_NCHARS && ENABLE_ASH_READ_TIMEOUT
    1261211510    while ((i = nextopt("p:rt:n:s")) != '\0')
    12613 #elif defined(CONFIG_ASH_READ_NCHARS)
     11511#elif ENABLE_ASH_READ_NCHARS
    1261411512    while ((i = nextopt("p:rn:s")) != '\0')
    12615 #elif defined(CONFIG_ASH_READ_TIMEOUT)
     11513#elif ENABLE_ASH_READ_TIMEOUT
    1261611514    while ((i = nextopt("p:rt:")) != '\0')
    1261711515#else
     
    1261911517#endif
    1262011518    {
    12621         switch(i) {
     11519        switch (i) {
    1262211520        case 'p':
    1262311521            prompt = optionarg;
    1262411522            break;
    12625 #if defined(CONFIG_ASH_READ_NCHARS)
     11523#if ENABLE_ASH_READ_NCHARS
    1262611524        case 'n':
    1262711525            nchars = strtol(optionarg, &p, 10);
    1262811526            if (*p)
    12629                 sh_error("invalid count");
     11527                ash_msg_and_raise_error("invalid count");
    1263011528            nch_flag = (nchars > 0);
    1263111529            break;
     
    1263411532            break;
    1263511533#endif
    12636 #if defined(CONFIG_ASH_READ_TIMEOUT)
     11534#if ENABLE_ASH_READ_TIMEOUT
    1263711535        case 't':
    1263811536            ts.tv_sec = strtol(optionarg, &p, 10);
     
    1264411542                    ts.tv_usec = strtol(p, &p2, 10);
    1264511543                    if (*p2)
    12646                         sh_error("invalid timeout");
     11544                        ash_msg_and_raise_error("invalid timeout");
    1264711545                    scale = p2 - p;
    1264811546                    /* normalize to usec */
    1264911547                    if (scale > 6)
    12650                         sh_error("invalid timeout");
     11548                        ash_msg_and_raise_error("invalid timeout");
    1265111549                    while (scale++ < 6)
    1265211550                        ts.tv_usec *= 10;
    1265311551                }
    1265411552            } else if (*p) {
    12655                 sh_error("invalid timeout");
     11553                ash_msg_and_raise_error("invalid timeout");
    1265611554            }
    1265711555            if ( ! ts.tv_sec && ! ts.tv_usec)
    12658                 sh_error("invalid timeout");
     11556                ash_msg_and_raise_error("invalid timeout");
    1265911557            break;
    1266011558#endif
     
    1266911567        out2str(prompt);
    1267011568    }
    12671     if (*(ap = argptr) == NULL)
    12672         sh_error("arg count");
    12673     if ((ifs = bltinlookup("IFS")) == NULL)
     11569    ap = argptr;
     11570    if (*ap == NULL)
     11571        ash_msg_and_raise_error("arg count");
     11572    ifs = bltinlookup("IFS");
     11573    if (ifs == NULL)
    1267411574        ifs = defifs;
    12675 #if defined(CONFIG_ASH_READ_NCHARS)
     11575#if ENABLE_ASH_READ_NCHARS
    1267611576    if (nch_flag || silent) {
    1267711577        tcgetattr(0, &tty);
    1267811578        old_tty = tty;
    1267911579        if (nch_flag) {
    12680             tty.c_lflag &= ~ICANON;
    12681             tty.c_cc[VMIN] = nchars;
     11580            tty.c_lflag &= ~ICANON;
     11581            tty.c_cc[VMIN] = nchars;
    1268211582        }
    1268311583        if (silent) {
    12684             tty.c_lflag &= ~(ECHO|ECHOK|ECHONL);
     11584            tty.c_lflag &= ~(ECHO|ECHOK|ECHONL);
    1268511585
    1268611586        }
     
    1268811588    }
    1268911589#endif
    12690 #if defined(CONFIG_ASH_READ_TIMEOUT)
     11590#if ENABLE_ASH_READ_TIMEOUT
    1269111591    if (ts.tv_sec || ts.tv_usec) {
    12692         FD_ZERO (&set);
    12693         FD_SET (0, &set);
    12694 
    12695         i = select (FD_SETSIZE, &set, NULL, NULL, &ts);
     11592        FD_ZERO(&set);
     11593        FD_SET(0, &set);
     11594
     11595        i = select(FD_SETSIZE, &set, NULL, NULL, &ts);
    1269611596        if (!i) {
    12697 #if defined(CONFIG_ASH_READ_NCHARS)
     11597#if ENABLE_ASH_READ_NCHARS
    1269811598            if (nch_flag)
    1269911599                tcsetattr(0, TCSANOW, &old_tty);
     
    1270711607    backslash = 0;
    1270811608    STARTSTACKSTR(p);
    12709 #if defined(CONFIG_ASH_READ_NCHARS)
     11609#if ENABLE_ASH_READ_NCHARS
    1271011610    while (!nch_flag || nchars--)
    1271111611#else
     
    1274211642            STARTSTACKSTR(p);
    1274311643        } else {
    12744 put:
     11644 put:
    1274511645            STPUTC(c, p);
    1274611646        }
    1274711647    }
    12748 #if defined(CONFIG_ASH_READ_NCHARS)
     11648#if ENABLE_ASH_READ_NCHARS
    1274911649    if (nch_flag || silent)
    1275011650        tcsetattr(0, TCSANOW, &old_tty);
     
    1276111661}
    1276211662
    12763 
    12764 static int umaskcmd(int argc, char **argv)
    12765 {
    12766     static const char permuser[3] = "ugo";
    12767     static const char permmode[3] = "rwx";
    12768     static const short int permmask[] = {
     11663static int
     11664umaskcmd(int argc, char **argv)
     11665{
     11666    static const char permuser[3] ALIGN1 = "ugo";
     11667    static const char permmode[3] ALIGN1 = "rwx";
     11668    static const short permmask[] ALIGN2 = {
    1276911669        S_IRUSR, S_IWUSR, S_IXUSR,
    1277011670        S_IRGRP, S_IWGRP, S_IXGRP,
     
    1278111681    }
    1278211682
    12783     INTOFF;
     11683    INT_OFF;
    1278411684    mask = umask(0);
    1278511685    umask(mask);
    12786     INTON;
    12787 
    12788     if ((ap = *argptr) == NULL) {
     11686    INT_ON;
     11687
     11688    ap = *argptr;
     11689    if (ap == NULL) {
    1278911690        if (symbolic_mode) {
    1279011691            char buf[18];
     
    1280911710        }
    1281011711    } else {
    12811         if (is_digit((unsigned char) *ap)) {
     11712        if (isdigit((unsigned char) *ap)) {
    1281211713            mask = 0;
    1281311714            do {
    1281411715                if (*ap >= '8' || *ap < '0')
    12815                     sh_error(illnum, argv[1]);
     11716                    ash_msg_and_raise_error(illnum, argv[1]);
    1281611717                mask = (mask << 3) + (*ap - '0');
    1281711718            } while (*++ap != '\0');
     
    1282011721            mask = ~mask & 0777;
    1282111722            if (!bb_parse_mode(ap, &mask)) {
    12822                 sh_error("Illegal mode: %s", ap);
     11723                ash_msg_and_raise_error("illegal mode: %s", ap);
    1282311724            }
    1282411725            umask(~mask & 0777);
     
    1287911780    { "locks",                      RLIMIT_LOCKS,      1, 'w' },
    1288011781#endif
    12881     { (char *) 0,                   0,                 0,  '\0' }
     11782    { NULL,                         0,                 0,  '\0' }
    1288211783};
    1288311784
    1288411785enum limtype { SOFT = 0x1, HARD = 0x2 };
    1288511786
    12886 static void printlim(enum limtype how, const struct rlimit *limit,
     11787static void
     11788printlim(enum limtype how, const struct rlimit *limit,
    1288711789            const struct limits *l)
    1288811790{
     
    1290111803}
    1290211804
    12903 int
     11805static int
    1290411806ulimitcmd(int argc, char **argv)
    1290511807{
    12906     int     c;
     11808    int c;
    1290711809    rlim_t val = 0;
    1290811810    enum limtype how = SOFT | HARD;
    12909     const struct limits     *l;
    12910     int             set, all = 0;
    12911     int             optc, what;
    12912     struct rlimit   limit;
     11811    const struct limits *l;
     11812    int set, all = 0;
     11813    int optc, what;
     11814    struct rlimit limit;
    1291311815
    1291411816    what = 'f';
     
    1294711849                "w"
    1294811850#endif
    12949                         )) != '\0')
     11851                    )) != '\0')
    1295011852        switch (optc) {
    1295111853        case 'H':
     
    1297011872
    1297111873        if (all || argptr[1])
    12972             sh_error("too many arguments");
     11874            ash_msg_and_raise_error("too many arguments");
    1297311875        if (strncmp(p, "unlimited\n", 9) == 0)
    1297411876            val = RLIM_INFINITY;
     
    1297611878            val = (rlim_t) 0;
    1297711879
    12978             while ((c = *p++) >= '0' && c <= '9')
    12979             {
     11880            while ((c = *p++) >= '0' && c <= '9') {
    1298011881                val = (val * 10) + (long)(c - '0');
    1298111882                if (val < (rlim_t) 0)
     
    1298311884            }
    1298411885            if (c)
    12985                 sh_error("bad number");
     11886                ash_msg_and_raise_error("bad number");
    1298611887            val *= l->factor;
    1298711888        }
     
    1300311904            limit.rlim_cur = val;
    1300411905        if (setrlimit(l->cmd, &limit) < 0)
    13005             sh_error("error setting limit (%m)");
     11906            ash_msg_and_raise_error("error setting limit (%m)");
    1300611907    } else {
    1300711908        printlim(how, &limit, l);
     
    1301111912
    1301211913
    13013 #ifdef CONFIG_ASH_MATH_SUPPORT
     11914/* ============ Math support */
     11915
     11916#if ENABLE_ASH_MATH_SUPPORT
    1301411917
    1301511918/* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
     
    1310712010 */
    1310812011
    13109 
    1311012012#define arith_isspace(arithval) \
    1311112013    (arithval == ' ' || arithval == '\n' || arithval == '\t')
    13112 
    1311312014
    1311412015typedef unsigned char operator;
     
    1314112042
    1314212043/* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
    13143 #define convert_prec_is_assing(prec) do { if(prec == 3) prec = 2; } while(0)
     12044#define convert_prec_is_assing(prec) do { if (prec == 3) prec = 2; } while (0)
    1314412045
    1314512046/* conditional is right associativity too */
     
    1320312104#define NUMPTR (*numstackptr)
    1320412105
    13205 static inline int tok_have_assign(operator op)
     12106static int
     12107tok_have_assign(operator op)
    1320612108{
    1320712109    operator prec = PREC(op);
     
    1321212114}
    1321312115
    13214 static inline int is_right_associativity(operator prec)
    13215 {
    13216     return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) ||
    13217         prec == PREC(TOK_CONDITIONAL));
    13218 }
    13219 
     12116static int
     12117is_right_associativity(operator prec)
     12118{
     12119    return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT)
     12120            || prec == PREC(TOK_CONDITIONAL));
     12121}
    1322012122
    1322112123typedef struct ARITCH_VAR_NUM {
     
    1322712129} v_n_t;
    1322812130
    13229 
    1323012131typedef struct CHK_VAR_RECURSIVE_LOOPED {
    1323112132    const char *var;
     
    1323512136static chk_var_recursive_looped_t *prev_chk_var_recursive;
    1323612137
    13237 
    13238 static int arith_lookup_val(v_n_t *t)
    13239 {
    13240     if(t->var) {
    13241     const char * p = lookupvar(t->var);
    13242 
    13243     if(p) {
    13244         int errcode;
    13245 
    13246         /* recursive try as expression */
    13247         chk_var_recursive_looped_t *cur;
    13248         chk_var_recursive_looped_t cur_save;
    13249 
    13250         for(cur = prev_chk_var_recursive; cur; cur = cur->next) {
    13251         if(strcmp(cur->var, t->var) == 0) {
    13252             /* expression recursion loop detected */
    13253             return -5;
    13254         }
    13255         }
    13256         /* save current lookuped var name */
    13257         cur = prev_chk_var_recursive;
    13258         cur_save.var = t->var;
    13259         cur_save.next = cur;
    13260         prev_chk_var_recursive = &cur_save;
    13261 
    13262         t->val = arith (p, &errcode);
    13263         /* restore previous ptr after recursiving */
    13264         prev_chk_var_recursive = cur;
    13265         return errcode;
    13266     } else {
    13267         /* allow undefined var as 0 */
    13268         t->val = 0;
    13269     }
    13270     }
    13271     return 0;
     12138static int
     12139arith_lookup_val(v_n_t *t)
     12140{
     12141    if (t->var) {
     12142        const char * p = lookupvar(t->var);
     12143
     12144        if (p) {
     12145            int errcode;
     12146
     12147            /* recursive try as expression */
     12148            chk_var_recursive_looped_t *cur;
     12149            chk_var_recursive_looped_t cur_save;
     12150
     12151            for (cur = prev_chk_var_recursive; cur; cur = cur->next) {
     12152                if (strcmp(cur->var, t->var) == 0) {
     12153                    /* expression recursion loop detected */
     12154                    return -5;
     12155                }
     12156            }
     12157            /* save current lookuped var name */
     12158            cur = prev_chk_var_recursive;
     12159            cur_save.var = t->var;
     12160            cur_save.next = cur;
     12161            prev_chk_var_recursive = &cur_save;
     12162
     12163            t->val = arith (p, &errcode);
     12164            /* restore previous ptr after recursiving */
     12165            prev_chk_var_recursive = cur;
     12166            return errcode;
     12167        }
     12168        /* allow undefined var as 0 */
     12169        t->val = 0;
     12170    }
     12171    return 0;
    1327212172}
    1327312173
     
    1327512175 * stack. For a unary operator it will only change the top element, but a
    1327612176 * binary operator will pop two arguments and push a result */
    13277 static inline int
     12177static int
    1327812178arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
    1327912179{
     
    1328212182    int ret_arith_lookup_val;
    1328312183
    13284     if (NUMPTR == numstack) goto err; /* There is no operator that can work
    13285                                          without arguments */
     12184    /* There is no operator that can work without arguments */
     12185    if (NUMPTR == numstack) goto err;
    1328612186    numptr_m1 = NUMPTR - 1;
    1328712187
    1328812188    /* check operand is var with noninteger value */
    1328912189    ret_arith_lookup_val = arith_lookup_val(numptr_m1);
    13290     if(ret_arith_lookup_val)
     12190    if (ret_arith_lookup_val)
    1329112191        return ret_arith_lookup_val;
    1329212192
     
    1330512205        /* Binary operators */
    1330612206
    13307         /* check and binary operators need two arguments */
    13308         if (numptr_m1 == numstack) goto err;
    13309 
    13310         /* ... and they pop one */
    13311         --NUMPTR;
    13312         numptr_val = rez;
    13313         if (op == TOK_CONDITIONAL) {
    13314         if(! numptr_m1->contidional_second_val_initialized) {
    13315             /* protect $((expr1 ? expr2)) without ": expr" */
    13316             goto err;
    13317         }
    13318         rez = numptr_m1->contidional_second_val;
    13319         } else if(numptr_m1->contidional_second_val_initialized) {
    13320             /* protect $((expr1 : expr2)) without "expr ? " */
    13321             goto err;
    13322         }
    13323         numptr_m1 = NUMPTR - 1;
    13324         if(op != TOK_ASSIGN) {
    13325         /* check operand is var with noninteger value for not '=' */
    13326         ret_arith_lookup_val = arith_lookup_val(numptr_m1);
    13327         if(ret_arith_lookup_val)
    13328             return ret_arith_lookup_val;
    13329         }
    13330         if (op == TOK_CONDITIONAL) {
    13331             numptr_m1->contidional_second_val = rez;
    13332         }
    13333         rez = numptr_m1->val;
    13334         if (op == TOK_BOR || op == TOK_OR_ASSIGN)
     12207        /* check and binary operators need two arguments */
     12208        if (numptr_m1 == numstack) goto err;
     12209
     12210        /* ... and they pop one */
     12211        --NUMPTR;
     12212        numptr_val = rez;
     12213        if (op == TOK_CONDITIONAL) {
     12214            if (! numptr_m1->contidional_second_val_initialized) {
     12215                /* protect $((expr1 ? expr2)) without ": expr" */
     12216                goto err;
     12217            }
     12218            rez = numptr_m1->contidional_second_val;
     12219        } else if (numptr_m1->contidional_second_val_initialized) {
     12220            /* protect $((expr1 : expr2)) without "expr ? " */
     12221            goto err;
     12222        }
     12223        numptr_m1 = NUMPTR - 1;
     12224        if (op != TOK_ASSIGN) {
     12225            /* check operand is var with noninteger value for not '=' */
     12226            ret_arith_lookup_val = arith_lookup_val(numptr_m1);
     12227            if (ret_arith_lookup_val)
     12228                return ret_arith_lookup_val;
     12229        }
     12230        if (op == TOK_CONDITIONAL) {
     12231            numptr_m1->contidional_second_val = rez;
     12232        }
     12233        rez = numptr_m1->val;
     12234        if (op == TOK_BOR || op == TOK_OR_ASSIGN)
    1333512235            rez |= numptr_val;
    13336         else if (op == TOK_OR)
     12236        else if (op == TOK_OR)
    1333712237            rez = numptr_val || rez;
    13338         else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
     12238        else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
    1333912239            rez &= numptr_val;
    13340         else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
     12240        else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
    1334112241            rez ^= numptr_val;
    13342         else if (op == TOK_AND)
     12242        else if (op == TOK_AND)
    1334312243            rez = rez && numptr_val;
    13344         else if (op == TOK_EQ)
     12244        else if (op == TOK_EQ)
    1334512245            rez = (rez == numptr_val);
    13346         else if (op == TOK_NE)
     12246        else if (op == TOK_NE)
    1334712247            rez = (rez != numptr_val);
    13348         else if (op == TOK_GE)
     12248        else if (op == TOK_GE)
    1334912249            rez = (rez >= numptr_val);
    13350         else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
     12250        else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
    1335112251            rez >>= numptr_val;
    13352         else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
     12252        else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
    1335312253            rez <<= numptr_val;
    13354         else if (op == TOK_GT)
     12254        else if (op == TOK_GT)
    1335512255            rez = (rez > numptr_val);
    13356         else if (op == TOK_LT)
     12256        else if (op == TOK_LT)
    1335712257            rez = (rez < numptr_val);
    13358         else if (op == TOK_LE)
     12258        else if (op == TOK_LE)
    1335912259            rez = (rez <= numptr_val);
    13360         else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
     12260        else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
    1336112261            rez *= numptr_val;
    13362         else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
     12262        else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
    1336312263            rez += numptr_val;
    13364         else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
     12264        else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
    1336512265            rez -= numptr_val;
    13366         else if (op == TOK_ASSIGN || op == TOK_COMMA)
     12266        else if (op == TOK_ASSIGN || op == TOK_COMMA)
    1336712267            rez = numptr_val;
    13368         else if (op == TOK_CONDITIONAL_SEP) {
     12268        else if (op == TOK_CONDITIONAL_SEP) {
    1336912269            if (numptr_m1 == numstack) {
    13370                 /* protect $((expr : expr)) without "expr ? " */
    13371                 goto err;
     12270                /* protect $((expr : expr)) without "expr ? " */
     12271                goto err;
    1337212272            }
    1337312273            numptr_m1->contidional_second_val_initialized = op;
    1337412274            numptr_m1->contidional_second_val = numptr_val;
    13375         }
    13376         else if (op == TOK_CONDITIONAL) {
     12275        } else if (op == TOK_CONDITIONAL) {
    1337712276            rez = rez ?
    13378                   numptr_val : numptr_m1->contidional_second_val;
    13379         }
    13380         else if(op == TOK_EXPONENT) {
    13381             if(numptr_val < 0)
     12277                numptr_val : numptr_m1->contidional_second_val;
     12278        } else if (op == TOK_EXPONENT) {
     12279            if (numptr_val < 0)
    1338212280                return -3;      /* exponent less than 0 */
    1338312281            else {
    1338412282                arith_t c = 1;
    1338512283
    13386                 if(numptr_val)
    13387                     while(numptr_val--)
     12284                if (numptr_val)
     12285                    while (numptr_val--)
    1338812286                        c *= rez;
    1338912287                rez = c;
    1339012288            }
    13391         }
    13392         else if(numptr_val==0)          /* zero divisor check */
     12289        } else if (numptr_val==0)          /* zero divisor check */
    1339312290            return -2;
    13394         else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
     12291        else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
    1339512292            rez /= numptr_val;
    13396         else if (op == TOK_REM || op == TOK_REM_ASSIGN)
     12293        else if (op == TOK_REM || op == TOK_REM_ASSIGN)
    1339712294            rez %= numptr_val;
    1339812295    }
    13399     if(tok_have_assign(op)) {
    13400         char buf[32];
    13401 
    13402         if(numptr_m1->var == NULL) {
     12296    if (tok_have_assign(op)) {
     12297        char buf[sizeof(arith_t_type)*3 + 2];
     12298
     12299        if (numptr_m1->var == NULL) {
    1340312300            /* Hmm, 1=2 ? */
    1340412301            goto err;
    1340512302        }
    1340612303        /* save to shell variable */
    13407 #ifdef CONFIG_ASH_MATH_SUPPORT_64
    13408         snprintf(buf, sizeof(buf), "%lld", arith_t_type rez);
     12304#if ENABLE_ASH_MATH_SUPPORT_64
     12305        snprintf(buf, sizeof(buf), "%lld", (arith_t_type) rez);
    1340912306#else
    13410         snprintf(buf, sizeof(buf), "%ld", arith_t_type rez);
     12307        snprintf(buf, sizeof(buf), "%ld", (arith_t_type) rez);
    1341112308#endif
    1341212309        setvar(numptr_m1->var, buf, 0);
    1341312310        /* after saving, make previous value for v++ or v-- */
    13414         if(op == TOK_POST_INC)
     12311        if (op == TOK_POST_INC)
    1341512312            rez--;
    13416         else if(op == TOK_POST_DEC)
     12313        else if (op == TOK_POST_DEC)
    1341712314            rez++;
    1341812315    }
     
    1342112318    numptr_m1->var = NULL;
    1342212319    return 0;
    13423 err: return(-1);
    13424 }
    13425 
    13426 /* longest must first */
    13427 static const char op_tokens[] = {
     12320 err:
     12321    return -1;
     12322}
     12323
     12324/* longest must be first */
     12325static const char op_tokens[] ALIGN1 = {
    1342812326    '<','<','=',0, TOK_LSHIFT_ASSIGN,
    1342912327    '>','>','=',0, TOK_RSHIFT_ASSIGN,
     
    1347112369#define endexpression &op_tokens[sizeof(op_tokens)-7]
    1347212370
    13473 
    13474 static arith_t arith (const char *expr, int *perrcode)
    13475 {
    13476     register char arithval; /* Current character under analysis */
    13477     operator lasttok, op;
    13478     operator prec;
    13479 
    13480     const char *p = endexpression;
    13481     int errcode;
    13482 
    13483     size_t datasizes = strlen(expr) + 2;
    13484 
    13485     /* Stack of integers */
    13486     /* The proof that there can be no more than strlen(startbuf)/2+1 integers
    13487      * in any given correct or incorrect expression is left as an exercise to
    13488      * the reader. */
    13489     v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
    13490         *numstackptr = numstack;
    13491     /* Stack of operator tokens */
    13492     operator *stack = alloca((datasizes) * sizeof(operator)),
    13493         *stackptr = stack;
    13494 
    13495     *stackptr++ = lasttok = TOK_LPAREN;     /* start off with a left paren */
    13496     *perrcode = errcode = 0;
    13497 
    13498     while(1) {
    13499     if ((arithval = *expr) == 0) {
    13500         if (p == endexpression) {
    13501             /* Null expression. */
    13502             return 0;
    13503         }
    13504 
    13505         /* This is only reached after all tokens have been extracted from the
    13506          * input stream. If there are still tokens on the operator stack, they
    13507          * are to be applied in order. At the end, there should be a final
    13508          * result on the integer stack */
    13509 
    13510         if (expr != endexpression + 1) {
    13511             /* If we haven't done so already, */
    13512             /* append a closing right paren */
    13513             expr = endexpression;
    13514             /* and let the loop process it. */
    13515             continue;
    13516         }
    13517         /* At this point, we're done with the expression. */
    13518         if (numstackptr != numstack+1) {
    13519             /* ... but if there isn't, it's bad */
    13520           err:
    13521             return (*perrcode = -1);
    13522         }
    13523         if(numstack->var) {
    13524             /* expression is $((var)) only, lookup now */
    13525             errcode = arith_lookup_val(numstack);
    13526         }
    13527     ret:
    13528         *perrcode = errcode;
    13529         return numstack->val;
    13530     } else {
     12371static arith_t
     12372arith(const char *expr, int *perrcode)
     12373{
     12374    char arithval; /* Current character under analysis */
     12375    operator lasttok, op;
     12376    operator prec;
     12377
     12378    const char *p = endexpression;
     12379    int errcode;
     12380
     12381    size_t datasizes = strlen(expr) + 2;
     12382
     12383    /* Stack of integers */
     12384    /* The proof that there can be no more than strlen(startbuf)/2+1 integers
     12385     * in any given correct or incorrect expression is left as an exercise to
     12386     * the reader. */
     12387    v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
     12388                *numstackptr = numstack;
     12389    /* Stack of operator tokens */
     12390    operator *stack = alloca((datasizes) * sizeof(operator)),
     12391                *stackptr = stack;
     12392
     12393    *stackptr++ = lasttok = TOK_LPAREN;     /* start off with a left paren */
     12394    *perrcode = errcode = 0;
     12395
     12396    while (1) {
     12397        arithval = *expr;
     12398        if (arithval == 0) {
     12399            if (p == endexpression) {
     12400                /* Null expression. */
     12401                return 0;
     12402            }
     12403
     12404            /* This is only reached after all tokens have been extracted from the
     12405             * input stream. If there are still tokens on the operator stack, they
     12406             * are to be applied in order. At the end, there should be a final
     12407             * result on the integer stack */
     12408
     12409            if (expr != endexpression + 1) {
     12410                /* If we haven't done so already, */
     12411                /* append a closing right paren */
     12412                expr = endexpression;
     12413                /* and let the loop process it. */
     12414                continue;
     12415            }
     12416            /* At this point, we're done with the expression. */
     12417            if (numstackptr != numstack+1) {
     12418                /* ... but if there isn't, it's bad */
     12419 err:
     12420                return (*perrcode = -1);
     12421            }
     12422            if (numstack->var) {
     12423                /* expression is $((var)) only, lookup now */
     12424                errcode = arith_lookup_val(numstack);
     12425            }
     12426 ret:
     12427            *perrcode = errcode;
     12428            return numstack->val;
     12429        }
     12430
    1353112431        /* Continue processing the expression. */
    1353212432        if (arith_isspace(arithval)) {
     
    1353412434            goto prologue;
    1353512435        }
    13536         if((p = endofname(expr)) != expr) {
     12436        p = endofname(expr);
     12437        if (p != expr) {
    1353712438            size_t var_name_size = (p-expr) + 1;  /* trailing zero */
    1353812439
     
    1354012441            safe_strncpy(numstackptr->var, expr, var_name_size);
    1354112442            expr = p;
    13542         num:
     12443 num:
    1354312444            numstackptr->contidional_second_val_initialized = 0;
    1354412445            numstackptr++;
    1354512446            lasttok = TOK_NUM;
    1354612447            continue;
    13547         } else if (is_digit(arithval)) {
     12448        }
     12449        if (isdigit(arithval)) {
    1354812450            numstackptr->var = NULL;
    13549 #ifdef CONFIG_ASH_MATH_SUPPORT_64
     12451#if ENABLE_ASH_MATH_SUPPORT_64
    1355012452            numstackptr->val = strtoll(expr, (char **) &expr, 0);
    1355112453#else
     
    1355412456            goto num;
    1355512457        }
    13556         for(p = op_tokens; ; p++) {
     12458        for (p = op_tokens; ; p++) {
    1355712459            const char *o;
    1355812460
    13559             if(*p == 0) {
     12461            if (*p == 0) {
    1356012462                /* strange operator not found */
    1356112463                goto err;
    1356212464            }
    13563             for(o = expr; *p && *o == *p; p++)
     12465            for (o = expr; *p && *o == *p; p++)
    1356412466                o++;
    13565             if(! *p) {
     12467            if (! *p) {
    1356612468                /* found */
    1356712469                expr = o - 1;
     
    1356912471            }
    1357012472            /* skip tail uncompared token */
    13571             while(*p)
     12473            while (*p)
    1357212474                p++;
    1357312475            /* skip zero delim */
     
    1357712479
    1357812480        /* post grammar: a++ reduce to num */
    13579         if(lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
    13580             lasttok = TOK_NUM;
     12481        if (lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
     12482            lasttok = TOK_NUM;
    1358112483
    1358212484        /* Plus and minus are binary (not unary) _only_ if the last
     
    1358512487         * It makes sense. */
    1358612488        if (lasttok != TOK_NUM) {
    13587             switch(op) {
    13588                 case TOK_ADD:
    13589                     op = TOK_UPLUS;
    13590                     break;
    13591                 case TOK_SUB:
    13592                     op = TOK_UMINUS;
    13593                     break;
    13594                 case TOK_POST_INC:
    13595                     op = TOK_PRE_INC;
    13596                     break;
    13597                 case TOK_POST_DEC:
    13598                     op = TOK_PRE_DEC;
    13599                     break;
     12489            switch (op) {
     12490            case TOK_ADD:
     12491                op = TOK_UPLUS;
     12492                break;
     12493            case TOK_SUB:
     12494                op = TOK_UMINUS;
     12495                break;
     12496            case TOK_POST_INC:
     12497                op = TOK_PRE_INC;
     12498                break;
     12499            case TOK_POST_DEC:
     12500                op = TOK_PRE_DEC;
     12501                break;
    1360012502            }
    1360112503        }
     
    1361912521            }
    1362012522            while (stackptr != stack) {
    13621                 if (op == TOK_RPAREN) {
    13622                 /* The algorithm employed here is simple: while we don't
    13623                  * hit an open paren nor the bottom of the stack, pop
    13624                  * tokens and apply them */
    13625                 if (stackptr[-1] == TOK_LPAREN) {
    13626                     --stackptr;
    13627                     /* Any operator directly after a */
    13628                     lasttok = TOK_NUM;
    13629                     /* close paren should consider itself binary */
    13630                     goto prologue;
     12523                if (op == TOK_RPAREN) {
     12524                    /* The algorithm employed here is simple: while we don't
     12525                     * hit an open paren nor the bottom of the stack, pop
     12526                     * tokens and apply them */
     12527                    if (stackptr[-1] == TOK_LPAREN) {
     12528                        --stackptr;
     12529                        /* Any operator directly after a */
     12530                        lasttok = TOK_NUM;
     12531                        /* close paren should consider itself binary */
     12532                        goto prologue;
     12533                    }
     12534                } else {
     12535                    operator prev_prec = PREC(stackptr[-1]);
     12536
     12537                    convert_prec_is_assing(prec);
     12538                    convert_prec_is_assing(prev_prec);
     12539                    if (prev_prec < prec)
     12540                        break;
     12541                    /* check right assoc */
     12542                    if (prev_prec == prec && is_right_associativity(prec))
     12543                        break;
    1363112544                }
    13632                 } else {
    13633                 operator prev_prec = PREC(stackptr[-1]);
    13634 
    13635                 convert_prec_is_assing(prec);
    13636                 convert_prec_is_assing(prev_prec);
    13637                 if (prev_prec < prec)
    13638                     break;
    13639                 /* check right assoc */
    13640                 if(prev_prec == prec && is_right_associativity(prec))
    13641                     break;
    13642                 }
    13643                 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
    13644                 if(errcode) goto ret;
     12545                errcode = arith_apply(*--stackptr, numstack, &numstackptr);
     12546                if (errcode) goto ret;
    1364512547            }
    1364612548            if (op == TOK_RPAREN) {
     
    1365112553        /* Push this operator to the stack and remember it. */
    1365212554        *stackptr++ = lasttok = op;
    13653 
    13654       prologue:
     12555 prologue:
    1365512556        ++expr;
    13656     }
    13657     }
    13658 }
    13659 #endif /* CONFIG_ASH_MATH_SUPPORT */
    13660 
    13661 
    13662 #ifdef DEBUG
    13663 const char *bb_applet_name = "debug stuff usage";
     12557    } /* while */
     12558}
     12559#endif /* ASH_MATH_SUPPORT */
     12560
     12561
     12562/* ============ main() and helpers */
     12563
     12564/*
     12565 * Called to exit the shell.
     12566 */
     12567static void exitshell(void) ATTRIBUTE_NORETURN;
     12568static void
     12569exitshell(void)
     12570{
     12571    struct jmploc loc;
     12572    char *p;
     12573    int status;
     12574
     12575    status = exitstatus;
     12576    TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
     12577    if (setjmp(loc.loc)) {
     12578        if (exception == EXEXIT)
     12579/* dash bug: it just does _exit(exitstatus) here
     12580 * but we have to do setjobctl(0) first!
     12581 * (bug is still not fixed in dash-0.5.3 - if you run dash
     12582 * under Midnight Commander, on exit from dash MC is backgrounded) */
     12583            status = exitstatus;
     12584        goto out;
     12585    }
     12586    exception_handler = &loc;
     12587    p = trap[0];
     12588    if (p) {
     12589        trap[0] = NULL;
     12590        evalstring(p, 0);
     12591    }
     12592    flush_stdout_stderr();
     12593 out:
     12594    setjobctl(0);
     12595    _exit(status);
     12596    /* NOTREACHED */
     12597}
     12598
     12599static void
     12600init(void)
     12601{
     12602    /* from input.c: */
     12603    basepf.nextc = basepf.buf = basebuf;
     12604
     12605    /* from trap.c: */
     12606    signal(SIGCHLD, SIG_DFL);
     12607
     12608    /* from var.c: */
     12609    {
     12610        char **envp;
     12611        char ppid[sizeof(int)*3 + 1];
     12612        const char *p;
     12613        struct stat st1, st2;
     12614
     12615        initvar();
     12616        for (envp = environ; envp && *envp; envp++) {
     12617            if (strchr(*envp, '=')) {
     12618                setvareq(*envp, VEXPORT|VTEXTFIXED);
     12619            }
     12620        }
     12621
     12622        snprintf(ppid, sizeof(ppid), "%u", (unsigned) getppid());
     12623        setvar("PPID", ppid, 0);
     12624
     12625        p = lookupvar("PWD");
     12626        if (p)
     12627            if (*p != '/' || stat(p, &st1) || stat(".", &st2)
     12628             || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
     12629                p = '\0';
     12630        setpwd(p, 0);
     12631    }
     12632}
     12633
     12634/*
     12635 * Process the shell command line arguments.
     12636 */
     12637static void
     12638procargs(int argc, char **argv)
     12639{
     12640    int i;
     12641    const char *xminusc;
     12642    char **xargv;
     12643
     12644    xargv = argv;
     12645    arg0 = xargv[0];
     12646    if (argc > 0)
     12647        xargv++;
     12648    for (i = 0; i < NOPTS; i++)
     12649        optlist[i] = 2;
     12650    argptr = xargv;
     12651    options(1);
     12652    xargv = argptr;
     12653    xminusc = minusc;
     12654    if (*xargv == NULL) {
     12655        if (xminusc)
     12656            ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
     12657        sflag = 1;
     12658    }
     12659    if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
     12660        iflag = 1;
     12661    if (mflag == 2)
     12662        mflag = iflag;
     12663    for (i = 0; i < NOPTS; i++)
     12664        if (optlist[i] == 2)
     12665            optlist[i] = 0;
     12666#if DEBUG == 2
     12667    debug = 1;
     12668#endif
     12669    /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
     12670    if (xminusc) {
     12671        minusc = *xargv++;
     12672        if (*xargv)
     12673            goto setarg0;
     12674    } else if (!sflag) {
     12675        setinputfile(*xargv, 0);
     12676 setarg0:
     12677        arg0 = *xargv++;
     12678        commandname = arg0;
     12679    }
     12680
     12681    shellparam.p = xargv;
     12682#if ENABLE_ASH_GETOPTS
     12683    shellparam.optind = 1;
     12684    shellparam.optoff = -1;
     12685#endif
     12686    /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
     12687    while (*xargv) {
     12688        shellparam.nparam++;
     12689        xargv++;
     12690    }
     12691    optschanged();
     12692}
     12693
     12694/*
     12695 * Read /etc/profile or .profile.
     12696 */
     12697static void
     12698read_profile(const char *name)
     12699{
     12700    int skip;
     12701
     12702    if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
     12703        return;
     12704    skip = cmdloop(0);
     12705    popfile();
     12706    if (skip)
     12707        exitshell();
     12708}
     12709
     12710/*
     12711 * This routine is called when an error or an interrupt occurs in an
     12712 * interactive shell and control is returned to the main command loop.
     12713 */
     12714static void
     12715reset(void)
     12716{
     12717    /* from eval.c: */
     12718    evalskip = 0;
     12719    loopnest = 0;
     12720    /* from input.c: */
     12721    parselleft = parsenleft = 0;      /* clear input buffer */
     12722    popallfiles();
     12723    /* from parser.c: */
     12724    tokpushback = 0;
     12725    checkkwd = 0;
     12726    /* from redir.c: */
     12727    clearredir(0);
     12728}
     12729
     12730#if PROFILE
     12731static short profile_buf[16384];
     12732extern int etext();
     12733#endif
     12734
     12735/*
     12736 * Main routine.  We initialize things, parse the arguments, execute
     12737 * profiles if we're a login shell, and then call cmdloop to execute
     12738 * commands.  The setjmp call sets up the location to jump to when an
     12739 * exception occurs.  When an exception occurs the variable "state"
     12740 * is used to figure out how far we had gotten.
     12741 */
     12742int ash_main(int argc, char **argv);
     12743int ash_main(int argc, char **argv)
     12744{
     12745    char *shinit;
     12746    volatile int state;
     12747    struct jmploc jmploc;
     12748    struct stackmark smark;
     12749
     12750#if PROFILE
     12751    monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
     12752#endif
     12753
     12754#if ENABLE_FEATURE_EDITING
     12755    line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
     12756#endif
     12757    state = 0;
     12758    if (setjmp(jmploc.loc)) {
     12759        int e;
     12760        int s;
     12761
     12762        reset();
     12763
     12764        e = exception;
     12765        if (e == EXERROR)
     12766            exitstatus = 2;
     12767        s = state;
     12768        if (e == EXEXIT || s == 0 || iflag == 0 || shlvl)
     12769            exitshell();
     12770
     12771        if (e == EXINT) {
     12772            outcslow('\n', stderr);
     12773        }
     12774        popstackmark(&smark);
     12775        FORCE_INT_ON; /* enable interrupts */
     12776        if (s == 1)
     12777            goto state1;
     12778        if (s == 2)
     12779            goto state2;
     12780        if (s == 3)
     12781            goto state3;
     12782        goto state4;
     12783    }
     12784    exception_handler = &jmploc;
     12785#if DEBUG
     12786    opentrace();
     12787    trace_puts("Shell args: ");
     12788    trace_puts_args(argv);
     12789#endif
     12790    rootpid = getpid();
     12791
     12792#if ENABLE_ASH_RANDOM_SUPPORT
     12793    rseed = rootpid + time(NULL);
     12794#endif
     12795    init();
     12796    setstackmark(&smark);
     12797    procargs(argc, argv);
     12798#if ENABLE_FEATURE_EDITING_SAVEHISTORY
     12799    if (iflag) {
     12800        const char *hp = lookupvar("HISTFILE");
     12801
     12802        if (hp == NULL) {
     12803            hp = lookupvar("HOME");
     12804            if (hp != NULL) {
     12805                char *defhp = concat_path_file(hp, ".ash_history");
     12806                setvar("HISTFILE", defhp, 0);
     12807                free(defhp);
     12808            }
     12809        }
     12810    }
     12811#endif
     12812    if (argv[0] && argv[0][0] == '-')
     12813        isloginsh = 1;
     12814    if (isloginsh) {
     12815        state = 1;
     12816        read_profile("/etc/profile");
     12817 state1:
     12818        state = 2;
     12819        read_profile(".profile");
     12820    }
     12821 state2:
     12822    state = 3;
     12823    if (
     12824#ifndef linux
     12825     getuid() == geteuid() && getgid() == getegid() &&
     12826#endif
     12827     iflag
     12828    ) {
     12829        shinit = lookupvar("ENV");
     12830        if (shinit != NULL && *shinit != '\0') {
     12831            read_profile(shinit);
     12832        }
     12833    }
     12834 state3:
     12835    state = 4;
     12836    if (minusc)
     12837        evalstring(minusc, 0);
     12838
     12839    if (sflag || minusc == NULL) {
     12840#if ENABLE_FEATURE_EDITING_SAVEHISTORY
     12841        if ( iflag ) {
     12842            const char *hp = lookupvar("HISTFILE");
     12843
     12844            if (hp != NULL)
     12845                line_input_state->hist_file = hp;
     12846        }
     12847#endif
     12848 state4: /* XXX ??? - why isn't this before the "if" statement */
     12849        cmdloop(1);
     12850    }
     12851#if PROFILE
     12852    monitor(0);
     12853#endif
     12854#ifdef GPROF
     12855    {
     12856        extern void _mcleanup(void);
     12857        _mcleanup();
     12858    }
     12859#endif
     12860    exitshell();
     12861    /* NOTREACHED */
     12862}
     12863
     12864#if DEBUG
     12865const char *applet_name = "debug stuff usage";
    1366412866int main(int argc, char **argv)
    1366512867{
     
    1366712869}
    1366812870#endif
     12871
    1366912872
    1367012873/*-
  • branches/2.2.5/mindi-busybox/shell/hush.c

    r821 r1765  
    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}
  • branches/2.2.5/mindi-busybox/shell/lash.c

    r821 r1765  
    2121//#define DEBUG_SHELL
    2222
    23 
    24 #include "busybox.h"
    25 #include <stdio.h>
    26 #include <stdlib.h>
    27 #include <ctype.h>
    28 #include <errno.h>
    29 #include <fcntl.h>
    30 #include <signal.h>
    31 #include <string.h>
    32 #include <sys/ioctl.h>
    33 #include <sys/wait.h>
    34 #include <unistd.h>
    3523#include <getopt.h>
    36 #include <termios.h>
    37 #include "cmdedit.h"
    38 
    39 #ifdef CONFIG_LOCALE_SUPPORT
    40 #include <locale.h>
    41 #endif
    42 
    4324#include <glob.h>
     25
     26#include "busybox.h" /* for struct bb_applet */
     27
    4428#define expand_t    glob_t
    4529
     
    4731#define CONFIG_LASH_PIPE_N_REDIRECTS
    4832#define CONFIG_LASH_JOB_CONTROL
    49 
    50 static const int MAX_READ = 128;    /* size of input buffer for `read' builtin */
     33#define ENABLE_LASH_PIPE_N_REDIRECTS 1
     34#define ENABLE_LASH_JOB_CONTROL      1
     35
     36
     37enum { MAX_READ = 128 }; /* size of input buffer for 'read' builtin */
    5138#define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n"
    5239
    5340
    54 #ifdef CONFIG_LASH_PIPE_N_REDIRECTS
     41#if ENABLE_LASH_PIPE_N_REDIRECTS
    5542enum redir_type { REDIRECT_INPUT, REDIRECT_OVERWRITE,
    5643    REDIRECT_APPEND
     
    6653};
    6754
    68 #ifdef CONFIG_LASH_PIPE_N_REDIRECTS
     55#define LASH_OPT_DONE (1)
     56#define LASH_OPT_SAW_QUOTE (2)
     57
     58#if ENABLE_LASH_PIPE_N_REDIRECTS
    6959struct redir_struct {
    7060    enum redir_type type;   /* type of redirection */
     
    8070    int is_stopped;             /* is the program currently running? */
    8171    struct job *family;         /* pointer back to the child's parent job */
    82 #ifdef CONFIG_LASH_PIPE_N_REDIRECTS
     72#if ENABLE_LASH_PIPE_N_REDIRECTS
    8373    struct redir_struct *redirects; /* I/O redirects */
    8474#endif
     
    10595
    10696struct built_in_command {
    107     char *cmd;                  /* name */
    108     char *descr;                /* description */
     97    const char *cmd;   /* name */
     98    const char *descr; /* description */
    10999    int (*function) (struct child_prog *);  /* function ptr */
    110100};
     
    127117static void checkjobs(struct jobset *job_list);
    128118static void remove_job(struct jobset *j_list, struct job *job);
    129 static int get_command(FILE * source, char *command);
     119static int get_command_bufsiz(FILE * source, char *command);
    130120static int parse_command(char **command_ptr, struct job *job, int *inbg);
    131121static int run_command(struct job *newjob, int inbg, int outpipe[2]);
     
    137127 * can change global variables in the parent shell process but they will not
    138128 * work with pipes and redirects; 'unset foo | whatever' will not work) */
    139 static struct built_in_command bltins[] = {
    140     {"bg", "Resume a job in the background", builtin_fg_bg},
    141     {"cd", "Change working directory", builtin_cd},
    142     {"exec", "Exec command, replacing this shell with the exec'd process", builtin_exec},
    143     {"exit", "Exit from shell()", builtin_exit},
    144     {"fg", "Bring job into the foreground", builtin_fg_bg},
    145     {"jobs", "Lists the active jobs", builtin_jobs},
     129static const struct built_in_command bltins[] = {
     130    {"bg"    , "Resume a job in the background", builtin_fg_bg},
     131    {"cd"    , "Change working directory", builtin_cd},
     132    {"exec"  , "Exec command, replacing this shell with the exec'd process", builtin_exec},
     133    {"exit"  , "Exit from shell()", builtin_exit},
     134    {"fg"    , "Bring job into the foreground", builtin_fg_bg},
     135    {"jobs"  , "Lists the active jobs", builtin_jobs},
    146136    {"export", "Set environment variable", builtin_export},
    147     {"unset", "Unset environment variable", builtin_unset},
    148     {"read", "Input environment variable", builtin_read},
    149     {".", "Source-in and run commands in a file", builtin_source},
     137    {"unset" , "Unset environment variable", builtin_unset},
     138    {"read"  , "Input environment variable", builtin_read},
     139    {"."     , "Source-in and run commands in a file", builtin_source},
     140    /* These were "forked applets", but distinction was nuked */
     141    /* Original comment retained: */
     142    /* Table of forking built-in functions (things that fork cannot change global
     143     * variables in the parent process, such as the current working directory) */
     144    {"pwd"   , "Print current directory", builtin_pwd},
     145    {"help"  , "List shell built-in commands", builtin_help},
    150146    /* to do: add ulimit */
    151     {NULL, NULL, NULL}
    152147};
    153148
    154 /* Table of forking built-in functions (things that fork cannot change global
    155  * variables in the parent process, such as the current working directory) */
    156 static struct built_in_command bltins_forking[] = {
    157     {"pwd", "Print current directory", builtin_pwd},
    158     {"help", "List shell built-in commands", builtin_help},
    159     {NULL, NULL, NULL}
    160 };
     149
     150#define VEC_LAST(v) v[ARRAY_SIZE(v)-1]
    161151
    162152
     
    165155
    166156/* Globals that are static to this file */
    167 static const char *cwd;
    168 static char *local_pending_command = NULL;
     157static char *cwd;
     158static char *local_pending_command;
    169159static struct jobset job_list = { NULL, NULL };
    170160static int argc;
     
    175165static unsigned int last_jobid;
    176166static int shell_terminal;
    177 static char *PS1;
    178 static char *PS2 = "> ";
     167static const char *PS1;
     168static const char *PS2 = "> ";
    179169
    180170
     
    188178}
    189179#else
    190 static inline void debug_printf(const char *format, ...) { }
     180static inline void debug_printf(const char ATTRIBUTE_UNUSED *format, ...) { }
    191181#endif
    192182
     
    219209 */
    220210
     211
     212static void update_cwd(void)
     213{
     214    cwd = xrealloc_getcwd_or_warn(cwd);
     215    if (!cwd)
     216        cwd = xstrdup(bb_msg_unknown);
     217}
     218
    221219/* built-in 'cd <path>' handler */
    222220static int builtin_cd(struct child_prog *child)
     
    232230        return EXIT_FAILURE;
    233231    }
    234     cwd = xgetcwd((char *)cwd);
    235     if (!cwd)
    236         cwd = bb_msg_unknown;
     232    update_cwd();
    237233    return EXIT_SUCCESS;
    238234}
     
    244240        return EXIT_SUCCESS;   /* Really? */
    245241    child->argv++;
    246     while(close_me_list) close((long)llist_pop(&close_me_list));
     242    while (close_me_list)
     243        close((long)llist_pop(&close_me_list));
    247244    pseudo_exec(child);
    248245    /* never returns */
     
    255252        exit(EXIT_SUCCESS);
    256253
    257     exit (atoi(child->argv[1]));
     254    exit(atoi(child->argv[1]));
    258255}
    259256
     
    262259{
    263260    int i, jobnum;
    264     struct job *job=NULL;
     261    struct job *job;
    265262
    266263    /* If they gave us no args, assume they want the last backgrounded task */
     
    268265        for (job = child->family->job_list->head; job; job = job->next) {
    269266            if (job->jobid == last_jobid) {
    270                 break;
    271             }
    272         }
    273         if (!job) {
    274             bb_error_msg("%s: no current job", child->argv[0]);
    275             return EXIT_FAILURE;
    276         }
    277     } else {
    278         if (sscanf(child->argv[1], "%%%d", &jobnum) != 1) {
    279             bb_error_msg(bb_msg_invalid_arg, child->argv[1], child->argv[0]);
    280             return EXIT_FAILURE;
    281         }
    282         for (job = child->family->job_list->head; job; job = job->next) {
    283             if (job->jobid == jobnum) {
    284                 break;
    285             }
    286         }
    287         if (!job) {
    288             bb_error_msg("%s: %d: no such job", child->argv[0], jobnum);
    289             return EXIT_FAILURE;
    290         }
    291     }
    292 
     267                goto found;
     268            }
     269        }
     270        bb_error_msg("%s: no current job", child->argv[0]);
     271        return EXIT_FAILURE;
     272    }
     273    if (sscanf(child->argv[1], "%%%d", &jobnum) != 1) {
     274        bb_error_msg(bb_msg_invalid_arg, child->argv[1], child->argv[0]);
     275        return EXIT_FAILURE;
     276    }
     277    for (job = child->family->job_list->head; job; job = job->next) {
     278        if (job->jobid == jobnum) {
     279            goto found;
     280        }
     281    }
     282    bb_error_msg("%s: %d: no such job", child->argv[0], jobnum);
     283    return EXIT_FAILURE;
     284 found:
    293285    if (*child->argv[0] == 'f') {
    294286        /* Put the job into the foreground.  */
     
    304296    job->stopped_progs = 0;
    305297
    306     if ( (i=kill(- job->pgrp, SIGCONT)) < 0) {
    307         if (i == ESRCH) {
     298    i = kill(- job->pgrp, SIGCONT);
     299    if (i < 0) {
     300        if (errno == ESRCH) {
    308301            remove_job(&job_list, job);
    309302        } else {
     
    316309
    317310/* built-in 'help' handler */
    318 static int builtin_help(struct child_prog *dummy)
    319 {
    320     struct built_in_command *x;
    321 
    322     printf("\nBuilt-in commands:\n");
    323     printf("-------------------\n");
    324     for (x = bltins; x->cmd; x++) {
    325         if (x->descr==NULL)
     311static int builtin_help(struct child_prog ATTRIBUTE_UNUSED *dummy)
     312{
     313    const struct built_in_command *x;
     314
     315    printf("\nBuilt-in commands:\n"
     316           "-------------------\n");
     317    for (x = bltins; x <= &VEC_LAST(bltins); x++) {
     318        if (x->descr == NULL)
    326319            continue;
    327320        printf("%s\t%s\n", x->cmd, x->descr);
    328321    }
    329     for (x = bltins_forking; x->cmd; x++) {
    330         if (x->descr==NULL)
    331             continue;
    332         printf("%s\t%s\n", x->cmd, x->descr);
    333     }
    334     printf("\n\n");
     322    putchar('\n');
    335323    return EXIT_SUCCESS;
    336324}
     
    340328{
    341329    struct job *job;
    342     char *status_string;
     330    const char *status_string;
    343331
    344332    for (job = child->family->job_list->head; job; job = job->next) {
     
    355343
    356344/* built-in 'pwd' handler */
    357 static int builtin_pwd(struct child_prog *dummy)
    358 {
    359     cwd = xgetcwd((char *)cwd);
    360     if (!cwd)
    361         cwd = bb_msg_unknown;
     345static int builtin_pwd(struct child_prog ATTRIBUTE_UNUSED *dummy)
     346{
     347    update_cwd();
    362348    puts(cwd);
    363349    return EXIT_SUCCESS;
     
    380366    if (res)
    381367        bb_perror_msg("export");
    382 #ifdef CONFIG_FEATURE_SH_FANCY_PROMPT
    383     if (strncmp(v, "PS1=", 4)==0)
     368#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
     369    if (strncmp(v, "PS1=", 4) == 0)
    384370        PS1 = getenv("PS1");
    385371#endif
    386372
    387 #ifdef CONFIG_LOCALE_SUPPORT
    388     if(strncmp(v, "LC_ALL=", 7)==0)
     373#if ENABLE_LOCALE_SUPPORT
     374    // TODO: why getenv? "" would be just as good...
     375    if (strncmp(v, "LC_ALL=", 7) == 0)
    389376        setlocale(LC_ALL, getenv("LC_ALL"));
    390     if(strncmp(v, "LC_CTYPE=", 9)==0)
     377    if (strncmp(v, "LC_CTYPE=", 9) == 0)
    391378        setlocale(LC_CTYPE, getenv("LC_CTYPE"));
    392379#endif
    393380
    394     return (res);
     381    return res;
    395382}
    396383
     
    398385static int builtin_read(struct child_prog *child)
    399386{
    400     int res = 0, len, newlen;
     387    int res = 0, len;
    401388    char *s;
    402389    char string[MAX_READ];
     
    409396        string[len]   = '\0';
    410397        fgets(&string[len], sizeof(string) - len, stdin);   /* read string */
    411         newlen = strlen(string);
    412         if(newlen > len)
    413             string[--newlen] = '\0';    /* chomp trailing newline */
     398        res = strlen(string);
     399        if (res > len)
     400            string[--res] = '\0';   /* chomp trailing newline */
    414401        /*
    415402        ** string should now contain "VAR=<value>"
     
    418405        */
    419406        res = -1;
    420         if((s = strdup(string)))
     407        s = strdup(string);
     408        if (s)
    421409            res = putenv(s);
    422410        if (res)
    423411            bb_perror_msg("read");
    424     }
    425     else
     412    } else
    426413        fgets(string, sizeof(string), stdin);
    427414
    428     return (res);
     415    return res;
    429416}
    430417
     
    435422    int status;
    436423
    437     if (child->argv[1] == NULL)
    438         return EXIT_FAILURE;
    439 
    440     input = fopen(child->argv[1], "r");
     424    input = fopen_or_warn(child->argv[1], "r");
    441425    if (!input) {
    442         printf( "Couldn't open file '%s'\n", child->argv[1]);
    443426        return EXIT_FAILURE;
    444427    }
     
    449432    fclose(input);
    450433    llist_pop(&close_me_list);
    451     return (status);
     434    return status;
    452435}
    453436
     
    463446}
    464447
    465 #ifdef CONFIG_LASH_JOB_CONTROL
     448#if ENABLE_LASH_JOB_CONTROL
    466449/* free up all memory from a job */
    467450static void free_job(struct job *cmd)
     
    472455    for (i = 0; i < cmd->num_progs; i++) {
    473456        free(cmd->progs[i].argv);
    474 #ifdef CONFIG_LASH_PIPE_N_REDIRECTS
     457#if ENABLE_LASH_PIPE_N_REDIRECTS
    475458        if (cmd->progs[i].redirects)
    476459            free(cmd->progs[i].redirects);
     
    527510
    528511        /* This happens on backticked commands */
    529         if(job==NULL)
     512        if (job == NULL)
    530513            return;
    531514
     
    537520            if (!job->running_progs) {
    538521                printf(JOB_STATUS_FORMAT, job->jobid, "Done", job->text);
    539                 last_jobid=0;
     522                last_jobid = 0;
    540523                remove_job(j_list, job);
    541524            }
     
    544527            job->stopped_progs++;
    545528            job->progs[prognum].is_stopped = 1;
    546 
    547 #if 0
    548             /* Printing this stuff is a pain, since it tends to
    549              * overwrite the prompt an inconveinient moments.  So
    550              * don't do that.  */
    551             if (job->stopped_progs == job->num_progs) {
    552                 printf(JOB_STATUS_FORMAT, job->jobid, "Stopped",
    553                        job->text);
    554             }
    555 #endif
    556529        }
    557530    }
     
    572545#endif
    573546
    574 #ifdef CONFIG_LASH_PIPE_N_REDIRECTS
     547#if ENABLE_LASH_PIPE_N_REDIRECTS
    575548/* squirrel != NULL means we squirrel away copies of stdin, stdout,
    576549 * and stderr if they are redirected. */
     
    595568        }
    596569
    597         openfd = open(redir->filename, mode, 0666);
     570        openfd = open3_or_warn(redir->filename, mode, 0666);
    598571        if (openfd < 0) {
    599572            /* this could get lost if stderr has been redirected, but
    600573               bash and ash both lose it as well (though zsh doesn't!) */
    601             bb_perror_msg("error opening %s", redir->filename);
    602574            return 1;
    603575        }
     
    606578            if (squirrel && redir->fd < 3) {
    607579                squirrel[redir->fd] = dup(redir->fd);
    608                 fcntl (squirrel[redir->fd], F_SETFD, FD_CLOEXEC);
     580                fcntl(squirrel[redir->fd], F_SETFD, FD_CLOEXEC);
    609581            }
    610582            dup2(openfd, redir->fd);
     
    619591{
    620592    int i, fd;
    621     for (i=0; i<3; i++) {
     593    for (i = 0; i < 3; i++) {
    622594        fd = squirrel[i];
    623595        if (fd != -1) {
     
    641613static inline void cmdedit_set_initial_prompt(void)
    642614{
    643 #ifndef CONFIG_FEATURE_SH_FANCY_PROMPT
     615#if !ENABLE_FEATURE_EDITING_FANCY_PROMPT
    644616    PS1 = NULL;
    645617#else
    646618    PS1 = getenv("PS1");
    647     if(PS1==0)
     619    if (PS1 == 0)
    648620        PS1 = "\\w \\$ ";
    649621#endif
    650622}
    651623
    652 static inline void setup_prompt_string(char **prompt_str)
    653 {
    654 #ifndef CONFIG_FEATURE_SH_FANCY_PROMPT
     624static inline const char* setup_prompt_string(void)
     625{
     626#if !ENABLE_FEATURE_EDITING_FANCY_PROMPT
    655627    /* Set up the prompt */
    656628    if (shell_context == 0) {
    657         free(PS1);
    658         PS1=xmalloc(strlen(cwd)+4);
    659         sprintf(PS1, "%s %s", cwd, ( geteuid() != 0 ) ?  "$ ":"# ");
    660         *prompt_str = PS1;
     629        char *ns;
     630        free((char*)PS1);
     631        ns = xmalloc(strlen(cwd)+4);
     632        sprintf(ns, "%s %c ", cwd, (geteuid() != 0) ? '$': '#');
     633        PS1 = ns;
     634        return ns;
    661635    } else {
    662         *prompt_str = PS2;
     636        return PS2;
    663637    }
    664638#else
    665     *prompt_str = (shell_context==0)? PS1 : PS2;
    666 #endif
    667 }
    668 
    669 static int get_command(FILE * source, char *command)
    670 {
    671     char *prompt_str;
     639    return (shell_context == 0)? PS1 : PS2;
     640#endif
     641}
     642
     643#if ENABLE_FEATURE_EDITING
     644static line_input_t *line_input_state;
     645#endif
     646
     647static int get_command_bufsiz(FILE * source, char *command)
     648{
     649    const char *prompt_str;
    672650
    673651    if (source == NULL) {
    674652        if (local_pending_command) {
    675653            /* a command specified (-c option): return it & mark it done */
    676             strcpy(command, local_pending_command);
    677             free(local_pending_command);
     654            strncpy(command, local_pending_command, BUFSIZ);
    678655            local_pending_command = NULL;
    679656            return 0;
     
    683660
    684661    if (source == stdin) {
    685         setup_prompt_string(&prompt_str);
    686 
    687 #ifdef CONFIG_FEATURE_COMMAND_EDITING
     662        prompt_str = setup_prompt_string();
     663
     664#if ENABLE_FEATURE_EDITING
    688665        /*
    689666        ** enable command line editing only while a command line
     
    692669        ** child processes (rob@sysgo.de)
    693670        */
    694         cmdedit_read_input(prompt_str, command);
     671        read_line_input(prompt_str, command, BUFSIZ, line_input_state);
    695672        return 0;
    696673#else
     
    701678    if (!fgets(command, BUFSIZ - 2, source)) {
    702679        if (source == stdin)
    703             printf("\n");
     680            puts("");
    704681        return 1;
    705682    }
     
    708685}
    709686
    710 static char* itoa(register int i)
    711 {
    712     static char a[7]; /* Max 7 ints */
    713     register char *b = a + sizeof(a) - 1;
    714     int   sign = (i < 0);
    715 
    716     if (sign)
    717         i = -i;
    718     *b = 0;
    719     do
    720     {
    721         *--b = '0' + (i % 10);
    722         i /= 10;
    723     }
    724     while (i);
    725     if (sign)
    726         *--b = '-';
    727     return b;
    728 }
    729 
    730 static char * strsep_space( char *string, int * ix)
    731 {
    732     char *token;
    733 
     687static char * strsep_space(char *string, int * ix)
     688{
    734689    /* Short circuit the trivial case */
    735     if ( !string || ! string[*ix])
     690    if (!string || ! string[*ix])
    736691        return NULL;
    737692
    738693    /* Find the end of the token. */
    739     while( string[*ix] && !isspace(string[*ix]) ) {
     694    while (string[*ix] && !isspace(string[*ix]) ) {
    740695        (*ix)++;
    741696    }
     
    743698    /* Find the end of any whitespace trailing behind
    744699     * the token and let that be part of the token */
    745     while( string[*ix] && isspace(string[*ix]) ) {
     700    while (string[*ix] && (isspace)(string[*ix]) ) {
    746701        (*ix)++;
    747702    }
     
    752707    }
    753708
    754     token = bb_xstrndup(string, *ix);
    755 
    756     return token;
     709    return xstrndup(string, *ix);
    757710}
    758711
    759712static int expand_arguments(char *command)
    760713{
    761     int total_length=0, length, i, retval, ix = 0;
     714    static const char out_of_space[] ALIGN1 = "out of space during expansion";
     715
     716    int total_length = 0, length, i, retval, ix = 0;
    762717    expand_t expand_result;
    763718    char *tmpcmd, *cmd, *cmd_copy;
    764719    char *src, *dst, *var;
    765     const char *out_of_space = "out of space during expansion";
    766720    int flags = GLOB_NOCHECK
    767721#ifdef GLOB_BRACE
     
    777731
    778732    /* Fix up escape sequences to be the Real Thing(tm) */
    779     while( command && command[ix]) {
     733    while (command && command[ix]) {
    780734        if (command[ix] == '\\') {
    781735            const char *tmp = command+ix+1;
     
    793747    /* We need a clean copy, so strsep can mess up the copy while
    794748     * we write stuff into the original (in a minute) */
    795     cmd = cmd_copy = bb_xstrdup(command);
     749    cmd = cmd_copy = xstrdup(command);
    796750    *command = '\0';
    797751    for (ix = 0, tmpcmd = cmd;
    798             (tmpcmd = strsep_space(cmd, &ix)) != NULL; cmd += ix, ix=0) {
     752            (tmpcmd = strsep_space(cmd, &ix)) != NULL; cmd += ix, ix = 0) {
    799753        if (*tmpcmd == '\0')
    800754            break;
     
    805759        if (retval == GLOB_NOSPACE) {
    806760            /* Mem may have been allocated... */
    807             globfree (&expand_result);
     761            globfree(&expand_result);
    808762            bb_error_msg(out_of_space);
    809763            return FALSE;
     
    817771            /* Convert from char** (one word per string) to a simple char*,
    818772             * but don't overflow command which is BUFSIZ in length */
    819             for (i=0; i < expand_result.gl_pathc; i++) {
    820                 length=strlen(expand_result.gl_pathv[i]);
     773            for (i = 0; i < expand_result.gl_pathc; i++) {
     774                length = strlen(expand_result.gl_pathv[i]);
    821775                if (total_length+length+1 >= BUFSIZ) {
    822776                    bb_error_msg(out_of_space);
     
    824778                }
    825779                strcat(command+total_length, " ");
    826                 total_length+=1;
     780                total_length += 1;
    827781                strcat(command+total_length, expand_result.gl_pathv[i]);
    828                 total_length+=length;
    829             }
    830             globfree (&expand_result);
     782                total_length += length;
     783            }
     784            globfree(&expand_result);
    831785        }
    832786    }
     
    837791     * wordexp can't do for us, namely $? and $! */
    838792    src = command;
    839     while((dst = strchr(src,'$')) != NULL){
     793    while ((dst = strchr(src,'$')) != NULL) {
    840794        var = NULL;
    841         switch(*(dst+1)) {
     795        switch (*(dst+1)) {
    842796            case '?':
    843797                var = itoa(last_return_code);
    844798                break;
    845799            case '!':
    846                 if (last_bg_pid==-1)
    847                     *(var)='\0';
     800                if (last_bg_pid == -1)
     801                    *var = '\0';
    848802                else
    849803                    var = itoa(last_bg_pid);
     
    863817            case '5':case '6':case '7':case '8':case '9':
    864818                {
    865                     int ixx=*(dst+1)-48+1;
     819                    int ixx = *(dst+1)-48+1;
    866820                    if (ixx >= argc) {
    867                         var='\0';
     821                        var = '\0';
    868822                    } else {
    869823                        var = argv[ixx];
     
    876830            /* a single character construction was found, and
    877831             * already handled in the case statement */
    878             src=dst+2;
     832            src = dst + 2;
    879833        } else {
    880834            /* Looks like an environment variable */
    881835            char delim_hold;
    882             int num_skip_chars=0;
     836            int num_skip_chars = 0;
    883837            int dstlen = strlen(dst);
    884838            /* Is this a ${foo} type variable? */
    885             if (dstlen >=2 && *(dst+1) == '{') {
    886                 src=strchr(dst+1, '}');
    887                 num_skip_chars=1;
     839            if (dstlen >= 2 && *(dst+1) == '{') {
     840                src = strchr(dst+1, '}');
     841                num_skip_chars = 1;
    888842            } else {
    889                 src=dst+1;
    890                 while(isalnum(*src) || *src=='_') src++;
     843                src = dst + 1;
     844                while ((isalnum)(*src) || *src == '_') src++;
    891845            }
    892846            if (src == NULL) {
    893847                src = dst+dstlen;
    894848            }
    895             delim_hold=*src;
    896             *src='\0';  /* temporary */
     849            delim_hold = *src;
     850            *src = '\0';  /* temporary */
    897851            var = getenv(dst + 1 + num_skip_chars);
    898             *src=delim_hold;
     852            *src = delim_hold;
    899853            src += num_skip_chars;
    900854        }
    901855        if (var == NULL) {
    902856            /* Seems we got an un-expandable variable.  So delete it. */
    903             var = "";
     857            var = (char*)"";
    904858        }
    905859        {
     
    932886    char *return_command = NULL;
    933887    char *src, *buf;
    934     int argc_l = 0;
    935     int done = 0;
     888    int argc_l;
     889    int flag;
    936890    int argv_alloced;
    937     int saw_quote = 0;
    938891    char quote = '\0';
    939892    struct child_prog *prog;
    940 #ifdef CONFIG_LASH_PIPE_N_REDIRECTS
     893#if ENABLE_LASH_PIPE_N_REDIRECTS
    941894    int i;
    942895    char *chptr;
     
    944897
    945898    /* skip leading white space */
    946     while (**command_ptr && isspace(**command_ptr))
    947         (*command_ptr)++;
     899    *command_ptr = skip_whitespace(*command_ptr);
    948900
    949901    /* this handles empty lines or leading '#' characters */
    950902    if (!**command_ptr || (**command_ptr == '#')) {
    951         job->num_progs=0;
     903        job->num_progs = 0;
    952904        return 0;
    953905    }
     
    971923    prog->is_stopped = 0;
    972924    prog->family = job;
    973 #ifdef CONFIG_LASH_PIPE_N_REDIRECTS
     925#if ENABLE_LASH_PIPE_N_REDIRECTS
    974926    prog->redirects = NULL;
    975927#endif
     
    979931    prog->argv[0] = job->cmdbuf;
    980932
     933    flag = argc_l = 0;
    981934    buf = command;
    982935    src = *command_ptr;
    983     while (*src && !done) {
     936    while (*src && !(flag & LASH_OPT_DONE)) {
    984937        if (quote == *src) {
    985938            quote = '\0';
     
    1002955            *buf++ = *src;
    1003956        } else if (isspace(*src)) {
    1004             if (*prog->argv[argc_l] || saw_quote) {
     957            if (*prog->argv[argc_l] || (flag & LASH_OPT_SAW_QUOTE)) {
    1005958                buf++, argc_l++;
    1006959                /* +1 here leaves room for the NULL which ends argv */
     
    1008961                    argv_alloced += 5;
    1009962                    prog->argv = xrealloc(prog->argv,
    1010                                           sizeof(*prog->argv) *
    1011                                           argv_alloced);
     963                            sizeof(*prog->argv) * argv_alloced);
    1012964                }
    1013965                prog->argv[argc_l] = buf;
    1014                 saw_quote = 0;
     966                flag ^= LASH_OPT_SAW_QUOTE;
    1015967            }
    1016968        } else
     
    1019971            case '\'':
    1020972                quote = *src;
    1021                 saw_quote = 1;
     973                flag |= LASH_OPT_SAW_QUOTE;
    1022974                break;
    1023975
     
    1026978                    *buf++ = *src;
    1027979                else
    1028                     done = 1;
     980                    flag |= LASH_OPT_DONE;
    1029981                break;
    1030982
    1031 #ifdef CONFIG_LASH_PIPE_N_REDIRECTS
     983#if ENABLE_LASH_PIPE_N_REDIRECTS
    1032984            case '>':           /* redirects */
    1033985            case '<':
    1034986                i = prog->num_redirects++;
    1035987                prog->redirects = xrealloc(prog->redirects,
    1036                                               sizeof(*prog->redirects) *
    1037                                               (i + 1));
     988                        sizeof(*prog->redirects) * (i + 1));
    1038989
    1039990                prog->redirects[i].fd = -1;
     
    10691020                /* This isn't POSIX sh compliant. Oh well. */
    10701021                chptr = src;
    1071                 while (isspace(*chptr))
    1072                     chptr++;
     1022                chptr = skip_whitespace(chptr);
    10731023
    10741024                if (!*chptr) {
    10751025                    bb_error_msg("file name expected after %c", *(src-1));
    10761026                    free_job(job);
    1077                     job->num_progs=0;
     1027                    job->num_progs = 0;
    10781028                    return 1;
    10791029                }
     
    10891039            case '|':           /* pipe */
    10901040                /* finish this command */
    1091                 if (*prog->argv[argc_l] || saw_quote)
     1041                if (*prog->argv[argc_l] || flag & LASH_OPT_SAW_QUOTE)
    10921042                    argc_l++;
    10931043                if (!argc_l) {
    1094                     bb_error_msg("empty command in pipe");
    1095                     free_job(job);
    1096                     job->num_progs=0;
    1097                     return 1;
     1044                    goto empty_command_in_pipe;
    10981045                }
    10991046                prog->argv[argc_l] = NULL;
     
    11021049                job->num_progs++;
    11031050                job->progs = xrealloc(job->progs,
    1104                                       sizeof(*job->progs) * job->num_progs);
     1051                        sizeof(*job->progs) * job->num_progs);
    11051052                prog = job->progs + (job->num_progs - 1);
    11061053                prog->num_redirects = 0;
     
    11151062
    11161063                src++;
    1117                 while (*src && isspace(*src))
    1118                     src++;
     1064                src = skip_whitespace(src);
    11191065
    11201066                if (!*src) {
     1067empty_command_in_pipe:
    11211068                    bb_error_msg("empty command in pipe");
    11221069                    free_job(job);
    1123                     job->num_progs=0;
     1070                    job->num_progs = 0;
    11241071                    return 1;
    11251072                }
     
    11291076#endif
    11301077
    1131 #ifdef CONFIG_LASH_JOB_CONTROL
     1078#if ENABLE_LASH_JOB_CONTROL
    11321079            case '&':           /* background */
    11331080                *inbg = 1;
     1081                /* fallthrough */
    11341082#endif
    11351083            case ';':           /* multiple commands */
    1136                 done = 1;
     1084                flag |= LASH_OPT_DONE;
    11371085                return_command = *command_ptr + (src - *command_ptr) + 1;
    11381086                break;
     
    11551103    }
    11561104
    1157     if (*prog->argv[argc_l] || saw_quote) {
     1105    if (*prog->argv[argc_l] || flag & LASH_OPT_SAW_QUOTE) {
    11581106        argc_l++;
    11591107    }
     
    11651113
    11661114    if (!return_command) {
    1167         job->text = bb_xstrdup(*command_ptr);
     1115        job->text = xstrdup(*command_ptr);
    11681116    } else {
    11691117        /* This leaves any trailing spaces, which is a bit sloppy */
    1170         job->text = bb_xstrndup(*command_ptr, return_command - *command_ptr);
     1118        job->text = xstrndup(*command_ptr, return_command - *command_ptr);
    11711119    }
    11721120
     
    11801128static int pseudo_exec(struct child_prog *child)
    11811129{
    1182     struct built_in_command *x;
     1130    const struct built_in_command *x;
    11831131
    11841132    /* Check if the command matches any of the non-forking builtins.
     
    11871135     * if this is one of those cases.
    11881136     */
    1189     for (x = bltins; x->cmd; x++) {
    1190         if (strcmp(child->argv[0], x->cmd) == 0 ) {
     1137    /* Check if the command matches any of the forking builtins. */
     1138    for (x = bltins; x <= &VEC_LAST(bltins); x++) {
     1139        if (strcmp(child->argv[0], x->cmd) == 0) {
    11911140            _exit(x->function(child));
    11921141        }
    11931142    }
    11941143
    1195     /* Check if the command matches any of the forking builtins. */
    1196     for (x = bltins_forking; x->cmd; x++) {
    1197         if (strcmp(child->argv[0], x->cmd) == 0) {
    1198             bb_applet_name=x->cmd;
    1199             _exit (x->function(child));
    1200         }
    1201     }
    12021144
    12031145    /* Check if the command matches any busybox internal
     
    12121154     * /bin/foo is a symlink to busybox.
    12131155     */
    1214 
    1215     if (ENABLE_FEATURE_SH_STANDALONE_SHELL) {
    1216         char **argv_l = child->argv;
    1217         int argc_l;
    1218 
    1219         for(argc_l=0; *argv_l; argv_l++, argc_l++);
    1220         optind = 1;
    1221         run_applet_by_name(child->argv[0], argc_l, child->argv);
     1156    if (ENABLE_FEATURE_SH_STANDALONE) {
     1157        run_applet_and_exit(child->argv[0], child->argv);
    12221158    }
    12231159
     
    12331169{
    12341170    struct job *thejob;
    1235     struct jobset *j_list=newjob->job_list;
     1171    struct jobset *j_list = newjob->job_list;
    12361172
    12371173    /* find the ID for thejob to use */
     
    12551191    thejob->stopped_progs = 0;
    12561192
    1257 #ifdef CONFIG_LASH_JOB_CONTROL
     1193#if ENABLE_LASH_JOB_CONTROL
    12581194    if (inbg) {
    12591195        /* we don't wait for background thejobs to return -- append it
     
    12621198               newjob->progs[newjob->num_progs - 1].pid);
    12631199        last_jobid = newjob->jobid;
    1264         last_bg_pid=newjob->progs[newjob->num_progs - 1].pid;
     1200        last_bg_pid = newjob->progs[newjob->num_progs - 1].pid;
    12651201    } else {
    12661202        newjob->job_list->fg = thejob;
     
    12791215    int nextin, nextout;
    12801216    int pipefds[2];             /* pipefd[0] is for reading */
    1281     struct built_in_command *x;
     1217    const struct built_in_command *x;
    12821218    struct child_prog *child;
    12831219
    1284     nextin = 0, nextout = 1;
     1220    nextin = 0;
    12851221    for (i = 0; i < newjob->num_progs; i++) {
    1286         child = & (newjob->progs[i]);
    1287 
     1222        child = &(newjob->progs[i]);
     1223
     1224        nextout = 1;
    12881225        if ((i + 1) < newjob->num_progs) {
    1289             if (pipe(pipefds)<0) bb_perror_msg_and_die("pipe");
     1226            xpipe(pipefds);
    12901227            nextout = pipefds[1];
    1291         } else {
    1292             if (outpipe[1]!=-1) {
    1293                 nextout = outpipe[1];
    1294             } else {
    1295                 nextout = 1;
    1296             }
    1297         }
    1298 
     1228        } else if (outpipe[1] != -1) {
     1229            nextout = outpipe[1];
     1230        }
    12991231
    13001232        /* Check if the command matches any non-forking builtins,
     
    13051237         */
    13061238        if (newjob->num_progs == 1) {
     1239            int rcode;
     1240            int squirrel[] = {-1, -1, -1};
     1241
    13071242            /* Check if the command sets an environment variable. */
    13081243            if (strchr(child->argv[0], '=') != NULL) {
     
    13111246            }
    13121247
    1313             for (x = bltins; x->cmd; x++) {
    1314                 if (strcmp(child->argv[0], x->cmd) == 0 ) {
    1315                     int rcode;
    1316                     int squirrel[] = {-1, -1, -1};
     1248            for (x = bltins; x <= &VEC_LAST(bltins); x++) {
     1249                if (strcmp(child->argv[0], x->cmd) == 0) {
    13171250                    setup_redirects(child, squirrel);
    13181251                    rcode = x->function(child);
     
    13211254                }
    13221255            }
    1323         }
    1324 
    1325 #if !defined(__UCLIBC__) || defined(__ARCH_HAS_MMU__)
    1326         if (!(child->pid = fork()))
     1256#if ENABLE_FEATURE_SH_STANDALONE
     1257            {
     1258                const struct bb_applet *a = find_applet_by_name(child->argv[i]);
     1259                if (a && a->nofork) {
     1260                    setup_redirects(child, squirrel);
     1261                    rcode = run_nofork_applet(a, child->argv + i);
     1262                    restore_redirects(squirrel);
     1263                    return rcode;
     1264                }
     1265            }
     1266#endif
     1267        }
     1268
     1269#if BB_MMU
     1270        child->pid = fork();
    13271271#else
    1328         if (!(child->pid = vfork()))
    1329 #endif
    1330         {
     1272        child->pid = vfork();
     1273#endif
     1274        if (!child->pid) {
    13311275            /* Set the handling for job control signals back to the default.  */
    13321276            signal(SIGINT, SIG_DFL);
     
    13371281            signal(SIGCHLD, SIG_DFL);
    13381282
    1339             // Close all open filehandles.
    1340             while(close_me_list) close((long)llist_pop(&close_me_list));
    1341 
    1342             if (outpipe[1]!=-1) {
     1283            /* Close all open filehandles. */
     1284            while (close_me_list)
     1285                close((long)llist_pop(&close_me_list));
     1286
     1287            if (outpipe[1] != -1) {
    13431288                close(outpipe[0]);
    13441289            }
     
    13601305            pseudo_exec(child);
    13611306        }
    1362         if (outpipe[1]!=-1) {
     1307        if (outpipe[1] != -1) {
    13631308            close(outpipe[1]);
    13641309        }
     
    13921337    int inbg = 0;
    13931338    int status;
    1394 #ifdef CONFIG_LASH_JOB_CONTROL
     1339#if ENABLE_LASH_JOB_CONTROL
    13951340    pid_t  parent_pgrp;
    13961341    /* save current owner of TTY so we can restore it on exit */
     
    14101355
    14111356            if (!next_command) {
    1412                 if (get_command(input, command))
     1357                if (get_command_bufsiz(input, command))
    14131358                    break;
    14141359                next_command = command;
    14151360            }
    14161361
    1417             if (! expand_arguments(next_command)) {
     1362            if (!expand_arguments(next_command)) {
    14181363                free(command);
    14191364                command = xzalloc(BUFSIZ);
     
    14241369            if (!parse_command(&next_command, &newjob, &inbg) &&
    14251370                newjob.num_progs) {
    1426                 int pipefds[2] = {-1,-1};
    1427                 debug_printf( "job=%p fed to run_command by busy_loop()'\n",
     1371                int pipefds[2] = { -1, -1 };
     1372                debug_printf("job=%p fed to run_command by busy_loop()'\n",
    14281373                        &newjob);
    14291374                run_command(&newjob, inbg, pipefds);
     
    14311376            else {
    14321377                free(command);
    1433                 command = (char *) xzalloc(BUFSIZ);
     1378                command = xzalloc(BUFSIZ);
    14341379                next_command = NULL;
    14351380            }
     
    14401385                   job_list.fg->progs[i].is_stopped == 1) i++;
    14411386
    1442             if (waitpid(job_list.fg->progs[i].pid, &status, WUNTRACED)<0) {
     1387            if (waitpid(job_list.fg->progs[i].pid, &status, WUNTRACED) < 0) {
    14431388                if (errno != ECHILD) {
    1444                     bb_perror_msg_and_die("waitpid(%d)",job_list.fg->progs[i].pid);
     1389                    bb_perror_msg_and_die("waitpid(%d)", job_list.fg->progs[i].pid);
    14451390                }
    14461391            }
     
    14511396                job_list.fg->progs[i].pid = 0;
    14521397
    1453                 last_return_code=WEXITSTATUS(status);
     1398                last_return_code = WEXITSTATUS(status);
    14541399
    14551400                if (!job_list.fg->running_progs) {
     
    14591404                }
    14601405            }
    1461 #ifdef CONFIG_LASH_JOB_CONTROL
     1406#if ENABLE_LASH_JOB_CONTROL
    14621407            else {
    14631408                /* the child was stopped */
     
    14831428    free(command);
    14841429
    1485 #ifdef CONFIG_LASH_JOB_CONTROL
     1430#if ENABLE_LASH_JOB_CONTROL
    14861431    /* return controlling TTY back to parent process group before exiting */
    14871432    if (tcsetpgrp(shell_terminal, parent_pgrp) && errno != ENOTTY)
     
    14961441}
    14971442
    1498 #ifdef CONFIG_FEATURE_CLEAN_UP
     1443#if ENABLE_FEATURE_CLEAN_UP
    14991444static void free_memory(void)
    15001445{
    1501     if (cwd && cwd!=bb_msg_unknown) {
    1502         free((char*)cwd);
    1503     }
    1504     if (local_pending_command)
    1505         free(local_pending_command);
     1446    free(cwd);
    15061447
    15071448    if (job_list.fg && !job_list.fg->running_progs) {
     
    15131454#endif
    15141455
    1515 #ifdef CONFIG_LASH_JOB_CONTROL
     1456#if ENABLE_LASH_JOB_CONTROL
    15161457/* Make sure we have a controlling tty.  If we get started under a job
    15171458 * aware app (like bash for example), make sure we are now in charge so
     
    15231464
    15241465    /* Loop until we are in the foreground.  */
    1525     while ((status = tcgetpgrp (shell_terminal)) >= 0) {
    1526         if (status == (shell_pgrp = getpgrp ())) {
     1466    while ((status = tcgetpgrp(shell_terminal)) >= 0) {
     1467        shell_pgrp = getpgrp();
     1468        if (status == shell_pgrp) {
    15271469            break;
    15281470        }
    1529         kill (- shell_pgrp, SIGTTIN);
     1471        kill(- shell_pgrp, SIGTTIN);
    15301472    }
    15311473
     
    15401482    /* Put ourselves in our own process group.  */
    15411483    setsid();
    1542     shell_pgrp = getpid ();
     1484    shell_pgrp = getpid();
    15431485    setpgid(shell_pgrp, shell_pgrp);
    15441486
     
    15521494#endif
    15531495
     1496int lash_main(int argc_l, char **argv_l);
    15541497int lash_main(int argc_l, char **argv_l)
    15551498{
    1556     int opt, interactive=FALSE;
     1499    unsigned opt;
    15571500    FILE *input = stdin;
    15581501    argc = argc_l;
    15591502    argv = argv_l;
    15601503
     1504#if ENABLE_FEATURE_EDITING
     1505    line_input_state = new_line_input_t(FOR_SHELL);
     1506#endif
     1507
    15611508    /* These variables need re-initializing when recursing */
    15621509    last_jobid = 0;
    1563     local_pending_command = NULL;
    15641510    close_me_list = NULL;
    15651511    job_list.head = NULL;
    15661512    job_list.fg = NULL;
    1567     last_return_code=1;
     1513    last_return_code = 1;
    15681514
    15691515    if (argv[0] && argv[0][0] == '-') {
     
    15741520            /* Now run the file */
    15751521            busy_loop(prof_input);
    1576             fclose(prof_input);
     1522            fclose_if_not_stdin(prof_input);
    15771523            llist_pop(&close_me_list);
    15781524        }
    15791525    }
    15801526
    1581     while ((opt = getopt(argc_l, argv_l, "cxi")) > 0) {
    1582         switch (opt) {
    1583             case 'c':
    1584                 input = NULL;
    1585                 if (local_pending_command != 0)
    1586                     bb_error_msg_and_die("multiple -c arguments");
    1587                 local_pending_command = bb_xstrdup(argv[optind]);
    1588                 optind++;
    1589                 argv = argv+optind;
    1590                 break;
    1591             case 'i':
    1592                 interactive++;
    1593                 break;
    1594             default:
    1595                 bb_show_usage();
    1596         }
     1527    opt = getopt32(argv_l, "+ic:", &local_pending_command);
     1528#define LASH_OPT_i (1<<0)
     1529#define LASH_OPT_c (1<<1)
     1530    if (opt & LASH_OPT_c) {
     1531        input = NULL;
     1532        optind++;
     1533        argv += optind;
    15971534    }
    15981535    /* A shell is interactive if the `-i' flag was given, or if all of
     
    16031540     *    standard output is a terminal
    16041541     *    Refer to Posix.2, the description of the `sh' utility. */
    1605     if (argv[optind]==NULL && input==stdin &&
    1606             isatty(STDIN_FILENO) && isatty(STDOUT_FILENO))
    1607     {
    1608         interactive++;
     1542    if (argv[optind] == NULL && input == stdin
     1543     && isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)
     1544    ) {
     1545        opt |= LASH_OPT_i;
    16091546    }
    16101547    setup_job_control();
    1611     if (interactive) {
     1548    if (opt & LASH_OPT_i) {
    16121549        /* Looks like they want an interactive shell */
    16131550        if (!ENABLE_FEATURE_SH_EXTRA_QUIET) {
    1614             printf( "\n\n%s Built-in shell (lash)\n", BB_BANNER);
    1615             printf( "Enter 'help' for a list of built-in commands.\n\n");
     1551            printf("\n\n%s built-in shell (lash)\n"
     1552                    "Enter 'help' for a list of built-in commands.\n\n",
     1553                    bb_banner);
    16161554        }
    16171555    } else if (!local_pending_command && argv[optind]) {
    16181556        //printf( "optind=%d  argv[optind]='%s'\n", optind, argv[optind]);
    1619         input = bb_xfopen(argv[optind], "r");
     1557        input = xfopen(argv[optind], "r");
    16201558        /* be lazy, never mark this closed */
    16211559        llist_add_to(&close_me_list, (void *)(long)fileno(input));
     
    16231561
    16241562    /* initialize the cwd -- this is never freed...*/
    1625     cwd = xgetcwd(0);
    1626     if (!cwd)
    1627         cwd = bb_msg_unknown;
     1563    update_cwd();
    16281564
    16291565    if (ENABLE_FEATURE_CLEAN_UP) atexit(free_memory);
    16301566
    1631     if (ENABLE_FEATURE_COMMAND_EDITING) cmdedit_set_initial_prompt();
     1567    if (ENABLE_FEATURE_EDITING) cmdedit_set_initial_prompt();
    16321568    else PS1 = NULL;
    16331569
    1634     return (busy_loop(input));
    1635 }
     1570    return busy_loop(input);
     1571}
  • branches/2.2.5/mindi-busybox/shell/msh.c

    r902 r1765  
    1111 *   Erik Andersen <andersen@codepoet.org>
    1212 *
    13  * This program is free software; you can redistribute it and/or modify
    14  * it under the terms of the GNU General Public License as published by
    15  * the Free Software Foundation; either version 2 of the License, or
    16  * (at your option) any later version.
    17  *
    18  * This program is distributed in the hope that it will be useful,
    19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    21  * General Public License for more details.
    22  *
    23  * You should have received a copy of the GNU General Public License
    24  * along with this program; if not, write to the Free Software
    25  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
    26  *
    27  * Original copyright notice is retained at the end of this file.
    28  */
    29 
    30 #include "busybox.h"
    31 #include <ctype.h>
    32 #include <dirent.h>
    33 #include <errno.h>
    34 #include <fcntl.h>
    35 #include <limits.h>
     13 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     14 */
     15
     16#include <sys/times.h>
    3617#include <setjmp.h>
    37 #include <signal.h>
    38 #include <stddef.h>
    39 #include <stdio.h>
    40 #include <stdlib.h>
    41 #include <string.h>
    42 #include <time.h>
    43 #include <unistd.h>
    44 #include <sys/stat.h>
    45 #include <sys/times.h>
    46 #include <sys/types.h>
    47 #include <sys/wait.h>
    48 
    49 #include "cmdedit.h"
    50 
    51 
    52 /* Conditional use of "register" keyword */
    53 #define REGISTER register
    54 
     18
     19#ifdef STANDALONE
     20# ifndef _GNU_SOURCE
     21#  define _GNU_SOURCE
     22# endif
     23# include <sys/types.h>
     24# include <sys/stat.h>
     25# include <sys/wait.h>
     26# include <signal.h>
     27# include <stdio.h>
     28# include <stdlib.h>
     29# include <unistd.h>
     30# include <string.h>
     31# include <errno.h>
     32# include <dirent.h>
     33# include <fcntl.h>
     34# include <ctype.h>
     35# include <assert.h>
     36# define bb_dev_null "/dev/null"
     37# define DEFAULT_SHELL "/proc/self/exe"
     38# define CONFIG_BUSYBOX_EXEC_PATH "/proc/self/exe"
     39# define bb_banner "busybox standalone"
     40# define ENABLE_FEATURE_SH_STANDALONE 0
     41# define bb_msg_memory_exhausted "memory exhausted"
     42# define xmalloc(size) malloc(size)
     43# define msh_main(argc,argv) main(argc,argv)
     44# define safe_read(fd,buf,count) read(fd,buf,count)
     45# define NOT_LONE_DASH(s) ((s)[0] != '-' || (s)[1])
     46# define LONE_CHAR(s,c) ((s)[0] == (c) && !(s)[1])
     47# define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__))
     48static char *find_applet_by_name(const char *applet)
     49{
     50    return NULL;
     51}
     52static char *utoa_to_buf(unsigned n, char *buf, unsigned buflen)
     53{
     54    unsigned i, out, res;
     55    assert(sizeof(unsigned) == 4);
     56    if (buflen) {
     57        out = 0;
     58        for (i = 1000000000; i; i /= 10) {
     59            res = n / i;
     60            if (res || out || i == 1) {
     61                if (!--buflen) break;
     62                out++;
     63                n -= res*i;
     64                *buf++ = '0' + res;
     65            }
     66        }
     67    }
     68    return buf;
     69}
     70static char *itoa_to_buf(int n, char *buf, unsigned buflen)
     71{
     72    if (buflen && n < 0) {
     73        n = -n;
     74        *buf++ = '-';
     75        buflen--;
     76    }
     77    return utoa_to_buf((unsigned)n, buf, buflen);
     78}
     79static char local_buf[12];
     80static char *itoa(int n)
     81{
     82    *(itoa_to_buf(n, local_buf, sizeof(local_buf))) = '\0';
     83    return local_buf;
     84}
     85#else
     86# include "busybox.h"
     87extern char **environ;
     88#endif
    5589
    5690/*#define MSHDEBUG 1*/
     
    5993int mshdbg = MSHDEBUG;
    6094
    61 #define DBGPRINTF(x)    if(mshdbg>0)printf x
    62 #define DBGPRINTF0(x)   if(mshdbg>0)printf x
    63 #define DBGPRINTF1(x)   if(mshdbg>1)printf x
    64 #define DBGPRINTF2(x)   if(mshdbg>2)printf x
    65 #define DBGPRINTF3(x)   if(mshdbg>3)printf x
    66 #define DBGPRINTF4(x)   if(mshdbg>4)printf x
    67 #define DBGPRINTF5(x)   if(mshdbg>5)printf x
    68 #define DBGPRINTF6(x)   if(mshdbg>6)printf x
    69 #define DBGPRINTF7(x)   if(mshdbg>7)printf x
    70 #define DBGPRINTF8(x)   if(mshdbg>8)printf x
    71 #define DBGPRINTF9(x)   if(mshdbg>9)printf x
     95#define DBGPRINTF(x)    if (mshdbg>0) printf x
     96#define DBGPRINTF0(x)   if (mshdbg>0) printf x
     97#define DBGPRINTF1(x)   if (mshdbg>1) printf x
     98#define DBGPRINTF2(x)   if (mshdbg>2) printf x
     99#define DBGPRINTF3(x)   if (mshdbg>3) printf x
     100#define DBGPRINTF4(x)   if (mshdbg>4) printf x
     101#define DBGPRINTF5(x)   if (mshdbg>5) printf x
     102#define DBGPRINTF6(x)   if (mshdbg>6) printf x
     103#define DBGPRINTF7(x)   if (mshdbg>7) printf x
     104#define DBGPRINTF8(x)   if (mshdbg>8) printf x
     105#define DBGPRINTF9(x)   if (mshdbg>9) printf x
    72106
    73107int mshdbg_rc = 0;
    74108
    75 #define RCPRINTF(x)     if(mshdbg_rc)printf x
     109#define RCPRINTF(x) if (mshdbg_rc) printf x
    76110
    77111#else
    78112
    79113#define DBGPRINTF(x)
    80 #define DBGPRINTF0(x)
    81 #define DBGPRINTF1(x)
    82 #define DBGPRINTF2(x)
    83 #define DBGPRINTF3(x)
    84 #define DBGPRINTF4(x)
    85 #define DBGPRINTF5(x)
    86 #define DBGPRINTF6(x)
    87 #define DBGPRINTF7(x)
    88 #define DBGPRINTF8(x)
    89 #define DBGPRINTF9(x)
    90 
    91 #define RCPRINTF(x)
     114#define DBGPRINTF0(x) ((void)0)
     115#define DBGPRINTF1(x) ((void)0)
     116#define DBGPRINTF2(x) ((void)0)
     117#define DBGPRINTF3(x) ((void)0)
     118#define DBGPRINTF4(x) ((void)0)
     119#define DBGPRINTF5(x) ((void)0)
     120#define DBGPRINTF6(x) ((void)0)
     121#define DBGPRINTF7(x) ((void)0)
     122#define DBGPRINTF8(x) ((void)0)
     123#define DBGPRINTF9(x) ((void)0)
     124
     125#define RCPRINTF(x) ((void)0)
    92126
    93127#endif                          /* MSHDEBUG */
    94128
    95129
    96 #ifdef CONFIG_FEATURE_SH_FANCY_PROMPT
     130#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
    97131# define DEFAULT_ROOT_PROMPT "\\u:\\w> "
    98132# define DEFAULT_USER_PROMPT "\\u:\\w$ "
     
    119153 * values returned by wait
    120154 */
    121 #define WAITSIG(s)  ((s)&0177)
    122 #define WAITVAL(s)  (((s)>>8)&0377)
    123 #define WAITCORE(s) (((s)&0200)!=0)
     155#define WAITSIG(s)  ((s) & 0177)
     156#define WAITVAL(s)  (((s) >> 8) & 0377)
     157#define WAITCORE(s) (((s) & 0200) != 0)
    124158
    125159/*
     
    131165 * shell components
    132166 */
    133 
    134 #define QUOTE   0200
    135 
    136167#define NOBLOCK ((struct op *)NULL)
    137168#define NOWORD  ((char *)NULL)
    138169#define NOWORDS ((char **)NULL)
    139170#define NOPIPE  ((int *)NULL)
     171
     172/*
     173 * redirection
     174 */
     175struct ioword {
     176    short io_unit;              /* unit affected */
     177    short io_flag;              /* action (below) */
     178    char *io_name;              /* file name */
     179};
     180
     181#define IOREAD   1              /* < */
     182#define IOHERE   2              /* << (here file) */
     183#define IOWRITE  4              /* > */
     184#define IOCAT    8              /* >> */
     185#define IOXHERE  16             /* ${}, ` in << */
     186#define IODUP    32             /* >&digit */
     187#define IOCLOSE  64             /* >&- */
     188
     189#define IODEFAULT (-1)          /* token for default IO unit */
     190
    140191
    141192/*
     
    173224/* Strings for names to make debug easier */
    174225#ifdef MSHDEBUG
    175 static char *T_CMD_NAMES[] = {
     226static const char *const T_CMD_NAMES[] = {
    176227    "PLACEHOLDER",
    177228    "TCOM",
     
    198249 * actions determining the environment of a process
    199250 */
    200 #define BIT(i)  (1<<(i))
    201 #define FEXEC   BIT(0)          /* execute without forking */
    202 
    203 #if 0                           /* Original value */
    204 #define AREASIZE    (65000)
    205 #else
    206 #define AREASIZE    (90000)
    207 #endif
     251#define FEXEC    1      /* execute without forking */
     252
     253#define AREASIZE (90000)
    208254
    209255/*
    210256 * flags to control evaluation of words
    211257 */
    212 #define DOSUB    1              /* interpret $, `, and quotes */
    213 #define DOBLANK  2              /* perform blank interpretation */
    214 #define DOGLOB   4              /* interpret [?* */
    215 #define DOKEY    8              /* move words with `=' to 2nd arg. list */
    216 #define DOTRIM   16             /* trim resulting string */
    217 
    218 #define DOALL   (DOSUB|DOBLANK|DOGLOB|DOKEY|DOTRIM)
    219 
    220 
    221 /* PROTOTYPES */
    222 static int newfile(char *s);
    223 static char *findeq(char *cp);
    224 static char *cclass(char *p, int sub);
    225 static void initarea(void);
    226 extern int msh_main(int argc, char **argv);
     258#define DOSUB    1      /* interpret $, `, and quotes */
     259#define DOBLANK  2      /* perform blank interpretation */
     260#define DOGLOB   4      /* interpret [?* */
     261#define DOKEY    8      /* move words with `=' to 2nd arg. list */
     262#define DOTRIM   16     /* trim resulting string */
     263
     264#define DOALL    (DOSUB|DOBLANK|DOGLOB|DOKEY|DOTRIM)
    227265
    228266
     
    232270};
    233271
    234 
    235 /*
    236  * redirection
    237  */
    238 struct ioword {
    239     short io_unit;              /* unit affected */
    240     short io_flag;              /* action (below) */
    241     char *io_name;              /* file name */
    242 };
    243 
    244 #define IOREAD   1              /* < */
    245 #define IOHERE   2              /* << (here file) */
    246 #define IOWRITE  4              /* > */
    247 #define IOCAT    8              /* >> */
    248 #define IOXHERE  16             /* ${}, ` in << */
    249 #define IODUP    32             /* >&digit */
    250 #define IOCLOSE  64             /* >&- */
    251 
    252 #define IODEFAULT (-1)          /* token for default IO unit */
    253 
    254 
    255 
    256 /*
    257  * parsing & execution environment
    258  */
    259 static struct env {
    260     char *linep;
    261     struct io *iobase;
    262     struct io *iop;
    263     xint *errpt;                /* void * */
    264     int iofd;
    265     struct env *oenv;
    266 } e;
    267272
    268273/*
     
    276281 * -u: unset variables net diagnostic
    277282 */
    278 static char *flag;
    279 
    280 static char *null;              /* null value for variable */
    281 static int intr;                /* interrupt pending */
    282 
    283 static char *trap[_NSIG + 1];
    284 static char ourtrap[_NSIG + 1];
     283static char flags['z' - 'a' + 1] ALIGN1;
     284/* this looks weird, but is OK ... we index FLAG with 'a'...'z' */
     285#define FLAG (flags - 'a')
     286
     287/* moved to G: static char *trap[_NSIG + 1]; */
     288/* moved to G: static char ourtrap[_NSIG + 1]; */
    285289static int trapset;             /* trap pending */
    286290
    287 static int heedint;             /* heed interrupt signals */
    288 
    289291static int yynerrs;             /* yacc */
    290292
    291 static char line[LINELIM];
    292 static char *elinep;
     293/* moved to G: static char line[LINELIM]; */
     294
     295#if ENABLE_FEATURE_EDITING
     296static char *current_prompt;
     297static line_input_t *line_input_state;
     298#endif
    293299
    294300
     
    296302 * other functions
    297303 */
    298 static int (*inbuilt(char *s)) (struct op *);
    299 
    300 static char *rexecve(char *c, char **v, char **envp);
    301 static char *space(int n);
    302 static char *strsave(char *s, int a);
     304static const char *rexecve(char *c, char **v, char **envp);
    303305static char *evalstr(char *cp, int f);
    304306static char *putn(int n);
    305 static char *itoa(int n);
    306307static char *unquote(char *as);
    307 static struct var *lookup(char *n);
    308308static int rlookup(char *n);
    309309static struct wdblock *glob(char *cp, struct wdblock *wb);
     
    319319static int newenv(int f);
    320320static void quitenv(void);
    321 static void err(char *s);
    322 static int anys(char *s1, char *s2);
    323 static int any(int c, char *s);
    324321static void next(int f);
    325322static void setdash(void);
    326323static void onecommand(void);
    327324static void runtrap(int i);
    328 static int gmatch(char *s, char *p);
    329 
    330 
    331 /*
    332  * error handling
    333  */
    334 static void leave(void);        /* abort shell (or fail in subshell) */
    335 static void fail(void);         /* fail but return to process next command */
    336 static void warn(char *s);
    337 static void sig(int i);         /* default signal handler */
    338 
    339325
    340326
    341327/* -------- area stuff -------- */
    342328
    343 #define REGSIZE   sizeof(struct region)
    344 #define GROWBY    (256)
    345 /* #define  SHRINKBY  (64) */
    346 #undef  SHRINKBY
    347 #define FREE      (32767)
    348 #define BUSY      (0)
    349 #define ALIGN     (sizeof(int)-1)
     329#define REGSIZE   sizeof(struct region)
     330#define GROWBY    (256)
     331/* #define SHRINKBY (64) */
     332#undef  SHRINKBY
     333#define FREE      (32767)
     334#define BUSY      (0)
     335#define ALIGN     (sizeof(int)-1)
    350336
    351337
     
    354340    int area;
    355341};
    356 
    357342
    358343
     
    365350} YYSTYPE;
    366351
    367 #define WORD    256
    368 #define LOGAND  257
    369 #define LOGOR   258
    370 #define BREAK   259
    371 #define IF      260
    372 #define THEN    261
    373 #define ELSE    262
    374 #define ELIF    263
    375 #define FI      264
    376 #define CASE    265
    377 #define ESAC    266
    378 #define FOR     267
    379 #define WHILE   268
    380 #define UNTIL   269
    381 #define DO      270
    382 #define DONE    271
    383 #define IN      272
     352#define WORD    256
     353#define LOGAND  257
     354#define LOGOR   258
     355#define BREAK   259
     356#define IF      260
     357#define THEN    261
     358#define ELSE    262
     359#define ELIF    263
     360#define FI      264
     361#define CASE    265
     362#define ESAC    266
     363#define FOR     267
     364#define WHILE   268
     365#define UNTIL   269
     366#define DO      270
     367#define DONE    271
     368#define IN      272
    384369/* Added for "." file expansion */
    385 #define DOT     273
     370#define DOT     273
    386371
    387372#define YYERRCODE 300
    388373
    389374/* flags to yylex */
    390 #define CONTIN  01              /* skip new lines to complete command */
    391 
    392 #define SYNTAXERR   zzerr()
     375#define CONTIN 01     /* skip new lines to complete command */
    393376
    394377static struct op *pipeline(int cf);
     
    415398static struct ioword **copyio(void);
    416399static struct ioword *io(int u, int f, char *cp);
    417 static void zzerr(void);
    418 static void yyerror(char *s);
    419400static int yylex(int cf);
    420401static int collect(int c, int c1);
     
    438419
    439420static int yyparse(void);
    440 static struct var *lookup(char *n);
    441 static void setval(struct var *vp, char *val);
    442 static void nameval(struct var *vp, char *val, char *name);
    443 static void export(struct var *vp);
    444 static void ronly(struct var *vp);
    445 static int isassign(char *s);
    446 static int checkname(char *cp);
    447 static int assign(char *s, int cf);
    448 static void putvlist(int f, int out);
    449 static int eqname(char *n1, char *n2);
    450421
    451422static int execute(struct op *t, int *pin, int *pout, int act);
     423
     424
     425#define AFID_NOBUF  (~0)
     426#define AFID_ID     0
    452427
    453428
     
    455430/* io buffer */
    456431struct iobuf {
    457     unsigned id;                /* buffer id */
    458     char buf[512];              /* buffer */
    459     char *bufp;                 /* pointer into buffer */
    460     char *ebufp;                /* pointer to end of buffer */
     432    unsigned id;            /* buffer id */
     433    char buf[512];          /* buffer */
     434    char *bufp;             /* pointer into buffer */
     435    char *ebufp;            /* pointer to end of buffer */
    461436};
    462437
    463438/* possible arguments to an IO function */
    464439struct ioarg {
    465     char *aword;
     440    const char *aword;
    466441    char **awordlist;
    467     int afile;                  /* file descriptor */
    468     unsigned afid;              /* buffer id */
    469     long afpos;                 /* file position */
    470     struct iobuf *afbuf;        /* buffer for this file */
     442    int afile;              /* file descriptor */
     443    unsigned afid;          /* buffer id */
     444    long afpos;             /* file position */
     445    struct iobuf *afbuf;    /* buffer for this file */
    471446};
    472 
    473 //static struct ioarg ioargstack[NPUSH];
    474 #define AFID_NOBUF  (~0)
    475 #define AFID_ID     0
    476447
    477448/* an input generator's state */
     
    480451    struct ioarg *argp;
    481452    int peekc;
    482     char prev;                  /* previous character read by readc() */
    483     char nlcount;               /* for `'s */
    484     char xchar;                 /* for `'s */
    485     char task;                  /* reason for pushed IO */
     453    char prev;              /* previous character read by readc() */
     454    char nlcount;           /* for `'s */
     455    char xchar;             /* for `'s */
     456    char task;              /* reason for pushed IO */
    486457};
    487458
    488 //static    struct  io  iostack[NPUSH];
    489459#define XOTHER  0               /* none of the below */
    490460#define XDOLL   1               /* expanding ${} */
    491461#define XGRAVE  2               /* expanding `'s */
    492 #define XIO 3                   /* file IO */
     462#define XIO 3               /* file IO */
    493463
    494464/* in substitution */
    495465#define INSUB() (e.iop->task == XGRAVE || e.iop->task == XDOLL)
     466
     467static struct ioarg temparg = { 0, 0, 0, AFID_NOBUF, 0 };   /* temporary for PUSHIO */
     468/* moved to G: static struct ioarg ioargstack[NPUSH]; */
     469static struct io iostack[NPUSH];
     470/* moved to G: static struct iobuf sharedbuf = { AFID_NOBUF }; */
     471/* moved to G: static struct iobuf mainbuf = { AFID_NOBUF }; */
     472static unsigned bufid = AFID_ID;    /* buffer id counter */
     473
     474#define RUN(what,arg,gen) ((temparg.what = (arg)), run(&temparg,(gen)))
    496475
    497476
     
    517496
    518497
    519 /*
    520  * IO functions
    521  */
    522498static int eofc(void);
    523499static int readc(void);
    524500static void unget(int c);
    525501static void ioecho(char c);
    526 static void prs(const char *s);
    527 static void prn(unsigned u);
    528 static void closef(int i);
    529 static void closeall(void);
    530502
    531503
     
    534506 */
    535507static void pushio(struct ioarg *argp, int (*f) (struct ioarg *));
     508#define PUSHIO(what,arg,gen) ((temparg.what = (arg)), pushio(&temparg,(gen)))
    536509static int remap(int fd);
    537510static int openpipe(int *pv);
    538511static void closepipe(int *pv);
    539512static struct io *setbase(struct io *ip);
    540 
    541 #define PUSHIO(what,arg,gen) ((temparg.what = (arg)),pushio(&temparg,(gen)))
    542 #define RUN(what,arg,gen) ((temparg.what = (arg)), run(&temparg,(gen)))
    543513
    544514/* -------- word.h -------- */
     
    557527static char **getwords(struct wdblock *wb);
    558528
    559 /* -------- area.h -------- */
    560 
    561 /*
    562  * storage allocation
    563  */
    564 static char *getcell(unsigned nbytes);
    565 static void garbage(void);
    566 static void setarea(char *cp, int a);
    567 static int getarea(char *cp);
    568 static void freearea(int a);
    569 static void freecell(char *cp);
    570 static int areanum;             /* current allocation area */
    571 
    572 #define NEW(type)   (type *)getcell(sizeof(type))
    573 #define DELETE(obj) freecell((char *)obj)
    574 
    575 
    576529/* -------- misc stuff -------- */
    577530
    578531static int forkexec(struct op *t, int *pin, int *pout, int act, char **wp);
    579532static int iosetup(struct ioword *iop, int pipein, int pipeout);
    580 static void echo(char **wp);
    581 static struct op **find1case(struct op *t, char *w);
    582 static struct op *findcase(struct op *t, char *w);
    583533static void brkset(struct brkcon *bc);
    584534static int dolabel(struct op *t);
     
    608558static void varput(char *s, int out);
    609559static int dotimes(struct op *t);
    610 static int expand(char *cp, struct wdblock **wbp, int f);
     560static int expand(const char *cp, struct wdblock **wbp, int f);
    611561static char *blank(int f);
    612562static int dollar(int quoted);
     
    616566static int anyspcl(struct wdblock *wb);
    617567static int xstrcmp(char *p1, char *p2);
    618 static void glob0(char *a0, unsigned int a1, int a2,
     568static void glob0(char *a0, unsigned a1, int a2,
    619569                  int (*a3) (char *, char *));
    620 static void glob1(char *base, char *lim);
    621 static void glob2(char *i, char *j);
    622 static void glob3(char *i, char *j, char *k);
    623570static void readhere(char **name, char *s, int ec);
    624 static void pushio(struct ioarg *argp, int (*f) (struct ioarg *));
    625571static int xxchar(struct ioarg *ap);
    626572
     
    632578};
    633579
    634 static const char * const signame[] = {
     580static const char *const signame[] = {
    635581    "Signal 0",
    636582    "Hangup",
    637     (char *) NULL,              /* interrupt */
     583    NULL,  /* interrupt */
    638584    "Quit",
    639585    "Illegal instruction",
     
    646592    "SIGSEGV",
    647593    "SIGUSR2",
    648     (char *) NULL,              /* broken pipe */
     594    NULL,  /* broken pipe */
    649595    "Alarm clock",
    650     "Terminated",
     596    "Terminated"
    651597};
    652598
    653 #define NSIGNAL (sizeof(signame)/sizeof(signame[0]))
    654599
    655600struct res {
     
    658603};
    659604static const struct res restab[] = {
    660     {"for", FOR},
    661     {"case", CASE},
    662     {"esac", ESAC},
    663     {"while", WHILE},
    664     {"do", DO},
    665     {"done", DONE},
    666     {"if", IF},
    667     {"in", IN},
    668     {"then", THEN},
    669     {"else", ELSE},
    670     {"elif", ELIF},
    671     {"until", UNTIL},
    672     {"fi", FI},
    673     {";;", BREAK},
    674     {"||", LOGOR},
    675     {"&&", LOGAND},
    676     {"{", '{'},
    677     {"}", '}'},
    678     {".", DOT},
    679     {0, 0},
     605    { "for"  , FOR    },
     606    { "case" , CASE   },
     607    { "esac" , ESAC   },
     608    { "while", WHILE  },
     609    { "do"   , DO     },
     610    { "done" , DONE   },
     611    { "if"   , IF     },
     612    { "in"   , IN     },
     613    { "then" , THEN   },
     614    { "else" , ELSE   },
     615    { "elif" , ELIF   },
     616    { "until", UNTIL  },
     617    { "fi"   , FI     },
     618    { ";;"   , BREAK  },
     619    { "||"   , LOGOR  },
     620    { "&&"   , LOGAND },
     621    { "{"    , '{'    },
     622    { "}"    , '}'    },
     623    { "."    , DOT    },
     624    { NULL   , 0      },
    680625};
    681 
    682626
    683627struct builtincmd {
    684628    const char *name;
    685     int (*builtinfunc) (struct op * t);
     629    int (*builtinfunc)(struct op *t);
    686630};
    687631static const struct builtincmd builtincmds[] = {
    688     {".", dodot},
    689     {":", dolabel},
    690     {"break", dobreak},
    691     {"cd", dochdir},
    692     {"continue", docontinue},
    693     {"eval", doeval},
    694     {"exec", doexec},
    695     {"exit", doexit},
    696     {"export", doexport},
    697     {"help", dohelp},
    698     {"login", dologin},
    699     {"newgrp", dologin},
    700     {"read", doread},
    701     {"readonly", doreadonly},
    702     {"set", doset},
    703     {"shift", doshift},
    704     {"times", dotimes},
    705     {"trap", dotrap},
    706     {"umask", doumask},
    707     {"wait", dowait},
    708     {0, 0}
     632    { "."       , dodot      },
     633    { ":"       , dolabel    },
     634    { "break"   , dobreak    },
     635    { "cd"      , dochdir    },
     636    { "continue", docontinue },
     637    { "eval"    , doeval     },
     638    { "exec"    , doexec     },
     639    { "exit"    , doexit     },
     640    { "export"  , doexport   },
     641    { "help"    , dohelp     },
     642    { "login"   , dologin    },
     643    { "newgrp"  , dologin    },
     644    { "read"    , doread     },
     645    { "readonly", doreadonly },
     646    { "set"     , doset      },
     647    { "shift"   , doshift    },
     648    { "times"   , dotimes    },
     649    { "trap"    , dotrap     },
     650    { "umask"   , doumask    },
     651    { "wait"    , dowait     },
     652    { NULL      , NULL       },
    709653};
    710654
     
    712656static struct op *dowholefile(int, int);
    713657
     658
    714659/* Globals */
    715 extern char **environ;          /* environment pointer */
    716 
    717660static char **dolv;
    718661static int dolc;
     
    729672static struct wdblock *wdlist;
    730673static struct wdblock *iolist;
    731 static char *trap[_NSIG + 1];
    732 static char ourtrap[_NSIG + 1];
    733 static int trapset;             /* trap pending */
    734 static int yynerrs;             /* yacc */
    735 static char line[LINELIM];
    736674
    737675#ifdef MSHDEBUG
     
    746684static struct var *ifs;         /* field separators */
    747685
    748 static int areanum;             /* current allocation area */
    749 static int intr;
     686static int areanum;                     /* current allocation area */
     687static int intr;                        /* interrupt pending */
    750688static int inparse;
    751 static char flags['z' - 'a' + 1];
    752 static char *flag = flags - 'a';
    753 static char *null = "";
    754 static int heedint = 1;
    755 static void (*qflag) (int) = SIG_IGN;
     689static char *null = (char*)"";          /* null value for variable */
     690static int heedint = 1;                 /* heed interrupt signals */
     691static void (*qflag)(int) = SIG_IGN;
    756692static int startl;
    757693static int peeksym;
     
    759695static int iounit = IODEFAULT;
    760696static YYSTYPE yylval;
    761 static char *elinep = line + sizeof(line) - 5;
    762 
    763 static struct ioarg temparg = { 0, 0, 0, AFID_NOBUF, 0 };   /* temporary for PUSHIO */
    764 static struct ioarg ioargstack[NPUSH];
    765 static struct io iostack[NPUSH];
    766 static struct iobuf sharedbuf = { AFID_NOBUF };
    767 static struct iobuf mainbuf = { AFID_NOBUF };
    768 static unsigned bufid = AFID_ID;    /* buffer id counter */
    769 
    770 static struct here *inhere;     /* list of hear docs while parsing */
    771 static struct here *acthere;    /* list of active here documents */
    772 static struct region *areabot;  /* bottom of area */
    773 static struct region *areatop;  /* top of area */
    774 static struct region *areanxt;  /* starting point of scan */
     697static char *elinep; /* done in main(): = line + sizeof(line) - 5 */
     698
     699static struct here *inhere;     /* list of hear docs while parsing */
     700static struct here *acthere;    /* list of active here documents */
     701static struct region *areabot;  /* bottom of area */
     702static struct region *areatop;  /* top of area */
     703static struct region *areanxt;  /* starting point of scan */
    775704static void *brktop;
    776705static void *brkaddr;
    777706
     707/*
     708 * parsing & execution environment
     709 */
     710struct env {
     711    char *linep;
     712    struct io *iobase;
     713    struct io *iop;
     714    xint *errpt;        /* void * */
     715    int iofd;
     716    struct env *oenv;
     717};
     718
    778719static struct env e = {
    779     line,                       /* linep:  char ptr */
    780     iostack,                    /* iobase:  struct io ptr */
    781     iostack - 1,                /* iop:  struct io ptr */
    782     (xint *) NULL,              /* errpt:  void ptr for errors? */
    783     FDBASE,                     /* iofd:  file desc  */
    784     (struct env *) NULL         /* oenv:  struct env ptr */
     720    NULL /* set to line in main() */, /* linep:  char ptr */
     721    iostack,                /* iobase:  struct io ptr */
     722    iostack - 1,            /* iop:  struct io ptr */
     723    (xint *) NULL,          /* errpt:  void ptr for errors? */
     724    FDBASE,                 /* iofd:  file desc  */
     725    (struct env *) NULL     /* oenv:  struct env ptr */
    785726};
    786727
     728
     729struct globals {
     730    char ourtrap[_NSIG + 1];
     731    char *trap[_NSIG + 1];
     732    struct iobuf sharedbuf; /* in main(): set to { AFID_NOBUF } */
     733    struct iobuf mainbuf; /* in main(): set to { AFID_NOBUF } */
     734    struct ioarg ioargstack[NPUSH];
     735    char filechar_cmdbuf[BUFSIZ];
     736    char line[LINELIM];
     737    char child_cmd[LINELIM];
     738};
     739
     740#define G (*ptr_to_globals)
     741#define ourtrap         (G.ourtrap        )
     742#define trap            (G.trap           )
     743#define sharedbuf       (G.sharedbuf      )
     744#define mainbuf         (G.mainbuf        )
     745#define ioargstack      (G.ioargstack     )
     746#define filechar_cmdbuf (G.filechar_cmdbuf)
     747#define line            (G.line           )
     748#define child_cmd       (G.child_cmd      )
     749
     750
    787751#ifdef MSHDEBUG
    788 void print_t(struct op *t);
    789752void print_t(struct op *t)
    790753{
     
    795758        DBGPRINTF(("T: W1: %s", t->words[0]));
    796759    }
    797 
    798     return;
    799 }
    800 
    801 void print_tree(struct op *head);
     760}
     761
    802762void print_tree(struct op *head)
    803763{
     
    815775    if (head->right)
    816776        print_tree(head->right);
    817 
    818     return;
    819 }
    820 #endif                          /* MSHDEBUG */
    821 
    822 
    823 #ifdef CONFIG_FEATURE_COMMAND_EDITING
    824 static char *current_prompt;
     777}
     778#endif /* MSHDEBUG */
     779
     780
     781/*
     782 * IO functions
     783 */
     784static void prs(const char *s)
     785{
     786    if (*s)
     787        write(2, s, strlen(s));
     788}
     789
     790static void prn(unsigned u)
     791{
     792    prs(itoa(u));
     793}
     794
     795static void echo(char **wp)
     796{
     797    int i;
     798
     799    prs("+");
     800    for (i = 0; wp[i]; i++) {
     801        if (i)
     802            prs(" ");
     803        prs(wp[i]);
     804    }
     805    prs("\n");
     806}
     807
     808static void closef(int i)
     809{
     810    if (i > 2)
     811        close(i);
     812}
     813
     814static void closeall(void)
     815{
     816    int u;
     817
     818    for (u = NUFILE; u < NOFILE;)
     819        close(u++);
     820}
     821
     822
     823/* fail but return to process next command */
     824static void fail(void) ATTRIBUTE_NORETURN;
     825static void fail(void)
     826{
     827    longjmp(failpt, 1);
     828    /* NOTREACHED */
     829}
     830
     831/* abort shell (or fail in subshell) */
     832static void leave(void) ATTRIBUTE_NORETURN;
     833static void leave(void)
     834{
     835    DBGPRINTF(("LEAVE: leave called!\n"));
     836
     837    if (execflg)
     838        fail();
     839    scraphere();
     840    freehere(1);
     841    runtrap(0);
     842    _exit(exstat);
     843    /* NOTREACHED */
     844}
     845
     846static void warn(const char *s)
     847{
     848    if (*s) {
     849        prs(s);
     850        exstat = -1;
     851    }
     852    prs("\n");
     853    if (FLAG['e'])
     854        leave();
     855}
     856
     857static void err(const char *s)
     858{
     859    warn(s);
     860    if (FLAG['n'])
     861        return;
     862    if (!interactive)
     863        leave();
     864    if (e.errpt)
     865        longjmp(e.errpt, 1);
     866    closeall();
     867    e.iop = e.iobase = iostack;
     868}
     869
     870
     871/* -------- area.c -------- */
     872
     873/*
     874 * All memory between (char *)areabot and (char *)(areatop+1) is
     875 * exclusively administered by the area management routines.
     876 * It is assumed that sbrk() and brk() manipulate the high end.
     877 */
     878
     879#define sbrk(X) ({ \
     880    void * __q = (void *)-1; \
     881    if (brkaddr + (int)(X) < brktop) { \
     882        __q = brkaddr; \
     883        brkaddr += (int)(X); \
     884    } \
     885    __q; \
     886})
     887
     888static void initarea(void)
     889{
     890    brkaddr = xmalloc(AREASIZE);
     891    brktop = brkaddr + AREASIZE;
     892
     893    while ((long) sbrk(0) & ALIGN)
     894        sbrk(1);
     895    areabot = (struct region *) sbrk(REGSIZE);
     896
     897    areabot->next = areabot;
     898    areabot->area = BUSY;
     899    areatop = areabot;
     900    areanxt = areabot;
     901}
     902
     903static char *getcell(unsigned nbytes)
     904{
     905    int nregio;
     906    struct region *p, *q;
     907    int i;
     908
     909    if (nbytes == 0) {
     910        puts("getcell(0)");
     911        abort();
     912    }
     913    /* silly and defeats the algorithm */
     914    /*
     915     * round upwards and add administration area
     916     */
     917    nregio = (nbytes + (REGSIZE - 1)) / REGSIZE + 1;
     918    p = areanxt;
     919    for (;;) {
     920        if (p->area > areanum) {
     921            /*
     922             * merge free cells
     923             */
     924            while ((q = p->next)->area > areanum && q != areanxt)
     925                p->next = q->next;
     926            /*
     927             * exit loop if cell big enough
     928             */
     929            if (q >= p + nregio)
     930                goto found;
     931        }
     932        p = p->next;
     933        if (p == areanxt)
     934            break;
     935    }
     936    i = nregio >= GROWBY ? nregio : GROWBY;
     937    p = (struct region *) sbrk(i * REGSIZE);
     938    if (p == (struct region *) -1)
     939        return NULL;
     940    p--;
     941    if (p != areatop) {
     942        puts("not contig");
     943        abort();                /* allocated areas are contiguous */
     944    }
     945    q = p + i;
     946    p->next = q;
     947    p->area = FREE;
     948    q->next = areabot;
     949    q->area = BUSY;
     950    areatop = q;
     951 found:
     952    /*
     953     * we found a FREE area big enough, pointed to by 'p', and up to 'q'
     954     */
     955    areanxt = p + nregio;
     956    if (areanxt < q) {
     957        /*
     958         * split into requested area and rest
     959         */
     960        if (areanxt + 1 > q) {
     961            puts("OOM");
     962            abort();            /* insufficient space left for admin */
     963        }
     964        areanxt->next = q;
     965        areanxt->area = FREE;
     966        p->next = areanxt;
     967    }
     968    p->area = areanum;
     969    return (char *) (p + 1);
     970}
     971
     972static void freecell(char *cp)
     973{
     974    struct region *p;
     975
     976    p = (struct region *) cp;
     977    if (p != NULL) {
     978        p--;
     979        if (p < areanxt)
     980            areanxt = p;
     981        p->area = FREE;
     982    }
     983}
     984#define DELETE(obj) freecell((char *)obj)
     985
     986static void freearea(int a)
     987{
     988    struct region *p, *top;
     989
     990    top = areatop;
     991    for (p = areabot; p != top; p = p->next)
     992        if (p->area >= a)
     993            p->area = FREE;
     994}
     995
     996static void setarea(char *cp, int a)
     997{
     998    struct region *p;
     999
     1000    p = (struct region *) cp;
     1001    if (p != NULL)
     1002        (p - 1)->area = a;
     1003}
     1004
     1005static int getarea(char *cp)
     1006{
     1007    return ((struct region *) cp - 1)->area;
     1008}
     1009
     1010static void garbage(void)
     1011{
     1012    struct region *p, *q, *top;
     1013
     1014    top = areatop;
     1015    for (p = areabot; p != top; p = p->next) {
     1016        if (p->area > areanum) {
     1017            while ((q = p->next)->area > areanum)
     1018                p->next = q->next;
     1019            areanxt = p;
     1020        }
     1021    }
     1022#ifdef SHRINKBY
     1023    if (areatop >= q + SHRINKBY && q->area > areanum) {
     1024        brk((char *) (q + 1));
     1025        q->next = areabot;
     1026        q->area = BUSY;
     1027        areatop = q;
     1028    }
    8251029#endif
    826 
    827 /* -------- sh.c -------- */
    828 /*
    829  * shell
    830  */
    831 
    832 
    833 int msh_main(int argc, char **argv)
    834 {
    835     REGISTER int f;
    836     REGISTER char *s;
    837     int cflag;
    838     char *name, **ap;
    839     int (*iof) (struct ioarg *);
    840 
    841     DBGPRINTF(("MSH_MAIN: argc %d, environ %p\n", argc, environ));
    842 
    843     initarea();
    844     if ((ap = environ) != NULL) {
    845         while (*ap)
    846             assign(*ap++, !COPYV);
    847         for (ap = environ; *ap;)
    848             export(lookup(*ap++));
    849     }
    850     closeall();
    851     areanum = 1;
    852 
    853     shell = lookup("SHELL");
    854     if (shell->value == null)
    855         setval(shell, (char *)DEFAULT_SHELL);
    856     export(shell);
    857 
    858     homedir = lookup("HOME");
    859     if (homedir->value == null)
    860         setval(homedir, "/");
    861     export(homedir);
    862 
    863     setval(lookup("$"), putn(getpid()));
    864 
    865     path = lookup("PATH");
    866     if (path->value == null) {
    867         if (geteuid() == 0)
    868             setval(path, "/sbin:/bin:/usr/sbin:/usr/bin");
    869         else
    870             setval(path, "/bin:/usr/bin");
    871     }
    872     export(path);
    873 
    874     ifs = lookup("IFS");
    875     if (ifs->value == null)
    876         setval(ifs, " \t\n");
    877 
    878 #ifdef MSHDEBUG
    879     mshdbg_var = lookup("MSHDEBUG");
    880     if (mshdbg_var->value == null)
    881         setval(mshdbg_var, "0");
    882 #endif
    883 
    884     prompt = lookup("PS1");
    885 #ifdef CONFIG_FEATURE_SH_FANCY_PROMPT
    886     if (prompt->value == null)
    887 #endif
    888         setval(prompt, DEFAULT_USER_PROMPT);
    889     if (geteuid() == 0) {
    890         setval(prompt, DEFAULT_ROOT_PROMPT);
    891         prompt->status &= ~EXPORT;
    892     }
    893     cprompt = lookup("PS2");
    894 #ifdef CONFIG_FEATURE_SH_FANCY_PROMPT
    895     if (cprompt->value == null)
    896 #endif
    897         setval(cprompt, "> ");
    898 
    899     iof = filechar;
    900     cflag = 0;
    901     name = *argv++;
    902     if (--argc >= 1) {
    903         if (argv[0][0] == '-' && argv[0][1] != '\0') {
    904             for (s = argv[0] + 1; *s; s++)
    905                 switch (*s) {
    906                 case 'c':
    907                     prompt->status &= ~EXPORT;
    908                     cprompt->status &= ~EXPORT;
    909                     setval(prompt, "");
    910                     setval(cprompt, "");
    911                     cflag = 1;
    912                     if (--argc > 0)
    913                         PUSHIO(aword, *++argv, iof = nlchar);
    914                     break;
    915 
    916                 case 'q':
    917                     qflag = SIG_DFL;
    918                     break;
    919 
    920                 case 's':
    921                     /* standard input */
    922                     break;
    923 
    924                 case 't':
    925                     prompt->status &= ~EXPORT;
    926                     setval(prompt, "");
    927                     iof = linechar;
    928                     break;
    929 
    930                 case 'i':
    931                     interactive++;
    932                 default:
    933                     if (*s >= 'a' && *s <= 'z')
    934                         flag[(int) *s]++;
    935                 }
    936         } else {
    937             argv--;
    938             argc++;
    939         }
    940 
    941         if (iof == filechar && --argc > 0) {
    942             setval(prompt, "");
    943             setval(cprompt, "");
    944             prompt->status &= ~EXPORT;
    945             cprompt->status &= ~EXPORT;
    946 
    947 /* Shell is non-interactive, activate printf-based debug */
    948 #ifdef MSHDEBUG
    949             mshdbg = (int) (((char) (mshdbg_var->value[0])) - '0');
    950             if (mshdbg < 0)
    951                 mshdbg = 0;
    952 #endif
    953             DBGPRINTF(("MSH_MAIN: calling newfile()\n"));
    954 
    955             if (newfile(name = *++argv))
    956                 exit(1);        /* Exit on error */
    957         }
    958     }
    959 
    960     setdash();
    961 
    962     /* This won't be true if PUSHIO has been called, say from newfile() above */
    963     if (e.iop < iostack) {
    964         PUSHIO(afile, 0, iof);
    965         if (isatty(0) && isatty(1) && !cflag) {
    966             interactive++;
    967 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
    968 #ifdef MSHDEBUG
    969             printf("\n\n%s Built-in shell (msh with debug)\n", BB_BANNER);
    970 #else
    971             printf("\n\n%s Built-in shell (msh)\n", BB_BANNER);
    972 #endif
    973             printf("Enter 'help' for a list of built-in commands.\n\n");
    974 #endif
    975         }
    976     }
    977 
    978     signal(SIGQUIT, qflag);
    979     if (name && name[0] == '-') {
    980         interactive++;
    981         if ((f = open(".profile", 0)) >= 0)
    982             next(remap(f));
    983         if ((f = open("/etc/profile", 0)) >= 0)
    984             next(remap(f));
    985     }
    986     if (interactive)
    987         signal(SIGTERM, sig);
    988 
    989     if (signal(SIGINT, SIG_IGN) != SIG_IGN)
    990         signal(SIGINT, onintr);
    991     dolv = argv;
    992     dolc = argc;
    993     dolv[0] = name;
    994     if (dolc > 1) {
    995         for (ap = ++argv; --argc > 0;) {
    996             if (assign(*ap = *argv++, !COPYV)) {
    997                 dolc--;         /* keyword */
    998             } else {
    999                 ap++;
    1000             }
    1001         }
    1002     }
    1003     setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc));
    1004 
    1005     DBGPRINTF(("MSH_MAIN: begin FOR loop, interactive %d, e.iop %p, iostack %p\n", interactive, e.iop, iostack));
    1006 
    1007     for (;;) {
    1008         if (interactive && e.iop <= iostack) {
    1009 #ifdef CONFIG_FEATURE_COMMAND_EDITING
    1010             current_prompt = prompt->value;
    1011 #else
    1012             prs(prompt->value);
    1013 #endif
    1014         }
    1015         onecommand();
    1016         /* Ensure that getenv("PATH") stays current */
    1017         setenv("PATH", path->value, 1);
    1018     }
    1019 
    1020     DBGPRINTF(("MSH_MAIN: returning.\n"));
    1021 }
     1030}
     1031
     1032static char *space(int n)
     1033{
     1034    char *cp;
     1035
     1036    cp = getcell(n);
     1037    if (cp == NULL)
     1038        err("out of string space");
     1039    return cp;
     1040}
     1041
     1042static char *strsave(const char *s, int a)
     1043{
     1044    char *cp;
     1045
     1046    cp = space(strlen(s) + 1);
     1047    if (cp == NULL) {
     1048// FIXME: I highly doubt this is good.
     1049        return (char*)"";
     1050    }
     1051    setarea(cp, a);
     1052    strcpy(cp, s);
     1053    return cp;
     1054}
     1055
     1056
     1057/* -------- var.c -------- */
     1058
     1059static int eqname(const char *n1, const char *n2)
     1060{
     1061    for (; *n1 != '=' && *n1 != '\0'; n1++)
     1062        if (*n2++ != *n1)
     1063            return 0;
     1064    return *n2 == '\0' || *n2 == '=';
     1065}
     1066
     1067static const char *findeq(const char *cp)
     1068{
     1069    while (*cp != '\0' && *cp != '=')
     1070        cp++;
     1071    return cp;
     1072}
     1073
     1074/*
     1075 * Find the given name in the dictionary
     1076 * and return its value.  If the name was
     1077 * not previously there, enter it now and
     1078 * return a null value.
     1079 */
     1080static struct var *lookup(const char *n)
     1081{
     1082// FIXME: dirty hack
     1083    static struct var dummy;
     1084
     1085    struct var *vp;
     1086    const char *cp;
     1087    char *xp;
     1088    int c;
     1089
     1090    if (isdigit(*n)) {
     1091        dummy.name = (char*)n;
     1092        for (c = 0; isdigit(*n) && c < 1000; n++)
     1093            c = c * 10 + *n - '0';
     1094        dummy.status = RONLY;
     1095        dummy.value = (c <= dolc ? dolv[c] : null);
     1096        return &dummy;
     1097    }
     1098
     1099    for (vp = vlist; vp; vp = vp->next)
     1100        if (eqname(vp->name, n))
     1101            return vp;
     1102
     1103    cp = findeq(n);
     1104    vp = (struct var *) space(sizeof(*vp));
     1105    if (vp == 0 || (vp->name = space((int) (cp - n) + 2)) == 0) {
     1106        dummy.name = dummy.value = (char*)"";
     1107        return &dummy;
     1108    }
     1109
     1110    xp = vp->name;
     1111    while ((*xp = *n++) != '\0' && *xp != '=')
     1112        xp++;
     1113    *xp++ = '=';
     1114    *xp = '\0';
     1115    setarea((char *) vp, 0);
     1116    setarea((char *) vp->name, 0);
     1117    vp->value = null;
     1118    vp->next = vlist;
     1119    vp->status = GETCELL;
     1120    vlist = vp;
     1121    return vp;
     1122}
     1123
     1124/*
     1125 * if name is not NULL, it must be
     1126 * a prefix of the space `val',
     1127 * and end with `='.
     1128 * this is all so that exporting
     1129 * values is reasonably painless.
     1130 */
     1131static void nameval(struct var *vp, const char *val, const char *name)
     1132{
     1133    const char *cp;
     1134    char *xp;
     1135    int fl;
     1136
     1137    if (vp->status & RONLY) {
     1138        xp = vp->name;
     1139        while (*xp && *xp != '=')
     1140            putc(*xp++, stderr);
     1141        err(" is read-only");
     1142        return;
     1143    }
     1144    fl = 0;
     1145    if (name == NULL) {
     1146        xp = space(strlen(vp->name) + strlen(val) + 2);
     1147        if (xp == NULL)
     1148            return;
     1149        /* make string: name=value */
     1150        setarea(xp, 0);
     1151        name = xp;
     1152        cp = vp->name;
     1153        while ((*xp = *cp++) != '\0' && *xp != '=')
     1154            xp++;
     1155        *xp++ = '=';
     1156        strcpy(xp, val);
     1157        val = xp;
     1158        fl = GETCELL;
     1159    }
     1160    if (vp->status & GETCELL)
     1161        freecell(vp->name);     /* form new string `name=value' */
     1162    vp->name = (char*)name;
     1163    vp->value = (char*)val;
     1164    vp->status |= fl;
     1165}
     1166
     1167/*
     1168 * give variable at `vp' the value `val'.
     1169 */
     1170static void setval(struct var *vp, const char *val)
     1171{
     1172    nameval(vp, val, NULL);
     1173}
     1174
     1175static void export(struct var *vp)
     1176{
     1177    vp->status |= EXPORT;
     1178}
     1179
     1180static void ronly(struct var *vp)
     1181{
     1182    if (isalpha(vp->name[0]) || vp->name[0] == '_') /* not an internal symbol */
     1183        vp->status |= RONLY;
     1184}
     1185
     1186static int isassign(const char *s)
     1187{
     1188    unsigned char c;
     1189    DBGPRINTF7(("ISASSIGN: enter, s=%s\n", s));
     1190
     1191    c = *s;
     1192    /* no isalpha() - we shouldn't use locale */
     1193    /* c | 0x20 - lowercase (Latin) letters */
     1194    if (c != '_' && (unsigned)((c|0x20) - 'a') > 25)
     1195        /* not letter */
     1196        return 0;
     1197
     1198    while (1) {
     1199        c = *++s;
     1200        if (c == '=')
     1201            return 1;
     1202        if (c == '\0')
     1203            return 0;
     1204        if (c != '_'
     1205         && (unsigned)(c - '0') > 9  /* not number */
     1206         && (unsigned)((c|0x20) - 'a') > 25 /* not letter */
     1207        ) {
     1208            return 0;
     1209        }
     1210    }
     1211}
     1212
     1213static int assign(const char *s, int cf)
     1214{
     1215    const char *cp;
     1216    struct var *vp;
     1217
     1218    DBGPRINTF7(("ASSIGN: enter, s=%s, cf=%d\n", s, cf));
     1219
     1220    if (!isalpha(*s) && *s != '_')
     1221        return 0;
     1222    for (cp = s; *cp != '='; cp++)
     1223        if (*cp == '\0' || (!isalnum(*cp) && *cp != '_'))
     1224            return 0;
     1225    vp = lookup(s);
     1226    nameval(vp, ++cp, cf == COPYV ? NULL : s);
     1227    if (cf != COPYV)
     1228        vp->status &= ~GETCELL;
     1229    return 1;
     1230}
     1231
     1232static int checkname(char *cp)
     1233{
     1234    DBGPRINTF7(("CHECKNAME: enter, cp=%s\n", cp));
     1235
     1236    if (!isalpha(*cp++) && *(cp - 1) != '_')
     1237        return 0;
     1238    while (*cp)
     1239        if (!isalnum(*cp++) && *(cp - 1) != '_')
     1240            return 0;
     1241    return 1;
     1242}
     1243
     1244static void putvlist(int f, int out)
     1245{
     1246    struct var *vp;
     1247
     1248    for (vp = vlist; vp; vp = vp->next) {
     1249        if (vp->status & f && (isalpha(*vp->name) || *vp->name == '_')) {
     1250            if (vp->status & EXPORT)
     1251                write(out, "export ", 7);
     1252            if (vp->status & RONLY)
     1253                write(out, "readonly ", 9);
     1254            write(out, vp->name, (int) (findeq(vp->name) - vp->name));
     1255            write(out, "\n", 1);
     1256        }
     1257    }
     1258}
     1259
     1260
     1261/*
     1262 * trap handling
     1263 */
     1264static void sig(int i)
     1265{
     1266    trapset = i;
     1267    signal(i, sig);
     1268}
     1269
     1270static void runtrap(int i)
     1271{
     1272    char *trapstr;
     1273
     1274    trapstr = trap[i];
     1275    if (trapstr == NULL)
     1276        return;
     1277
     1278    if (i == 0)
     1279        trap[i] = NULL;
     1280
     1281    RUN(aword, trapstr, nlchar);
     1282}
     1283
    10221284
    10231285static void setdash(void)
    10241286{
    1025     REGISTER char *cp;
    1026     REGISTER int c;
     1287    char *cp;
     1288    int c;
    10271289    char m['z' - 'a' + 1];
    10281290
    10291291    cp = m;
    10301292    for (c = 'a'; c <= 'z'; c++)
    1031         if (flag[(int) c])
     1293        if (FLAG[c])
    10321294            *cp++ = c;
    1033     *cp = 0;
     1295    *cp = '\0';
    10341296    setval(lookup("-"), m);
    10351297}
    10361298
    1037 static int newfile(REGISTER char *s)
    1038 {
    1039     REGISTER int f;
     1299static int newfile(char *s)
     1300{
     1301    int f;
    10401302
    10411303    DBGPRINTF7(("NEWFILE: opening %s\n", s));
    10421304
    1043     if (strcmp(s, "-") != 0) {
     1305    f = 0;
     1306    if (NOT_LONE_DASH(s)) {
    10441307        DBGPRINTF(("NEWFILE: s is %s\n", s));
    1045         f = open(s, 0);
     1308        f = open(s, O_RDONLY);
    10461309        if (f < 0) {
    10471310            prs(s);
    10481311            err(": cannot open");
    1049             return (1);
    1050         }
    1051     } else
    1052         f = 0;
     1312            return 1;
     1313        }
     1314    }
    10531315
    10541316    next(remap(f));
    1055     return (0);
     1317    return 0;
    10561318}
    10571319
     
    10621324
    10631325    if (head == NULL)
    1064         return (NULL);
     1326        return NULL;
    10651327
    10661328    if (head->left != NULL) {
    10671329        dotnode = scantree(head->left);
    10681330        if (dotnode)
    1069             return (dotnode);
     1331            return dotnode;
    10701332    }
    10711333
     
    10731335        dotnode = scantree(head->right);
    10741336        if (dotnode)
    1075             return (dotnode);
     1337            return dotnode;
    10761338    }
    10771339
    10781340    if (head->words == NULL)
    1079         return (NULL);
     1341        return NULL;
    10801342
    10811343    DBGPRINTF5(("SCANTREE: checking node %p\n", head));
    10821344
    1083     if ((head->type != TDOT) && (strcmp(".", head->words[0]) == 0)) {
     1345    if ((head->type != TDOT) && LONE_CHAR(head->words[0], '.')) {
    10841346        DBGPRINTF5(("SCANTREE: dot found in node %p\n", head));
    1085         return (head);
    1086     }
    1087 
    1088     return (NULL);
     1347        return head;
     1348    }
     1349
     1350    return NULL;
    10891351}
    10901352
     
    10921354static void onecommand(void)
    10931355{
    1094     REGISTER int i;
     1356    int i;
    10951357    jmp_buf m1;
    10961358
     
    11141376    execflg = 0;
    11151377
    1116     setjmp(failpt = m1);        /* Bruce Evans' fix */
    1117     if (setjmp(failpt = m1) || yyparse() || intr) {
    1118 
     1378    failpt = m1;
     1379    setjmp(failpt);     /* Bruce Evans' fix */
     1380    failpt = m1;
     1381    if (setjmp(failpt) || yyparse() || intr) {
    11191382        DBGPRINTF(("ONECOMMAND: this is not good.\n"));
    11201383
     
    11341397    execflg = 0;
    11351398
    1136     if (!flag['n']) {
     1399    if (!FLAG['n']) {
    11371400        DBGPRINTF(("ONECOMMAND: calling execute, t=outtree=%p\n",
    11381401                   outtree));
     
    11451408    }
    11461409
    1147     if ((i = trapset) != 0) {
     1410    i = trapset;
     1411    if (i != 0) {
    11481412        trapset = 0;
    11491413        runtrap(i);
     
    11511415}
    11521416
    1153 static void fail(void)
    1154 {
    1155     longjmp(failpt, 1);
    1156     /* NOTREACHED */
    1157 }
    1158 
    1159 static void leave(void)
    1160 {
    1161     DBGPRINTF(("LEAVE: leave called!\n"));
    1162 
    1163     if (execflg)
    1164         fail();
    1165     scraphere();
    1166     freehere(1);
    1167     runtrap(0);
    1168     _exit(exstat);
    1169     /* NOTREACHED */
    1170 }
    1171 
    1172 static void warn(REGISTER char *s)
    1173 {
    1174     if (*s) {
    1175         prs(s);
    1176         exstat = -1;
    1177     }
    1178     prs("\n");
    1179     if (flag['e'])
    1180         leave();
    1181 }
    1182 
    1183 static void err(char *s)
    1184 {
    1185     warn(s);
    1186     if (flag['n'])
    1187         return;
    1188     if (!interactive)
    1189         leave();
    1190     if (e.errpt)
    1191         longjmp(e.errpt, 1);
    1192     closeall();
    1193     e.iop = e.iobase = iostack;
    1194 }
    1195 
    11961417static int newenv(int f)
    11971418{
    1198     REGISTER struct env *ep;
     1419    struct env *ep;
    11991420
    12001421    DBGPRINTF(("NEWENV: f=%d (indicates quitenv and return)\n", f));
     
    12021423    if (f) {
    12031424        quitenv();
    1204         return (1);
     1425        return 1;
    12051426    }
    12061427
     
    12151436    e.errpt = errpt;
    12161437
    1217     return (0);
     1438    return 0;
    12181439}
    12191440
    12201441static void quitenv(void)
    12211442{
    1222     REGISTER struct env *ep;
    1223     REGISTER int fd;
     1443    struct env *ep;
     1444    int fd;
    12241445
    12251446    DBGPRINTF(("QUITENV: e.oenv=%p\n", e.oenv));
    12261447
    1227     if ((ep = e.oenv) != NULL) {
     1448    ep = e.oenv;
     1449    if (ep != NULL) {
    12281450        fd = e.iofd;
    12291451        e = *ep;
     
    12361458
    12371459/*
     1460 * Is character c in s?
     1461 */
     1462static int any(int c, const char *s)
     1463{
     1464    while (*s)
     1465        if (*s++ == c)
     1466            return 1;
     1467    return 0;
     1468}
     1469
     1470/*
    12381471 * Is any character from s1 in s2?
    12391472 */
    1240 static int anys(REGISTER char *s1, REGISTER char *s2)
     1473static int anys(const char *s1, const char *s2)
    12411474{
    12421475    while (*s1)
    12431476        if (any(*s1++, s2))
    1244             return (1);
    1245     return (0);
    1246 }
    1247 
    1248 /*
    1249  * Is character c in s?
    1250  */
    1251 static int any(REGISTER int c, REGISTER char *s)
    1252 {
    1253     while (*s)
    1254         if (*s++ == c)
    1255             return (1);
    1256     return (0);
    1257 }
    1258 
    1259 static char *putn(REGISTER int n)
    1260 {
    1261     return (itoa(n));
    1262 }
    1263 
    1264 static char *itoa(REGISTER int n)
    1265 {
    1266     static char s[20];
    1267 
    1268     snprintf(s, sizeof(s), "%u", n);
    1269     return (s);
    1270 }
    1271 
     1477            return 1;
     1478    return 0;
     1479}
     1480
     1481static char *putn(int n)
     1482{
     1483    return itoa(n);
     1484}
    12721485
    12731486static void next(int f)
     
    12911504}
    12921505
    1293 static char *space(int n)
    1294 {
    1295     REGISTER char *cp;
    1296 
    1297     if ((cp = getcell(n)) == 0)
    1298         err("out of string space");
    1299     return (cp);
    1300 }
    1301 
    1302 static char *strsave(REGISTER char *s, int a)
    1303 {
    1304     REGISTER char *cp, *xp;
    1305 
    1306     if ((cp = space(strlen(s) + 1)) != NULL) {
    1307         setarea((char *) cp, a);
    1308         for (xp = cp; (*xp++ = *s++) != '\0';);
    1309         return (cp);
    1310     }
    1311     return ("");
    1312 }
    1313 
    1314 /*
    1315  * trap handling
    1316  */
    1317 static void sig(REGISTER int i)
    1318 {
    1319     trapset = i;
    1320     signal(i, sig);
    1321 }
    1322 
    1323 static void runtrap(int i)
    1324 {
    1325     char *trapstr;
    1326 
    1327     if ((trapstr = trap[i]) == NULL)
    1328         return;
    1329 
    1330     if (i == 0)
    1331         trap[i] = 0;
    1332 
    1333     RUN(aword, trapstr, nlchar);
    1334 }
    1335 
    1336 /* -------- var.c -------- */
    1337 
    1338 /*
    1339  * Find the given name in the dictionary
    1340  * and return its value.  If the name was
    1341  * not previously there, enter it now and
    1342  * return a null value.
    1343  */
    1344 static struct var *lookup(REGISTER char *n)
    1345 {
    1346     REGISTER struct var *vp;
    1347     REGISTER char *cp;
    1348     REGISTER int c;
    1349     static struct var dummy;
    1350 
    1351     if (isdigit(*n)) {
    1352         dummy.name = n;
    1353         for (c = 0; isdigit(*n) && c < 1000; n++)
    1354             c = c * 10 + *n - '0';
    1355         dummy.status = RONLY;
    1356         dummy.value = c <= dolc ? dolv[c] : null;
    1357         return (&dummy);
    1358     }
    1359     for (vp = vlist; vp; vp = vp->next)
    1360         if (eqname(vp->name, n))
    1361             return (vp);
    1362     cp = findeq(n);
    1363     vp = (struct var *) space(sizeof(*vp));
    1364     if (vp == 0 || (vp->name = space((int) (cp - n) + 2)) == 0) {
    1365         dummy.name = dummy.value = "";
    1366         return (&dummy);
    1367     }
    1368     for (cp = vp->name; (*cp = *n++) && *cp != '='; cp++);
    1369     if (*cp == 0)
    1370         *cp = '=';
    1371     *++cp = 0;
    1372     setarea((char *) vp, 0);
    1373     setarea((char *) vp->name, 0);
    1374     vp->value = null;
    1375     vp->next = vlist;
    1376     vp->status = GETCELL;
    1377     vlist = vp;
    1378     return (vp);
    1379 }
    1380 
    1381 /*
    1382  * give variable at `vp' the value `val'.
    1383  */
    1384 static void setval(struct var *vp, char *val)
    1385 {
    1386     nameval(vp, val, (char *) NULL);
    1387 }
    1388 
    1389 /*
    1390  * if name is not NULL, it must be
    1391  * a prefix of the space `val',
    1392  * and end with `='.
    1393  * this is all so that exporting
    1394  * values is reasonably painless.
    1395  */
    1396 static void nameval(REGISTER struct var *vp, char *val, char *name)
    1397 {
    1398     REGISTER char *cp, *xp;
    1399     char *nv;
    1400     int fl;
    1401 
    1402     if (vp->status & RONLY) {
    1403         for (xp = vp->name; *xp && *xp != '=';)
    1404             putc(*xp++, stderr);
    1405         err(" is read-only");
    1406         return;
    1407     }
    1408     fl = 0;
    1409     if (name == NULL) {
    1410         xp = space(strlen(vp->name) + strlen(val) + 2);
    1411         if (xp == 0)
    1412             return;
    1413         /* make string:  name=value */
    1414         setarea((char *) xp, 0);
    1415         name = xp;
    1416         for (cp = vp->name; (*xp = *cp++) && *xp != '='; xp++);
    1417         if (*xp++ == 0)
    1418             xp[-1] = '=';
    1419         nv = xp;
    1420         for (cp = val; (*xp++ = *cp++) != '\0';);
    1421         val = nv;
    1422         fl = GETCELL;
    1423     }
    1424     if (vp->status & GETCELL)
    1425         freecell(vp->name);     /* form new string `name=value' */
    1426     vp->name = name;
    1427     vp->value = val;
    1428     vp->status |= fl;
    1429 }
    1430 
    1431 static void export(struct var *vp)
    1432 {
    1433     vp->status |= EXPORT;
    1434 }
    1435 
    1436 static void ronly(struct var *vp)
    1437 {
    1438     if (isalpha(vp->name[0]) || vp->name[0] == '_') /* not an internal symbol */
    1439         vp->status |= RONLY;
    1440 }
    1441 
    1442 static int isassign(REGISTER char *s)
    1443 {
    1444     DBGPRINTF7(("ISASSIGN: enter, s=%s\n", s));
    1445 
    1446     if (!isalpha((int) *s) && *s != '_')
    1447         return (0);
    1448     for (; *s != '='; s++)
    1449         if (*s == 0 || (!isalnum(*s) && *s != '_'))
    1450             return (0);
    1451 
    1452     return (1);
    1453 }
    1454 
    1455 static int assign(REGISTER char *s, int cf)
    1456 {
    1457     REGISTER char *cp;
    1458     struct var *vp;
    1459 
    1460     DBGPRINTF7(("ASSIGN: enter, s=%s, cf=%d\n", s, cf));
    1461 
    1462     if (!isalpha(*s) && *s != '_')
    1463         return (0);
    1464     for (cp = s; *cp != '='; cp++)
    1465         if (*cp == 0 || (!isalnum(*cp) && *cp != '_'))
    1466             return (0);
    1467     vp = lookup(s);
    1468     nameval(vp, ++cp, cf == COPYV ? (char *) NULL : s);
    1469     if (cf != COPYV)
    1470         vp->status &= ~GETCELL;
    1471     return (1);
    1472 }
    1473 
    1474 static int checkname(REGISTER char *cp)
    1475 {
    1476     DBGPRINTF7(("CHECKNAME: enter, cp=%s\n", cp));
    1477 
    1478     if (!isalpha(*cp++) && *(cp - 1) != '_')
    1479         return (0);
    1480     while (*cp)
    1481         if (!isalnum(*cp++) && *(cp - 1) != '_')
    1482             return (0);
    1483     return (1);
    1484 }
    1485 
    1486 static void putvlist(REGISTER int f, REGISTER int out)
    1487 {
    1488     REGISTER struct var *vp;
    1489 
    1490     for (vp = vlist; vp; vp = vp->next)
    1491         if (vp->status & f && (isalpha(*vp->name) || *vp->name == '_')) {
    1492             if (vp->status & EXPORT)
    1493                 write(out, "export ", 7);
    1494             if (vp->status & RONLY)
    1495                 write(out, "readonly ", 9);
    1496             write(out, vp->name, (int) (findeq(vp->name) - vp->name));
    1497             write(out, "\n", 1);
    1498         }
    1499 }
    1500 
    1501 static int eqname(REGISTER char *n1, REGISTER char *n2)
    1502 {
    1503     for (; *n1 != '=' && *n1 != 0; n1++)
    1504         if (*n2++ != *n1)
    1505             return (0);
    1506     return (*n2 == 0 || *n2 == '=');
    1507 }
    1508 
    1509 static char *findeq(REGISTER char *cp)
    1510 {
    1511     while (*cp != '\0' && *cp != '=')
    1512         cp++;
    1513     return (cp);
    1514 }
    15151506
    15161507/* -------- gmatch.c -------- */
     
    15241515#define CMASK   0377
    15251516#define QUOTE   0200
    1526 #define QMASK   (CMASK&~QUOTE)
     1517#define QMASK   (CMASK & ~QUOTE)
    15271518#define NOT '!'                 /* might use ^ */
    15281519
    1529 static int gmatch(REGISTER char *s, REGISTER char *p)
    1530 {
    1531     REGISTER int sc, pc;
    1532 
    1533     if (s == NULL || p == NULL)
    1534         return (0);
    1535     while ((pc = *p++ & CMASK) != '\0') {
    1536         sc = *s++ & QMASK;
    1537         switch (pc) {
    1538         case '[':
    1539             if ((p = cclass(p, sc)) == NULL)
    1540                 return (0);
    1541             break;
    1542 
    1543         case '?':
    1544             if (sc == 0)
    1545                 return (0);
    1546             break;
    1547 
    1548         case '*':
    1549             s--;
    1550             do {
    1551                 if (*p == '\0' || gmatch(s, p))
    1552                     return (1);
    1553             } while (*s++ != '\0');
    1554             return (0);
    1555 
    1556         default:
    1557             if (sc != (pc & ~QUOTE))
    1558                 return (0);
    1559         }
    1560     }
    1561     return (*s == 0);
    1562 }
    1563 
    1564 static char *cclass(REGISTER char *p, REGISTER int sub)
    1565 {
    1566     REGISTER int c, d, not, found;
    1567 
    1568     if ((not = *p == NOT) != 0)
     1520static const char *cclass(const char *p, int sub)
     1521{
     1522    int c, d, not, found;
     1523
     1524    not = (*p == NOT);
     1525    if (not != 0)
    15691526        p++;
    15701527    found = not;
    15711528    do {
    15721529        if (*p == '\0')
    1573             return ((char *) NULL);
     1530            return NULL;
    15741531        c = *p & CMASK;
    15751532        if (p[1] == '-' && p[2] != ']') {
     
    15811538            found = !not;
    15821539    } while (*++p != ']');
    1583     return (found ? p + 1 : (char *) NULL);
    1584 }
    1585 
    1586 
    1587 /* -------- area.c -------- */
    1588 
    1589 /*
    1590  * All memory between (char *)areabot and (char *)(areatop+1) is
    1591  * exclusively administered by the area management routines.
    1592  * It is assumed that sbrk() and brk() manipulate the high end.
    1593  */
    1594 
    1595 #define sbrk(X) ({ void * __q = (void *)-1; if (brkaddr + (int)(X) < brktop) { __q = brkaddr; brkaddr+=(int)(X); } __q;})
    1596 
    1597 static void initarea(void)
    1598 {
    1599     brkaddr = xmalloc(AREASIZE);
    1600     brktop = brkaddr + AREASIZE;
    1601 
    1602     while ((long) sbrk(0) & ALIGN)
    1603         sbrk(1);
    1604     areabot = (struct region *) sbrk(REGSIZE);
    1605 
    1606     areabot->next = areabot;
    1607     areabot->area = BUSY;
    1608     areatop = areabot;
    1609     areanxt = areabot;
    1610 }
    1611 
    1612 char *getcell(unsigned nbytes)
    1613 {
    1614     REGISTER int nregio;
    1615     REGISTER struct region *p, *q;
    1616     REGISTER int i;
    1617 
    1618     if (nbytes == 0) {
    1619         puts("getcell(0)");
    1620         abort();
    1621     }
    1622     /* silly and defeats the algorithm */
    1623     /*
    1624      * round upwards and add administration area
    1625      */
    1626     nregio = (nbytes + (REGSIZE - 1)) / REGSIZE + 1;
    1627     for (p = areanxt;;) {
    1628         if (p->area > areanum) {
    1629             /*
    1630              * merge free cells
    1631              */
    1632             while ((q = p->next)->area > areanum && q != areanxt)
    1633                 p->next = q->next;
    1634             /*
    1635              * exit loop if cell big enough
    1636              */
    1637             if (q >= p + nregio)
    1638                 goto found;
    1639         }
    1640         p = p->next;
    1641         if (p == areanxt)
     1540    return found ? p + 1 : NULL;
     1541}
     1542
     1543static int gmatch(const char *s, const char *p)
     1544{
     1545    int sc, pc;
     1546
     1547    if (s == NULL || p == NULL)
     1548        return 0;
     1549
     1550    while ((pc = *p++ & CMASK) != '\0') {
     1551        sc = *s++ & QMASK;
     1552        switch (pc) {
     1553        case '[':
     1554            p = cclass(p, sc);
     1555            if (p == NULL)
     1556                return 0;
    16421557            break;
    1643     }
    1644     i = nregio >= GROWBY ? nregio : GROWBY;
    1645     p = (struct region *) sbrk(i * REGSIZE);
    1646     if (p == (struct region *) -1)
    1647         return ((char *) NULL);
    1648     p--;
    1649     if (p != areatop) {
    1650         puts("not contig");
    1651         abort();                /* allocated areas are contiguous */
    1652     }
    1653     q = p + i;
    1654     p->next = q;
    1655     p->area = FREE;
    1656     q->next = areabot;
    1657     q->area = BUSY;
    1658     areatop = q;
    1659   found:
    1660     /*
    1661      * we found a FREE area big enough, pointed to by 'p', and up to 'q'
    1662      */
    1663     areanxt = p + nregio;
    1664     if (areanxt < q) {
    1665         /*
    1666          * split into requested area and rest
    1667          */
    1668         if (areanxt + 1 > q) {
    1669             puts("OOM");
    1670             abort();            /* insufficient space left for admin */
    1671         }
    1672         areanxt->next = q;
    1673         areanxt->area = FREE;
    1674         p->next = areanxt;
    1675     }
    1676     p->area = areanum;
    1677     return ((char *) (p + 1));
    1678 }
    1679 
    1680 static void freecell(char *cp)
    1681 {
    1682     REGISTER struct region *p;
    1683 
    1684     if ((p = (struct region *) cp) != NULL) {
    1685         p--;
    1686         if (p < areanxt)
    1687             areanxt = p;
    1688         p->area = FREE;
    1689     }
    1690 }
    1691 
    1692 static void freearea(REGISTER int a)
    1693 {
    1694     REGISTER struct region *p, *top;
    1695 
    1696     top = areatop;
    1697     for (p = areabot; p != top; p = p->next)
    1698         if (p->area >= a)
    1699             p->area = FREE;
    1700 }
    1701 
    1702 static void setarea(char *cp, int a)
    1703 {
    1704     REGISTER struct region *p;
    1705 
    1706     if ((p = (struct region *) cp) != NULL)
    1707         (p - 1)->area = a;
    1708 }
    1709 
    1710 int getarea(char *cp)
    1711 {
    1712     return ((struct region *) cp - 1)->area;
    1713 }
    1714 
    1715 static void garbage(void)
    1716 {
    1717     REGISTER struct region *p, *q, *top;
    1718 
    1719     top = areatop;
    1720     for (p = areabot; p != top; p = p->next) {
    1721         if (p->area > areanum) {
    1722             while ((q = p->next)->area > areanum)
    1723                 p->next = q->next;
    1724             areanxt = p;
    1725         }
    1726     }
    1727 #ifdef SHRINKBY
    1728     if (areatop >= q + SHRINKBY && q->area > areanum) {
    1729         brk((char *) (q + 1));
    1730         q->next = areabot;
    1731         q->area = BUSY;
    1732         areatop = q;
    1733     }
    1734 #endif
    1735 }
     1558
     1559        case '?':
     1560            if (sc == 0)
     1561                return 0;
     1562            break;
     1563
     1564        case '*':
     1565            s--;
     1566            do {
     1567                if (*p == '\0' || gmatch(s, p))
     1568                    return 1;
     1569            } while (*s++ != '\0');
     1570            return 0;
     1571
     1572        default:
     1573            if (sc != (pc & ~QUOTE))
     1574                return 0;
     1575        }
     1576    }
     1577    return *s == '\0';
     1578}
     1579
    17361580
    17371581/* -------- csyn.c -------- */
     
    17391583 * shell: syntax (C version)
    17401584 */
     1585
     1586static void yyerror(const char *s) ATTRIBUTE_NORETURN;
     1587static void yyerror(const char *s)
     1588{
     1589    yynerrs++;
     1590    if (interactive && e.iop <= iostack) {
     1591        multiline = 0;
     1592        while (eofc() == 0 && yylex(0) != '\n');
     1593    }
     1594    err(s);
     1595    fail();
     1596}
     1597
     1598static void zzerr(void) ATTRIBUTE_NORETURN;
     1599static void zzerr(void)
     1600{
     1601    yyerror("syntax error");
     1602}
    17411603
    17421604int yyparse(void)
     
    17541616static struct op *pipeline(int cf)
    17551617{
    1756     REGISTER struct op *t, *p;
    1757     REGISTER int c;
     1618    struct op *t, *p;
     1619    int c;
    17581620
    17591621    DBGPRINTF7(("PIPELINE: enter, cf=%d\n", cf));
     
    17651627    if (t != NULL) {
    17661628        while ((c = yylex(0)) == '|') {
    1767             if ((p = command(CONTIN)) == NULL) {
     1629            p = command(CONTIN);
     1630            if (p == NULL) {
    17681631                DBGPRINTF8(("PIPELINE: error!\n"));
    1769                 SYNTAXERR;
     1632                zzerr();
    17701633            }
    17711634
     
    17811644
    17821645    DBGPRINTF7(("PIPELINE: returning t=%p\n", t));
    1783     return (t);
     1646    return t;
    17841647}
    17851648
    17861649static struct op *andor(void)
    17871650{
    1788     REGISTER struct op *t, *p;
    1789     REGISTER int c;
     1651    struct op *t, *p;
     1652    int c;
    17901653
    17911654    DBGPRINTF7(("ANDOR: enter...\n"));
     
    17971660    if (t != NULL) {
    17981661        while ((c = yylex(0)) == LOGAND || c == LOGOR) {
    1799             if ((p = pipeline(CONTIN)) == NULL) {
     1662            p = pipeline(CONTIN);
     1663            if (p == NULL) {
    18001664                DBGPRINTF8(("ANDOR: error!\n"));
    1801                 SYNTAXERR;
     1665                zzerr();
    18021666            }
    18031667
     
    18091673
    18101674    DBGPRINTF7(("ANDOR: returning t=%p\n", t));
    1811     return (t);
     1675    return t;
    18121676}
    18131677
    18141678static struct op *c_list(void)
    18151679{
    1816     REGISTER struct op *t, *p;
    1817     REGISTER int c;
     1680    struct op *t, *p;
     1681    int c;
    18181682
    18191683    DBGPRINTF7(("C_LIST: enter...\n"));
     
    18221686
    18231687    if (t != NULL) {
    1824         if ((peeksym = yylex(0)) == '&')
     1688        peeksym = yylex(0);
     1689        if (peeksym == '&')
    18251690            t = block(TASYNC, t, NOBLOCK, NOWORDS);
    18261691
     
    18281693               || (multiline && c == '\n')) {
    18291694
    1830             if ((p = andor()) == NULL)
    1831                 return (t);
    1832 
    1833             if ((peeksym = yylex(0)) == '&')
     1695            p = andor();
     1696            if (p== NULL)
     1697                return t;
     1698
     1699            peeksym = yylex(0);
     1700            if (peeksym == '&')
    18341701                p = block(TASYNC, p, NOBLOCK, NOWORDS);
    18351702
     
    18411708    /* IF */
    18421709    DBGPRINTF7(("C_LIST: returning t=%p\n", t));
    1843     return (t);
     1710    return t;
    18441711}
    18451712
    18461713static int synio(int cf)
    18471714{
    1848     REGISTER struct ioword *iop;
    1849     REGISTER int i;
    1850     REGISTER int c;
     1715    struct ioword *iop;
     1716    int i;
     1717    int c;
    18511718
    18521719    DBGPRINTF7(("SYNIO: enter, cf=%d\n", cf));
    18531720
    1854     if ((c = yylex(cf)) != '<' && c != '>') {
     1721    c = yylex(cf);
     1722    if (c != '<' && c != '>') {
    18551723        peeksym = c;
    1856         return (0);
     1724        return 0;
    18571725    }
    18581726
     
    18661734
    18671735    DBGPRINTF7(("SYNIO: returning 1\n"));
    1868     return (1);
     1736    return 1;
    18691737}
    18701738
    18711739static void musthave(int c, int cf)
    18721740{
    1873     if ((peeksym = yylex(cf)) != c) {
     1741    peeksym = yylex(cf);
     1742    if (peeksym != c) {
    18741743        DBGPRINTF7(("MUSTHAVE: error!\n"));
    1875         SYNTAXERR;
     1744        zzerr();
    18761745    }
    18771746
     
    18811750static struct op *simple(void)
    18821751{
    1883     REGISTER struct op *t;
     1752    struct op *t;
    18841753
    18851754    t = NULL;
     
    19011770
    19021771        default:
    1903             return (t);
     1772            return t;
    19041773        }
    19051774    }
     
    19081777static struct op *nested(int type, int mark)
    19091778{
    1910     REGISTER struct op *t;
     1779    struct op *t;
    19111780
    19121781    DBGPRINTF3(("NESTED: enter, type=%d, mark=%d\n", type, mark));
     
    19161785    musthave(mark, 0);
    19171786    multiline--;
    1918     return (block(type, t, NOBLOCK, NOWORDS));
     1787    return block(type, t, NOBLOCK, NOWORDS);
    19191788}
    19201789
    19211790static struct op *command(int cf)
    19221791{
    1923     REGISTER struct op *t;
     1792    struct op *t;
    19241793    struct wdblock *iosave;
    1925     REGISTER int c;
     1794    int c;
    19261795
    19271796    DBGPRINTF(("COMMAND: enter, cf=%d\n", cf));
     
    19411810    default:
    19421811        peeksym = c;
    1943         if ((t = simple()) == NULL) {
     1812        t = simple();
     1813        if (t == NULL) {
    19441814            if (iolist == NULL)
    1945                 return ((struct op *) NULL);
     1815                return NULL;
    19461816            t = newtp();
    19471817            t->type = TCOM;
     
    19651835        multiline++;
    19661836        t->words = wordlist();
    1967         if ((c = yylex(0)) != '\n' && c != ';')
     1837        c = yylex(0);
     1838        if (c != '\n' && c != ';')
    19681839            peeksym = c;
    19691840        t->left = dogroup(0);
     
    20291900    DBGPRINTF(("COMMAND: returning %p\n", t));
    20301901
    2031     return (t);
     1902    return t;
    20321903}
    20331904
    20341905static struct op *dowholefile(int type, int mark)
    20351906{
    2036     REGISTER struct op *t;
     1907    struct op *t;
    20371908
    20381909    DBGPRINTF(("DOWHOLEFILE: enter, type=%d, mark=%d\n", type, mark));
     
    20431914    t = block(type, t, NOBLOCK, NOWORDS);
    20441915    DBGPRINTF(("DOWHOLEFILE: return t=%p\n", t));
    2045     return (t);
     1916    return t;
    20461917}
    20471918
    20481919static struct op *dogroup(int onlydone)
    20491920{
    2050     REGISTER int c;
    2051     REGISTER struct op *mylist;
     1921    int c;
     1922    struct op *mylist;
    20521923
    20531924    c = yylex(CONTIN);
    20541925    if (c == DONE && onlydone)
    2055         return ((struct op *) NULL);
     1926        return NULL;
    20561927    if (c != DO)
    2057         SYNTAXERR;
     1928        zzerr();
    20581929    mylist = c_list();
    20591930    musthave(DONE, 0);
    2060     return (mylist);
     1931    return mylist;
    20611932}
    20621933
    20631934static struct op *thenpart(void)
    20641935{
    2065     REGISTER int c;
    2066     REGISTER struct op *t;
    2067 
    2068     if ((c = yylex(0)) != THEN) {
     1936    int c;
     1937    struct op *t;
     1938
     1939    c = yylex(0);
     1940    if (c != THEN) {
    20691941        peeksym = c;
    2070         return ((struct op *) NULL);
     1942        return NULL;
    20711943    }
    20721944    t = newtp();
     
    20741946    t->left = c_list();
    20751947    if (t->left == NULL)
    2076         SYNTAXERR;
     1948        zzerr();
    20771949    t->right = elsepart();
    2078     return (t);
     1950    return t;
    20791951}
    20801952
    20811953static struct op *elsepart(void)
    20821954{
    2083     REGISTER int c;
    2084     REGISTER struct op *t;
     1955    int c;
     1956    struct op *t;
    20851957
    20861958    switch (c = yylex(0)) {
    20871959    case ELSE:
    2088         if ((t = c_list()) == NULL)
    2089             SYNTAXERR;
    2090         return (t);
     1960        t = c_list();
     1961        if (t == NULL)
     1962            zzerr();
     1963        return t;
    20911964
    20921965    case ELIF:
     
    20951968        t->left = c_list();
    20961969        t->right = thenpart();
    2097         return (t);
     1970        return t;
    20981971
    20991972    default:
    21001973        peeksym = c;
    2101         return ((struct op *) NULL);
     1974        return NULL;
    21021975    }
    21031976}
     
    21051978static struct op *caselist(void)
    21061979{
    2107     REGISTER struct op *t;
     1980    struct op *t;
    21081981
    21091982    t = NULL;
     
    21141987
    21151988    DBGPRINTF(("CASELIST, returning t=%p\n", t));
    2116     return (t);
     1989    return t;
    21171990}
    21181991
    21191992static struct op *casepart(void)
    21201993{
    2121     REGISTER struct op *t;
     1994    struct op *t;
    21221995
    21231996    DBGPRINTF7(("CASEPART: enter...\n"));
     
    21282001    musthave(')', 0);
    21292002    t->left = c_list();
    2130     if ((peeksym = yylex(CONTIN)) != ESAC)
     2003    peeksym = yylex(CONTIN);
     2004    if (peeksym != ESAC)
    21312005        musthave(BREAK, CONTIN);
    21322006
    21332007    DBGPRINTF7(("CASEPART: made newtp(TPAT, t=%p)\n", t));
    21342008
    2135     return (t);
     2009    return t;
    21362010}
    21372011
    21382012static char **pattern(void)
    21392013{
    2140     REGISTER int c, cf;
     2014    int c, cf;
    21412015
    21422016    cf = CONTIN;
     
    21452019        word(yylval.cp);
    21462020        cf = 0;
    2147     } while ((c = yylex(0)) == '|');
     2021        c = yylex(0);
     2022    } while (c == '|');
    21482023    peeksym = c;
    21492024    word(NOWORD);
    21502025
    2151     return (copyw());
     2026    return copyw();
    21522027}
    21532028
    21542029static char **wordlist(void)
    21552030{
    2156     REGISTER int c;
    2157 
    2158     if ((c = yylex(0)) != IN) {
     2031    int c;
     2032
     2033    c = yylex(0);
     2034    if (c != IN) {
    21592035        peeksym = c;
    2160         return ((char **) NULL);
     2036        return NULL;
    21612037    }
    21622038    startl = 0;
     
    21652041    word(NOWORD);
    21662042    peeksym = c;
    2167     return (copyw());
     2043    return copyw();
    21682044}
    21692045
     
    21712047 * supporting functions
    21722048 */
    2173 static struct op *list(REGISTER struct op *t1, REGISTER struct op *t2)
     2049static struct op *list(struct op *t1, struct op *t2)
    21742050{
    21752051    DBGPRINTF7(("LIST: enter, t1=%p, t2=%p\n", t1, t2));
    21762052
    21772053    if (t1 == NULL)
    2178         return (t2);
     2054        return t2;
    21792055    if (t2 == NULL)
    2180         return (t1);
    2181 
    2182     return (block(TLIST, t1, t2, NOWORDS));
     2056        return t1;
     2057
     2058    return block(TLIST, t1, t2, NOWORDS);
    21832059}
    21842060
    21852061static struct op *block(int type, struct op *t1, struct op *t2, char **wp)
    21862062{
    2187     REGISTER struct op *t;
     2063    struct op *t;
    21882064
    21892065    DBGPRINTF7(("BLOCK: enter, type=%d (%s)\n", type, T_CMD_NAMES[type]));
     
    21982074                t2));
    21992075
    2200     return (t);
     2076    return t;
    22012077}
    22022078
    22032079/* See if given string is a shell multiline (FOR, IF, etc) */
    2204 static int rlookup(REGISTER char *n)
    2205 {
    2206     REGISTER const struct res *rp;
     2080static int rlookup(char *n)
     2081{
     2082    const struct res *rp;
    22072083
    22082084    DBGPRINTF7(("RLOOKUP: enter, n is %s\n", n));
     
    22112087        if (strcmp(rp->r_name, n) == 0) {
    22122088            DBGPRINTF7(("RLOOKUP: match, returning %d\n", rp->r_val));
    2213             return (rp->r_val); /* Return numeric code for shell multiline */
     2089            return rp->r_val;   /* Return numeric code for shell multiline */
    22142090        }
    22152091
    22162092    DBGPRINTF7(("RLOOKUP: NO match, returning 0\n"));
    2217     return (0);                 /* Not a shell multiline */
     2093    return 0;                   /* Not a shell multiline */
    22182094}
    22192095
    22202096static struct op *newtp(void)
    22212097{
    2222     REGISTER struct op *t;
     2098    struct op *t;
    22232099
    22242100    t = (struct op *) tree(sizeof(*t));
     
    22322108    DBGPRINTF3(("NEWTP: allocated %p\n", t));
    22332109
    2234     return (t);
    2235 }
    2236 
    2237 static struct op *namelist(REGISTER struct op *t)
    2238 {
    2239 
     2110    return t;
     2111}
     2112
     2113static struct op *namelist(struct op *t)
     2114{
    22402115    DBGPRINTF7(("NAMELIST: enter, t=%p, type %s, iolist=%p\n", t,
    22412116                T_CMD_NAMES[t->type], iolist));
     
    22532128            t->left->ioact = NULL;
    22542129        }
    2255         return (t);
     2130        return t;
    22562131    }
    22572132
     
    22592134    t->words = copyw();
    22602135
    2261 
    2262     return (t);
     2136    return t;
    22632137}
    22642138
    22652139static char **copyw(void)
    22662140{
    2267     REGISTER char **wd;
     2141    char **wd;
    22682142
    22692143    wd = getwords(wdlist);
    22702144    wdlist = 0;
    2271     return (wd);
     2145    return wd;
    22722146}
    22732147
     
    22792153static struct ioword **copyio(void)
    22802154{
    2281     REGISTER struct ioword **iop;
     2155    struct ioword **iop;
    22822156
    22832157    iop = (struct ioword **) getwords(iolist);
    22842158    iolist = 0;
    2285     return (iop);
     2159    return iop;
    22862160}
    22872161
    22882162static struct ioword *io(int u, int f, char *cp)
    22892163{
    2290     REGISTER struct ioword *iop;
     2164    struct ioword *iop;
    22912165
    22922166    iop = (struct ioword *) tree(sizeof(*iop));
     
    22952169    iop->io_name = cp;
    22962170    iolist = addword((char *) iop, iolist);
    2297     return (iop);
    2298 }
    2299 
    2300 static void zzerr(void)
    2301 {
    2302     yyerror("syntax error");
    2303 }
    2304 
    2305 static void yyerror(char *s)
    2306 {
    2307     yynerrs++;
    2308     if (interactive && e.iop <= iostack) {
    2309         multiline = 0;
    2310         while (eofc() == 0 && yylex(0) != '\n');
    2311     }
    2312     err(s);
    2313     fail();
     2171    return iop;
    23142172}
    23152173
    23162174static int yylex(int cf)
    23172175{
    2318     REGISTER int c, c1;
     2176    int c, c1;
    23192177    int atstart;
    23202178
    2321     if ((c = peeksym) > 0) {
     2179    c = peeksym;
     2180    if (c > 0) {
    23222181        peeksym = 0;
    23232182        if (c == '\n')
    23242183            startl = 1;
    2325         return (c);
    2326     }
    2327 
     2184        return c;
     2185    }
    23282186
    23292187    nlseen = 0;
     
    23362194    line[LINELIM - 1] = '\0';
    23372195
    2338   loop:
     2196 loop:
    23392197    while ((c = my_getc(0)) == ' ' || c == '\t')    /* Skip whitespace */
    23402198        ;
     
    23432201    default:
    23442202        if (any(c, "0123456789")) {
    2345             unget(c1 = my_getc(0));
     2203            c1 = my_getc(0);
     2204            unget(c1);
    23462205            if (c1 == '<' || c1 == '>') {
    23472206                iounit = c - '0';
     
    23542213
    23552214    case '#':                   /* Comment, skip to next newline or End-of-string */
    2356         while ((c = my_getc(0)) != 0 && c != '\n');
     2215        while ((c = my_getc(0)) != '\0' && c != '\n');
    23572216        unget(c);
    23582217        goto loop;
     
    23602219    case 0:
    23612220        DBGPRINTF5(("YYLEX: return 0, c=%d\n", c));
    2362         return (c);
     2221        return c;
    23632222
    23642223    case '$':
    23652224        DBGPRINTF9(("YYLEX: found $\n"));
    23662225        *e.linep++ = c;
    2367         if ((c = my_getc(0)) == '{') {
    2368             if ((c = collect(c, '}')) != '\0')
    2369                 return (c);
     2226        c = my_getc(0);
     2227        if (c == '{') {
     2228            c = collect(c, '}');
     2229            if (c != '\0')
     2230                return c;
    23702231            goto pack;
    23712232        }
     
    23752236    case '\'':
    23762237    case '"':
    2377         if ((c = collect(c, c)) != '\0')
    2378             return (c);
     2238        c = collect(c, c);
     2239        if (c != '\0')
     2240            return c;
    23792241        goto pack;
    23802242
     
    23842246        startl = 1;
    23852247        /* If more chars process them, else return NULL char */
    2386         if ((c1 = dual(c)) != '\0')
    2387             return (c1);
    2388         else
    2389             return (c);
     2248        c1 = dual(c);
     2249        if (c1 != '\0')
     2250            return c1;
     2251        return c;
    23902252
    23912253    case '^':
    23922254        startl = 1;
    2393         return ('|');
     2255        return '|';
    23942256    case '>':
    23952257    case '<':
    23962258        diag(c);
    2397         return (c);
     2259        return c;
    23982260
    23992261    case '\n':
     
    24032265        if (multiline || cf & CONTIN) {
    24042266            if (interactive && e.iop <= iostack) {
    2405 #ifdef CONFIG_FEATURE_COMMAND_EDITING
     2267#if ENABLE_FEATURE_EDITING
    24062268                current_prompt = cprompt->value;
    24072269#else
     
    24122274                goto loop;
    24132275        }
    2414         return (c);
     2276        return c;
    24152277
    24162278    case '(':
    24172279    case ')':
    24182280        startl = 1;
    2419         return (c);
     2281        return c;
    24202282    }
    24212283
    24222284    unget(c);
    24232285
    2424   pack:
    2425     while ((c = my_getc(0)) != 0 && !any(c, "`$ '\"\t;&<>()|^\n")) {
     2286 pack:
     2287    while ((c = my_getc(0)) != '\0' && !any(c, "`$ '\"\t;&<>()|^\n")) {
    24262288        if (e.linep >= elinep)
    24272289            err("word too long");
     
    24372299    *e.linep++ = '\0';
    24382300
    2439     if (atstart && (c = rlookup(line)) != 0) {
    2440         startl = 1;
    2441         return (c);
     2301    if (atstart) {
     2302        c = rlookup(line);
     2303        if (c != 0) {
     2304            startl = 1;
     2305            return c;
     2306        }
    24422307    }
    24432308
    24442309    yylval.cp = strsave(line, areanum);
    2445     return (WORD);
    2446 }
    2447 
    2448 
    2449 static int collect(REGISTER int c, REGISTER int c1)
     2310    return WORD;
     2311}
     2312
     2313
     2314static int collect(int c, int c1)
    24502315{
    24512316    char s[2];
     
    24612326            prs("no closing ");
    24622327            yyerror(s);
    2463             return (YYERRCODE);
     2328            return YYERRCODE;
    24642329        }
    24652330        if (interactive && c == '\n' && e.iop <= iostack) {
    2466 #ifdef CONFIG_FEATURE_COMMAND_EDITING
     2331#if ENABLE_FEATURE_EDITING
    24672332            current_prompt = cprompt->value;
    24682333#else
     
    24772342    DBGPRINTF8(("COLLECT: return 0, line is %s\n", line));
    24782343
    2479     return (0);
     2344    return 0;
    24802345}
    24812346
    24822347/* "multiline commands" helper func */
    24832348/* see if next 2 chars form a shell multiline */
    2484 static int dual(REGISTER int c)
     2349static int dual(int c)
    24852350{
    24862351    char s[3];
    2487     REGISTER char *cp = s;
     2352    char *cp = s;
    24882353
    24892354    DBGPRINTF8(("DUAL: enter, c=%d\n", c));
    24902355
    2491     *cp++ = c;                  /* c is the given "peek" char */
    2492     *cp++ = my_getc(0);         /* get next char of input */
    2493     *cp = 0;                    /* add EOS marker */
    2494 
    2495     c = rlookup(s);             /* see if 2 chars form a shell multiline */
     2356    *cp++ = c;              /* c is the given "peek" char */
     2357    *cp++ = my_getc(0);     /* get next char of input */
     2358    *cp = '\0';             /* add EOS marker */
     2359
     2360    c = rlookup(s);         /* see if 2 chars form a shell multiline */
    24962361    if (c == 0)
    2497         unget(*--cp);           /* String is not a shell multiline, put peek char back */
    2498 
    2499     return (c);                 /* String is multiline, return numeric multiline (restab) code */
    2500 }
    2501 
    2502 static void diag(REGISTER int ec)
    2503 {
    2504     REGISTER int c;
     2362        unget(*--cp);   /* String is not a shell multiline, put peek char back */
     2363
     2364    return c;               /* String is multiline, return numeric multiline (restab) code */
     2365}
     2366
     2367static void diag(int ec)
     2368{
     2369    int c;
    25052370
    25062371    DBGPRINTF8(("DIAG: enter, ec=%d\n", ec));
     
    25102375        if (c != ec)
    25112376            zzerr();
    2512         yylval.i = ec == '>' ? IOWRITE | IOCAT : IOHERE;
     2377        yylval.i = (ec == '>' ? IOWRITE | IOCAT : IOHERE);
    25132378        c = my_getc(0);
    25142379    } else
    2515         yylval.i = ec == '>' ? IOWRITE : IOREAD;
     2380        yylval.i = (ec == '>' ? IOWRITE : IOREAD);
    25162381    if (c != '&' || yylval.i == IOHERE)
    25172382        unget(c);
     
    25222387static char *tree(unsigned size)
    25232388{
    2524     REGISTER char *t;
    2525 
    2526     if ((t = getcell(size)) == NULL) {
     2389    char *t;
     2390
     2391    t = getcell(size);
     2392    if (t == NULL) {
    25272393        DBGPRINTF2(("TREE: getcell(%d) failed!\n", size));
    25282394        prs("command line too complicated\n");
     
    25302396        /* NOTREACHED */
    25312397    }
    2532     return (t);
    2533 }
     2398    return t;
     2399}
     2400
    25342401
    25352402/* VARARGS1 */
     
    25382405/* -------- exec.c -------- */
    25392406
     2407static struct op **find1case(struct op *t, const char *w)
     2408{
     2409    struct op *t1;
     2410    struct op **tp;
     2411    char **wp;
     2412    char *cp;
     2413
     2414    if (t == NULL) {
     2415        DBGPRINTF3(("FIND1CASE: enter, t==NULL, returning.\n"));
     2416        return NULL;
     2417    }
     2418
     2419    DBGPRINTF3(("FIND1CASE: enter, t->type=%d (%s)\n", t->type,
     2420                T_CMD_NAMES[t->type]));
     2421
     2422    if (t->type == TLIST) {
     2423        tp = find1case(t->left, w);
     2424        if (tp != NULL) {
     2425            DBGPRINTF3(("FIND1CASE: found one to the left, returning tp=%p\n", tp));
     2426            return tp;
     2427        }
     2428        t1 = t->right;          /* TPAT */
     2429    } else
     2430        t1 = t;
     2431
     2432    for (wp = t1->words; *wp;) {
     2433        cp = evalstr(*wp++, DOSUB);
     2434        if (cp && gmatch(w, cp)) {
     2435            DBGPRINTF3(("FIND1CASE: returning &t1->left= %p.\n",
     2436                        &t1->left));
     2437            return &t1->left;
     2438        }
     2439    }
     2440
     2441    DBGPRINTF(("FIND1CASE: returning NULL\n"));
     2442    return NULL;
     2443}
     2444
     2445static struct op *findcase(struct op *t, const char *w)
     2446{
     2447    struct op **tp;
     2448
     2449    tp = find1case(t, w);
     2450    return tp != NULL ? *tp : NULL;
     2451}
     2452
    25402453/*
    25412454 * execute tree
    25422455 */
    25432456
    2544 
    2545 static int execute(REGISTER struct op *t, int *pin, int *pout, int act)
    2546 {
    2547     REGISTER struct op *t1;
     2457static int execute(struct op *t, int *pin, int *pout, int act)
     2458{
     2459    struct op *t1;
    25482460    volatile int i, rv, a;
    2549     char *cp, **wp, **wp2;
     2461    const char *cp;
     2462    char **wp, **wp2;
    25502463    struct var *vp;
    25512464    struct op *outtree_save;
     
    25592472    if (t == NULL) {
    25602473        DBGPRINTF4(("EXECUTE: enter, t==null, returning.\n"));
    2561         return (0);
     2474        return 0;
    25622475    }
    25632476
     
    25722485        : NULL;
    25732486
    2574 /* Hard to know how many words there are, be careful of garbage pointer values */
    2575 /* They are likely to cause "PCI bus fault" errors */
    2576 #if 0
    2577     DBGPRINTF(("EXECUTE: t->left=%p, t->right=%p, t->words[1] is %s\n",
    2578                t->left, t->right,
    2579                ((t->words[1] == NULL) ? "NULL" : t->words[1])));
    2580     DBGPRINTF7(("EXECUTE: t->words[2] is %s, t->words[3] is %s\n",
    2581                 ((t->words[2] == NULL) ? "NULL" : t->words[2]),
    2582                 ((t->words[3] == NULL) ? "NULL" : t->words[3])));
    2583 #endif
    2584 
    2585 
    25862487    switch (t->type) {
    25872488    case TDOT:
     
    26082509
    26092510    case TCOM:
    2610         {
    2611             rv = forkexec(t, pin, pout, act, wp);
    2612         }
     2511        rv = forkexec(t, pin, pout, act, wp);
    26132512        break;
    26142513
     
    26172516            int pv[2];
    26182517
    2619             if ((rv = openpipe(pv)) < 0)
     2518            rv = openpipe(pv);
     2519            if (rv < 0)
    26202520                break;
    26212521            pv[0] = remap(pv[0]);
     
    26382538
    26392539            i = vfork();
    2640             if (i != 0) {
    2641                 interactive = hinteractive;
    2642                 if (i != -1) {
    2643                     setval(lookup("!"), putn(i));
    2644                     if (pin != NULL)
    2645                         closepipe(pin);
    2646                     if (interactive) {
    2647                         prs(putn(i));
    2648                         prs("\n");
    2649                     }
    2650                 } else
    2651                     rv = -1;
    2652                 setstatus(rv);
    2653             } else {
     2540            if (i == 0) { /* child */
    26542541                signal(SIGINT, SIG_IGN);
    26552542                signal(SIGQUIT, SIG_IGN);
     
    26592546                if (pin == NULL) {
    26602547                    close(0);
    2661                     open(bb_dev_null, 0);
     2548                    xopen(bb_dev_null, O_RDONLY);
    26622549                }
    26632550                _exit(execute(t->left, pin, pout, FEXEC));
    26642551            }
     2552            interactive = hinteractive;
     2553            if (i != -1) {
     2554                setval(lookup("!"), putn(i));
     2555                if (pin != NULL)
     2556                    closepipe(pin);
     2557                if (interactive) {
     2558                    prs(putn(i));
     2559                    prs("\n");
     2560                }
     2561            } else
     2562                rv = -1;
     2563            setstatus(rv);
    26652564        }
    26662565        break;
     
    26692568    case TAND:
    26702569        rv = execute(t->left, pin, pout, 0);
    2671         if ((t1 = t->right) != NULL && (rv == 0) == (t->type == TAND))
     2570        t1 = t->right;
     2571        if (t1 != NULL && (rv == 0) == (t->type == TAND))
    26722572            rv = execute(t1, pin, pout, 0);
    26732573        break;
     
    26762576        if (wp == NULL) {
    26772577            wp = dolv + 1;
    2678             if ((i = dolc) < 0)
     2578            i = dolc;
     2579            if (i < 0)
    26792580                i = 0;
    26802581        } else {
     
    27162617
    27172618    case TCASE:
    2718         if ((cp = evalstr(t->str, DOSUB | DOTRIM)) == 0)
     2619        cp = evalstr(t->str, DOSUB | DOTRIM);
     2620        if (cp == NULL)
    27192621            cp = "";
    27202622
     
    27232625                    ((cp == NULL) ? "NULL" : cp)));
    27242626
    2725         if ((t1 = findcase(t->left, cp)) != NULL) {
     2627        t1 = findcase(t->left, cp);
     2628        if (t1 != NULL) {
    27262629            DBGPRINTF7(("EXECUTE: TCASE, calling execute(t=%p, t1=%p)...\n", t, t1));
    27272630            rv = execute(t1, pin, pout, 0);
     
    27322635    case TBRACE:
    27332636/*
    2734         if (iopp = t->ioact)
     2637        iopp = t->ioact;
     2638        if (i)
    27352639            while (*iopp)
    27362640                if (iosetup(*iopp++, pin!=NULL, pout!=NULL)) {
     
    27392643                }
    27402644*/
    2741         if (rv >= 0 && (t1 = t->left))
    2742             rv = execute(t1, pin, pout, 0);
     2645        if (rv >= 0) {
     2646            t1 = t->left;
     2647            if (t1) {
     2648                rv = execute(t1, pin, pout, 0);
     2649            }
     2650        }
    27432651        break;
    27442652
    27452653    };
    27462654
    2747   broken:
     2655 broken:
    27482656    t->words = wp2;
    27492657    isbreak = 0;
     
    27562664    }
    27572665
    2758     if ((i = trapset) != 0) {
     2666    i = trapset;
     2667    if (i != 0) {
    27592668        trapset = 0;
    27602669        runtrap(i);
     
    27622671
    27632672    DBGPRINTF(("EXECUTE: returning from t=%p, rv=%d\n", t, rv));
    2764     return (rv);
    2765 }
    2766 
    2767 static int
    2768 forkexec(REGISTER struct op *t, int *pin, int *pout, int act, char **wp)
     2673    return rv;
     2674}
     2675
     2676typedef int (*builtin_func_ptr)(struct op *);
     2677
     2678static builtin_func_ptr inbuilt(const char *s)
     2679{
     2680    const struct builtincmd *bp;
     2681
     2682    for (bp = builtincmds; bp->name; bp++)
     2683        if (strcmp(bp->name, s) == 0)
     2684            return bp->builtinfunc;
     2685    return NULL;
     2686}
     2687
     2688static int forkexec(struct op *t, int *pin, int *pout, int act, char **wp)
    27692689{
    27702690    pid_t newpid;
    27712691    int i, rv;
    2772     int (*shcom) (struct op *) = NULL;
    2773     REGISTER int f;
    2774     char *cp = NULL;
     2692    builtin_func_ptr shcom = NULL;
     2693    int f;
     2694    const char *cp = NULL;
    27752695    struct ioword **iopp;
    27762696    int resetsig;
     
    28022722                ((t->words == NULL) ? "NULL" : t->words[0])));
    28032723
    2804 /* Hard to know how many words there are, be careful of garbage pointer values */
    2805 /* They are likely to cause "PCI bus fault" errors */
    2806 #if 0
    2807     DBGPRINTF7(("FORKEXEC: t->words is %s, t->words[1] is %s\n",
    2808                 ((t->words == NULL) ? "NULL" : t->words[0]),
    2809                 ((t->words == NULL) ? "NULL" : t->words[1])));
    2810     DBGPRINTF7(("FORKEXEC: wp is %s, wp[1] is %s\n",
    2811                 ((wp == NULL) ? "NULL" : wp[0]),
    2812                 ((wp[1] == NULL) ? "NULL" : wp[1])));
    2813     DBGPRINTF7(("FORKEXEC: wp2 is %s, wp[3] is %s\n",
    2814                 ((wp[2] == NULL) ? "NULL" : wp[2]),
    2815                 ((wp[3] == NULL) ? "NULL" : wp[3])));
    2816 #endif
    2817 
    2818 
    28192724    owp = wp;
    28202725    resetsig = 0;
    28212726    rv = -1;                    /* system-detected error */
    28222727    if (t->type == TCOM) {
    2823         while ((cp = *wp++) != NULL);
     2728        while (*wp++ != NULL)
     2729            continue;
    28242730        cp = *wp;
    28252731
    28262732        /* strip all initial assignments */
    28272733        /* not correct wrt PATH=yyy command  etc */
    2828         if (flag['x']) {
     2734        if (FLAG['x']) {
    28292735            DBGPRINTF9(("FORKEXEC: echo'ing, cp=%p, wp=%p, owp=%p\n",
    28302736                        cp, wp, owp));
    28312737            echo(cp ? wp : owp);
    28322738        }
    2833 #if 0
    2834         DBGPRINTF9(("FORKEXEC: t->words is %s, t->words[1] is %s\n",
    2835                     ((t->words == NULL) ? "NULL" : t->words[0]),
    2836                     ((t->words == NULL) ? "NULL" : t->words[1])));
    2837         DBGPRINTF9(("FORKEXEC: wp is %s, wp[1] is %s\n",
    2838                     ((wp == NULL) ? "NULL" : wp[0]),
    2839                     ((wp == NULL) ? "NULL" : wp[1])));
    2840 #endif
    28412739
    28422740        if (cp == NULL && t->ioact == NULL) {
    2843             while ((cp = *owp++) != NULL && assign(cp, COPYV));
     2741            while ((cp = *owp++) != NULL && assign(cp, COPYV))
     2742                continue;
    28442743            DBGPRINTF(("FORKEXEC: returning setstatus()\n"));
    2845             return (setstatus(0));
    2846         } else if (cp != NULL) {
     2744            return setstatus(0);
     2745        }
     2746        if (cp != NULL) {
    28472747            shcom = inbuilt(cp);
    28482748        }
     
    28522752    f = act;
    28532753
    2854 #if 0
    2855     DBGPRINTF3(("FORKEXEC: t->words is %s, t->words[1] is %s\n",
    2856                 ((t->words == NULL) ? "NULL" : t->words[0]),
    2857                 ((t->words == NULL) ? "NULL" : t->words[1])));
    2858 #endif
    28592754    DBGPRINTF(("FORKEXEC: shcom %p, f&FEXEC 0x%x, owp %p\n", shcom,
    28602755               f & FEXEC, owp));
     
    28752770
    28762771        if (newpid == -1) {
    2877             DBGPRINTF(("FORKEXEC: ERROR, unable to vfork()!\n"));
    2878             return (-1);
    2879         }
    2880 
    2881 
    2882         if (newpid > 0) {       /* Parent */
    2883 
     2772            DBGPRINTF(("FORKEXEC: ERROR, cannot vfork()!\n"));
     2773            return -1;
     2774        }
     2775
     2776        if (newpid > 0) {  /* Parent */
    28842777            /* Restore values */
    28852778            pin = hpin;
     
    28902783            brklist = hbrklist;
    28912784            execflg = hexecflg;
    2892 
    28932785/* moved up
    28942786            if (i == -1)
    2895                 return(rv);
     2787                return rv;
    28962788*/
    2897 
    28982789            if (pin != NULL)
    28992790                closepipe(pin);
     
    29172808    }
    29182809
    2919 
    29202810    if (owp != NULL)
    29212811        while ((cp = *owp++) != NULL && assign(cp, COPYV))
     
    29282818        if (forked)
    29292819            _exit(-1);
    2930         return (-1);
     2820        return -1;
    29312821    }
    29322822#endif
    29332823
    29342824    if (pin != NULL) {
    2935         dup2(pin[0], 0);
    2936         closepipe(pin);
     2825        xmove_fd(pin[0], 0);
     2826        if (pin[1] != 0) close(pin[1]);
    29372827    }
    29382828    if (pout != NULL) {
    2939         dup2(pout[1], 1);
    2940         closepipe(pout);
    2941     }
    2942 
    2943     if ((iopp = t->ioact) != NULL) {
     2829        xmove_fd(pout[1], 1);
     2830        if (pout[1] != 1) close(pout[0]);
     2831    }
     2832
     2833    iopp = t->ioact;
     2834    if (iopp != NULL) {
    29442835        if (shcom != NULL && shcom != doexec) {
    29452836            prs(cp);
     
    29472838            if (forked)
    29482839                _exit(-1);
    2949             return (-1);
     2840            return -1;
    29502841        }
    29512842        while (*iopp)
     
    29532844                if (forked)
    29542845                    _exit(rv);
    2955                 return (rv);
     2846                return rv;
    29562847            }
    29572848    }
     
    29622853            _exit(i);
    29632854        DBGPRINTF(("FORKEXEC: returning i=%d\n", i));
    2964         return (i);
     2855        return i;
    29652856    }
    29662857
     
    29962887 * within pipelines.
    29972888 */
    2998 static int iosetup(REGISTER struct ioword *iop, int pipein, int pipeout)
    2999 {
    3000     REGISTER int u = -1;
    3001     char *cp = NULL, *msg;
     2889static int iosetup(struct ioword *iop, int pipein, int pipeout)
     2890{
     2891    int u = -1;
     2892    char *cp = NULL;
     2893    const char *msg;
    30022894
    30032895    DBGPRINTF(("IOSETUP: iop %p, pipein %i, pipeout %i\n", iop,
     
    30082900
    30092901    if (pipein && iop->io_unit == 0)
    3010         return (0);
     2902        return 0;
    30112903
    30122904    if (pipeout && iop->io_unit == 1)
    3013         return (0);
     2905        return 0;
    30142906
    30152907    msg = iop->io_flag & (IOREAD | IOHERE) ? "open" : "create";
    30162908    if ((iop->io_flag & IOHERE) == 0) {
    3017         cp = iop->io_name;
    3018         if ((cp = evalstr(cp, DOSUB | DOTRIM)) == NULL)
    3019             return (1);
     2909        cp = iop->io_name; /* huh?? */
     2910        cp = evalstr(cp, DOSUB | DOTRIM);
     2911        if (cp == NULL)
     2912            return 1;
    30202913    }
    30212914
     
    30242917            prs(cp);
    30252918            err(": illegal >& argument");
    3026             return (1);
     2919            return 1;
    30272920        }
    30282921        if (*cp == '-')
     
    30322925    switch (iop->io_flag) {
    30332926    case IOREAD:
    3034         u = open(cp, 0);
     2927        u = open(cp, O_RDONLY);
    30352928        break;
    30362929
     
    30382931    case IOHERE | IOXHERE:
    30392932        u = herein(iop->io_name, iop->io_flag & IOXHERE);
    3040         cp = "here file";
     2933        cp = (char*)"here file";
    30412934        break;
    30422935
    30432936    case IOWRITE | IOCAT:
    3044         if ((u = open(cp, 1)) >= 0) {
    3045             lseek(u, (long) 0, 2);
     2937        u = open(cp, O_WRONLY);
     2938        if (u >= 0) {
     2939            lseek(u, (long) 0, SEEK_END);
    30462940            break;
    30472941        }
     
    30562950    case IOCLOSE:
    30572951        close(iop->io_unit);
    3058         return (0);
     2952        return 0;
    30592953    }
    30602954    if (u < 0) {
     
    30622956        prs(": cannot ");
    30632957        warn(msg);
    3064         return (1);
    3065     } else {
    3066         if (u != iop->io_unit) {
    3067             dup2(u, iop->io_unit);
    3068             close(u);
    3069         }
    3070     }
    3071     return (0);
    3072 }
    3073 
    3074 static void echo(REGISTER char **wp)
    3075 {
    3076     REGISTER int i;
    3077 
    3078     prs("+");
    3079     for (i = 0; wp[i]; i++) {
    3080         if (i)
    3081             prs(" ");
    3082         prs(wp[i]);
    3083     }
    3084     prs("\n");
    3085 }
    3086 
    3087 static struct op **find1case(struct op *t, char *w)
    3088 {
    3089     REGISTER struct op *t1;
    3090     struct op **tp;
    3091     REGISTER char **wp, *cp;
    3092 
    3093 
    3094     if (t == NULL) {
    3095         DBGPRINTF3(("FIND1CASE: enter, t==NULL, returning.\n"));
    3096         return ((struct op **) NULL);
    3097     }
    3098 
    3099     DBGPRINTF3(("FIND1CASE: enter, t->type=%d (%s)\n", t->type,
    3100                 T_CMD_NAMES[t->type]));
    3101 
    3102     if (t->type == TLIST) {
    3103         if ((tp = find1case(t->left, w)) != NULL) {
    3104             DBGPRINTF3(("FIND1CASE: found one to the left, returning tp=%p\n", tp));
    3105             return (tp);
    3106         }
    3107         t1 = t->right;          /* TPAT */
    3108     } else
    3109         t1 = t;
    3110 
    3111     for (wp = t1->words; *wp;)
    3112         if ((cp = evalstr(*wp++, DOSUB)) && gmatch(w, cp)) {
    3113             DBGPRINTF3(("FIND1CASE: returning &t1->left= %p.\n",
    3114                         &t1->left));
    3115             return (&t1->left);
    3116         }
    3117 
    3118     DBGPRINTF(("FIND1CASE: returning NULL\n"));
    3119     return ((struct op **) NULL);
    3120 }
    3121 
    3122 static struct op *findcase(struct op *t, char *w)
    3123 {
    3124     REGISTER struct op **tp;
    3125 
    3126     return ((tp = find1case(t, w)) != NULL ? *tp : (struct op *) NULL);
     2958        return 1;
     2959    }
     2960    if (u != iop->io_unit) {
     2961        dup2(u, iop->io_unit);
     2962        close(u);
     2963    }
     2964    return 0;
    31272965}
    31282966
     
    31432981 * unless `canintr' is true.
    31442982 */
    3145 static int waitfor(REGISTER int lastpid, int canintr)
    3146 {
    3147     REGISTER int pid, rv;
     2983static int waitfor(int lastpid, int canintr)
     2984{
     2985    int pid, rv;
    31482986    int s;
    31492987    int oheedint = heedint;
     
    31572995                break;
    31582996        } else {
    3159             if ((rv = WAITSIG(s)) != 0) {
    3160                 if (rv < NSIGNAL) {
     2997            rv = WAITSIG(s);
     2998            if (rv != 0) {
     2999                if (rv < ARRAY_SIZE(signame)) {
    31613000                    if (signame[rv] != NULL) {
    31623001                        if (pid != lastpid) {
     
    31773016                if (WAITCORE(s))
    31783017                    prs(" - core dumped");
    3179                 if (rv >= NSIGNAL || signame[rv])
     3018                if (rv >= ARRAY_SIZE(signame) || signame[rv])
    31803019                    prs("\n");
    31813020                rv = -1;
     
    31953034        }
    31963035    }
    3197     return (rv);
    3198 }
    3199 
    3200 static int setstatus(REGISTER int s)
     3036    return rv;
     3037}
     3038
     3039static int setstatus(int s)
    32013040{
    32023041    exstat = s;
    32033042    setval(lookup("?"), putn(s));
    3204     return (s);
     3043    return s;
    32053044}
    32063045
     
    32103049 * execvp might be used.
    32113050 */
    3212 static char *rexecve(char *c, char **v, char **envp)
    3213 {
    3214     REGISTER int i;
    3215     REGISTER char *sp, *tp;
     3051static const char *rexecve(char *c, char **v, char **envp)
     3052{
     3053    int i;
     3054    const char *sp;
     3055    char *tp;
    32163056    int eacces = 0, asis = 0;
    32173057    char *name = c;
    32183058
    3219     if (ENABLE_FEATURE_SH_STANDALONE_SHELL) {
    3220         optind = 1;
     3059    if (ENABLE_FEATURE_SH_STANDALONE) {
    32213060        if (find_applet_by_name(name)) {
    32223061            /* We have to exec here since we vforked.  Running
    3223              * run_applet_by_name() won't work and bad things
     3062             * run_applet_and_exit() won't work and bad things
    32243063             * will happen. */
    3225             execve(CONFIG_BUSYBOX_EXEC_PATH, v, envp);
     3064            execve(bb_busybox_exec_path, v, envp);
    32263065        }
    32273066    }
     
    32303069
    32313070    sp = any('/', c) ? "" : path->value;
    3232     asis = *sp == '\0';
     3071    asis = (*sp == '\0');
    32333072    while (asis || *sp != '\0') {
    32343073        asis = 0;
    32353074        tp = e.linep;
    3236         for (; *sp != '\0'; tp++)
    3237             if ((*tp = *sp++) == ':') {
    3238                 asis = *sp == '\0';
     3075        for (; *sp != '\0'; tp++) {
     3076            *tp = *sp++;
     3077            if (*tp == ':') {
     3078                asis = (*sp == '\0');
    32393079                break;
    32403080            }
     3081        }
    32413082        if (tp != e.linep)
    32423083            *tp++ = '/';
     
    32543095            execve(DEFAULT_SHELL, v, envp);
    32553096            *v = tp;
    3256             return ("no Shell");
     3097            return "no Shell";
    32573098
    32583099        case ENOMEM:
    3259             return ((char *) bb_msg_memory_exhausted);
     3100            return (char *) bb_msg_memory_exhausted;
    32603101
    32613102        case E2BIG:
    3262             return ("argument list too long");
     3103            return "argument list too long";
    32633104
    32643105        case EACCES:
     
    32673108        }
    32683109    }
    3269     return (errno == ENOENT ? "not found" : "cannot execute");
     3110    return errno == ENOENT ? "not found" : "cannot execute";
    32703111}
    32713112
     
    32983139    rv = -1;
    32993140
    3300     if (newenv(setjmp(errpt = ev)) == 0) {
     3141    errpt = ev;
     3142    if (newenv(setjmp(errpt)) == 0) {
    33013143        wdlist = 0;
    33023144        iolist = 0;
     
    33043146        e.iobase = e.iop;
    33053147        yynerrs = 0;
    3306         if (setjmp(failpt = rt) == 0 && yyparse() == 0)
     3148        failpt = rt;
     3149        if (setjmp(failpt) == 0 && yyparse() == 0)
    33073150            rv = execute(outtree, NOPIPE, NOPIPE, 0);
    33083151        quitenv();
     
    33173160    freearea(areanum--);
    33183161
    3319     return (rv);
     3162    return rv;
    33203163}
    33213164
     
    33313174    const struct builtincmd *x;
    33323175
    3333     printf("\nBuilt-in commands:\n");
    3334     printf("-------------------\n");
    3335 
    3336     for (col = 0, x = builtincmds; x->builtinfunc != NULL; x++) {
    3337         if (!x->name)
    3338             continue;
    3339         col += printf("%s%s", ((col == 0) ? "\t" : " "), x->name);
     3176    puts("\nBuilt-in commands:\n"
     3177         "-------------------");
     3178
     3179    col = 0;
     3180    x = builtincmds;
     3181    while (x->name) {
     3182        col += printf("%c%s", ((col == 0) ? '\t' : ' '), x->name);
    33403183        if (col > 60) {
    3341             printf("\n");
     3184            puts("");
    33423185            col = 0;
    33433186        }
    3344     }
    3345 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
     3187        x++;
     3188    }
     3189#if ENABLE_FEATURE_SH_STANDALONE
    33463190    {
    3347         int i;
    3348         const struct BB_applet *applet;
    3349         extern const struct BB_applet applets[];
    3350         extern const size_t NUM_APPLETS;
    3351 
    3352         for (i = 0, applet = applets; i < NUM_APPLETS; applet++, i++) {
    3353             if (!applet->name)
    3354                 continue;
    3355 
    3356             col += printf("%s%s", ((col == 0) ? "\t" : " "), applet->name);
     3191        const struct bb_applet *applet = applets;
     3192
     3193        while (applet->name) {
     3194            col += printf("%c%s", ((col == 0) ? '\t' : ' '), applet->name);
    33573195            if (col > 60) {
    3358                 printf("\n");
     3196                puts("");
    33593197                col = 0;
    33603198            }
     3199            applet++;
    33613200        }
    33623201    }
    33633202#endif
    3364     printf("\n\n");
     3203    puts("\n");
    33653204    return EXIT_SUCCESS;
    33663205}
    33673206
    3368 
    3369 
    33703207static int dolabel(struct op *t)
    33713208{
    3372     return (0);
    3373 }
    3374 
    3375 static int dochdir(REGISTER struct op *t)
    3376 {
    3377     REGISTER char *cp, *er;
    3378 
    3379     if ((cp = t->words[1]) == NULL && (cp = homedir->value) == NULL)
     3209    return 0;
     3210}
     3211
     3212static int dochdir(struct op *t)
     3213{
     3214    const char *cp, *er;
     3215
     3216    cp = t->words[1];
     3217    if (cp == NULL) {
     3218        cp = homedir->value;
     3219        if (cp != NULL)
     3220            goto do_cd;
    33803221        er = ": no home directory";
    3381     else if (chdir(cp) < 0)
     3222    } else {
     3223 do_cd:
     3224        if (chdir(cp) >= 0)
     3225            return 0;
    33823226        er = ": bad directory";
    3383     else
    3384         return (0);
     3227    }
    33853228    prs(cp != NULL ? cp : "cd");
    33863229    err(er);
    3387     return (1);
    3388 }
    3389 
    3390 static int doshift(REGISTER struct op *t)
    3391 {
    3392     REGISTER int n;
     3230    return 1;
     3231}
     3232
     3233static int doshift(struct op *t)
     3234{
     3235    int n;
    33933236
    33943237    n = t->words[1] ? getn(t->words[1]) : 1;
    33953238    if (dolc < n) {
    33963239        err("nothing to shift");
    3397         return (1);
     3240        return 1;
    33983241    }
    33993242    dolv[n] = dolv[0];
     
    34013244    dolc -= n;
    34023245    setval(lookup("#"), putn(dolc));
    3403     return (0);
     3246    return 0;
    34043247}
    34053248
     
    34093252static int dologin(struct op *t)
    34103253{
    3411     REGISTER char *cp;
     3254    const char *cp;
    34123255
    34133256    if (interactive) {
     
    34193262    prs(": ");
    34203263    err(cp);
    3421     return (1);
    3422 }
    3423 
    3424 static int doumask(REGISTER struct op *t)
    3425 {
    3426     REGISTER int i, n;
    3427     REGISTER char *cp;
    3428 
    3429     if ((cp = t->words[1]) == NULL) {
     3264    return 1;
     3265}
     3266
     3267static int doumask(struct op *t)
     3268{
     3269    int i, n;
     3270    char *cp;
     3271
     3272    cp = t->words[1];
     3273    if (cp == NULL) {
    34303274        i = umask(0);
    34313275        umask(i);
     
    34343278        putc('\n', stderr);
    34353279    } else {
     3280/* huh??? '8','9' are not allowed! */
    34363281        for (n = 0; *cp >= '0' && *cp <= '9'; cp++)
    34373282            n = n * 8 + (*cp - '0');
    34383283        umask(n);
    34393284    }
    3440     return (0);
    3441 }
    3442 
    3443 static int doexec(REGISTER struct op *t)
    3444 {
    3445     REGISTER int i;
     3285    return 0;
     3286}
     3287
     3288static int doexec(struct op *t)
     3289{
     3290    int i;
    34463291    jmp_buf ex;
    34473292    xint *ofail;
     
    34503295    for (i = 0; (t->words[i] = t->words[i + 1]) != NULL; i++);
    34513296    if (i == 0)
    3452         return (1);
     3297        return 1;
    34533298    execflg = 1;
    34543299    ofail = failpt;
    3455     if (setjmp(failpt = ex) == 0)
     3300    failpt = ex;
     3301    if (setjmp(failpt) == 0)
    34563302        execute(t, NOPIPE, NOPIPE, FEXEC);
    34573303    failpt = ofail;
    34583304    execflg = 0;
    3459     return (1);
     3305    return 1;
    34603306}
    34613307
    34623308static int dodot(struct op *t)
    34633309{
    3464     REGISTER int i;
    3465     REGISTER char *sp, *tp;
     3310    int i;
     3311    const char *sp;
     3312    char *tp;
    34663313    char *cp;
    34673314    int maltmp;
     
    34693316    DBGPRINTF(("DODOT: enter, t=%p, tleft %p, tright %p, e.linep is %s\n", t, t->left, t->right, ((e.linep == NULL) ? "NULL" : e.linep)));
    34703317
    3471     if ((cp = t->words[1]) == NULL) {
     3318    cp = t->words[1];
     3319    if (cp == NULL) {
    34723320        DBGPRINTF(("DODOT: bad args, ret 0\n"));
    3473         return (0);
    3474     } else {
    3475         DBGPRINTF(("DODOT: cp is %s\n", cp));
    3476     }
     3321        return 0;
     3322    }
     3323    DBGPRINTF(("DODOT: cp is %s\n", cp));
    34773324
    34783325    sp = any('/', cp) ? ":" : path->value;
     
    34923339
    34933340        /* Original code */
    3494         if ((i = open(e.linep, 0)) >= 0) {
     3341        i = open(e.linep, O_RDONLY);
     3342        if (i >= 0) {
    34953343            exstat = 0;
    34963344            maltmp = remap(i);
     
    35013349            DBGPRINTF(("DODOT: returning exstat=%d\n", exstat));
    35023350
    3503             return (exstat);
    3504         }
    3505 
    3506     }                           /* While */
     3351            return exstat;
     3352        }
     3353    } /* while */
    35073354
    35083355    prs(cp);
    35093356    err(": not found");
    35103357
    3511     return (-1);
     3358    return -1;
    35123359}
    35133360
    35143361static int dowait(struct op *t)
    35153362{
    3516     REGISTER int i;
    3517     REGISTER char *cp;
    3518 
    3519     if ((cp = t->words[1]) != NULL) {
     3363    int i;
     3364    char *cp;
     3365
     3366    cp = t->words[1];
     3367    if (cp != NULL) {
    35203368        i = getn(cp);
    35213369        if (i == 0)
    3522             return (0);
     3370            return 0;
    35233371    } else
    35243372        i = -1;
    35253373    setstatus(waitfor(i, 1));
    3526     return (0);
     3374    return 0;
    35273375}
    35283376
    35293377static int doread(struct op *t)
    35303378{
    3531     REGISTER char *cp, **wp;
    3532     REGISTER int nb = 0;
    3533     REGISTER int nl = 0;
     3379    char *cp, **wp;
     3380    int nb = 0;
     3381    int nl = 0;
    35343382
    35353383    if (t->words[1] == NULL) {
    35363384        err("Usage: read name ...");
    3537         return (1);
     3385        return 1;
    35383386    }
    35393387    for (wp = t->words + 1; *wp; wp++) {
    3540         for (cp = e.linep; !nl && cp < elinep - 1; cp++)
    3541             if ((nb = read(0, cp, sizeof(*cp))) != sizeof(*cp) ||
    3542                 (nl = (*cp == '\n')) || (wp[1] && any(*cp, ifs->value)))
     3388        for (cp = e.linep; !nl && cp < elinep - 1; cp++) {
     3389            nb = read(0, cp, sizeof(*cp));
     3390            if (nb != sizeof(*cp))
    35433391                break;
    3544         *cp = 0;
     3392            nl = (*cp == '\n');
     3393            if (nl || (wp[1] && any(*cp, ifs->value)))
     3394                break;
     3395        }
     3396        *cp = '\0';
    35453397        if (nb <= 0)
    35463398            break;
    35473399        setval(lookup(*wp), e.linep);
    35483400    }
    3549     return (nb <= 0);
    3550 }
    3551 
    3552 static int doeval(REGISTER struct op *t)
    3553 {
    3554     return (RUN(awordlist, t->words + 1, wdchar));
    3555 }
    3556 
    3557 static int dotrap(REGISTER struct op *t)
    3558 {
    3559     REGISTER int n, i;
    3560     REGISTER int resetsig;
     3401    return nb <= 0;
     3402}
     3403
     3404static int doeval(struct op *t)
     3405{
     3406    return RUN(awordlist, t->words + 1, wdchar);
     3407}
     3408
     3409static int dotrap(struct op *t)
     3410{
     3411    int n, i;
     3412    int resetsig;
    35613413
    35623414    if (t->words[1] == NULL) {
     
    35683420                prs("\n");
    35693421            }
    3570         return (0);
     3422        return 0;
    35713423    }
    35723424    resetsig = isdigit(*t->words[1]);
     
    35823434                setsig(n, SIG_IGN);
    35833435        } else {
    3584             if (interactive)
     3436            if (interactive) {
    35853437                if (n == SIGINT)
    35863438                    setsig(n, onintr);
    35873439                else
    35883440                    setsig(n, n == SIGQUIT ? SIG_IGN : SIG_DFL);
    3589             else
     3441            } else
    35903442                setsig(n, SIG_DFL);
    35913443        }
    35923444    }
    3593     return (0);
     3445    return 0;
    35943446}
    35953447
    35963448static int getsig(char *s)
    35973449{
    3598     REGISTER int n;
    3599 
    3600     if ((n = getn(s)) < 0 || n > _NSIG) {
     3450    int n;
     3451
     3452    n = getn(s);
     3453    if (n < 0 || n > _NSIG) {
    36013454        err("trap: bad signal number");
    36023455        n = 0;
    36033456    }
    3604     return (n);
    3605 }
    3606 
    3607 static void setsig(REGISTER int n, sighandler_t f)
     3457    return n;
     3458}
     3459
     3460static void setsig(int n, sighandler_t f)
    36083461{
    36093462    if (n == 0)
     
    36173470static int getn(char *as)
    36183471{
    3619     REGISTER char *s;
    3620     REGISTER int n, m;
     3472    char *s;
     3473    int n, m;
    36213474
    36223475    s = as;
     
    36323485        err(": bad number");
    36333486    }
    3634     return (n * m);
     3487    return n * m;
    36353488}
    36363489
    36373490static int dobreak(struct op *t)
    36383491{
    3639     return (brkcontin(t->words[1], 1));
     3492    return brkcontin(t->words[1], 1);
    36403493}
    36413494
    36423495static int docontinue(struct op *t)
    36433496{
    3644     return (brkcontin(t->words[1], 0));
    3645 }
    3646 
    3647 static int brkcontin(REGISTER char *cp, int val)
    3648 {
    3649     REGISTER struct brkcon *bc;
    3650     REGISTER int nl;
     3497    return brkcontin(t->words[1], 0);
     3498}
     3499
     3500static int brkcontin(char *cp, int val)
     3501{
     3502    struct brkcon *bc;
     3503    int nl;
    36513504
    36523505    nl = cp == NULL ? 1 : getn(cp);
     
    36543507        nl = 999;
    36553508    do {
    3656         if ((bc = brklist) == NULL)
     3509        bc = brklist;
     3510        if (bc == NULL)
    36573511            break;
    36583512        brklist = bc->nextlev;
     
    36603514    if (nl) {
    36613515        err("bad break/continue level");
    3662         return (1);
     3516        return 1;
    36633517    }
    36643518    isbreak = val;
     
    36693523static int doexit(struct op *t)
    36703524{
    3671     REGISTER char *cp;
     3525    char *cp;
    36723526
    36733527    execflg = 0;
    3674     if ((cp = t->words[1]) != NULL)
     3528    cp = t->words[1];
     3529    if (cp != NULL)
    36753530        setstatus(getn(cp));
    36763531
     
    36793534    leave();
    36803535    /* NOTREACHED */
    3681     return (0);
     3536    return 0;
    36823537}
    36833538
     
    36853540{
    36863541    rdexp(t->words + 1, export, EXPORT);
    3687     return (0);
     3542    return 0;
    36883543}
    36893544
     
    36913546{
    36923547    rdexp(t->words + 1, ronly, RONLY);
    3693     return (0);
     3548    return 0;
    36943549}
    36953550
     
    37173572}
    37183573
    3719 static void badid(REGISTER char *s)
     3574static void badid(char *s)
    37203575{
    37213576    prs(s);
     
    37233578}
    37243579
    3725 static int doset(REGISTER struct op *t)
    3726 {
    3727     REGISTER struct var *vp;
    3728     REGISTER char *cp;
    3729     REGISTER int n;
    3730 
    3731     if ((cp = t->words[1]) == NULL) {
     3580static int doset(struct op *t)
     3581{
     3582    struct var *vp;
     3583    char *cp;
     3584    int n;
     3585
     3586    cp = t->words[1];
     3587    if (cp == NULL) {
    37323588        for (vp = vlist; vp; vp = vp->next)
    37333589            varput(vp->name, 1);
    3734         return (0);
     3590        return 0;
    37353591    }
    37363592    if (*cp == '-') {
     
    37383594        for (n = 0; (t->words[n] = t->words[n + 1]) != NULL; n++);
    37393595        if (*++cp == 0)
    3740             flag['x'] = flag['v'] = 0;
    3741         else
    3742             for (; *cp; cp++)
     3596            FLAG['x'] = FLAG['v'] = 0;
     3597        else {
     3598            for (; *cp; cp++) {
    37433599                switch (*cp) {
    37443600                case 'e':
    37453601                    if (!interactive)
    3746                         flag['e']++;
     3602                        FLAG['e']++;
    37473603                    break;
    37483604
    37493605                default:
    37503606                    if (*cp >= 'a' && *cp <= 'z')
    3751                         flag[(int) *cp]++;
     3607                        FLAG[(int) *cp]++;
    37523608                    break;
    37533609                }
     3610            }
     3611        }
    37543612        setdash();
    37553613    }
     
    37633621        setarea((char *) (dolv - 1), 0);
    37643622    }
    3765     return (0);
    3766 }
    3767 
    3768 static void varput(REGISTER char *s, int out)
     3623    return 0;
     3624}
     3625
     3626static void varput(char *s, int out)
    37693627{
    37703628    if (isalnum(*s) || *s == '_') {
     
    37823640{
    37833641    struct tms buf;
    3784     long int clk_tck = sysconf(_SC_CLK_TCK);
     3642    long clk_tck = sysconf(_SC_CLK_TCK);
    37853643
    37863644    times(&buf);
     
    37983656
    37993657
    3800 static int (*inbuilt(char *s)) (struct op *) {
    3801     const struct builtincmd *bp;
    3802 
    3803     for (bp = builtincmds; bp->name != NULL; bp++)
    3804         if (strcmp(bp->name, s) == 0)
    3805             return (bp->builtinfunc);
    3806 
    3807     return (NULL);
    3808 }
    3809 
    38103658/* -------- eval.c -------- */
    38113659
     
    38363684    wb = NULL;
    38373685    wf = NULL;
    3838     if (newenv(setjmp(errpt = ev)) == 0) {
     3686    errpt = ev;
     3687    if (newenv(setjmp(errpt)) == 0) {
    38393688        while (*ap && isassign(*ap))
    38403689            expand(*ap++, &wb, f & ~DOGLOB);
    3841         if (flag['k']) {
     3690        if (FLAG['k']) {
    38423691            for (wf = ap; *wf; wf++) {
    38433692                if (isassign(*wf))
     
    38463695        }
    38473696        for (wb = addword((char *) 0, wb); *ap; ap++) {
    3848             if (!flag['k'] || !isassign(*ap))
     3697            if (!FLAG['k'] || !isassign(*ap))
    38493698                expand(*ap, &wb, f & ~DOKEY);
    38503699        }
     
    38553704        gflg = 1;
    38563705
    3857     return (gflg ? (char **) NULL : wp);
    3858 }
     3706    return gflg ? (char **) NULL : wp;
     3707}
     3708
    38593709
    38603710/*
     
    38653715static char **makenv(int all, struct wdblock *wb)
    38663716{
    3867     REGISTER struct var *vp;
     3717    struct var *vp;
    38683718
    38693719    DBGPRINTF5(("MAKENV: enter, all=%d\n", all));
     
    38733723            wb = addword(vp->name, wb);
    38743724    wb = addword((char *) 0, wb);
    3875     return (getwords(wb));
    3876 }
    3877 
    3878 static char *evalstr(REGISTER char *cp, int f)
    3879 {
    3880     struct wdblock *wb;
    3881 
    3882     DBGPRINTF6(("EVALSTR: enter, cp=%p, f=%d\n", cp, f));
    3883 
    3884     wb = NULL;
    3885     if (expand(cp, &wb, f)) {
    3886         if (wb == NULL || wb->w_nword == 0
    3887             || (cp = wb->w_words[0]) == NULL)
    3888             cp = "";
    3889         DELETE(wb);
    3890     } else
    3891         cp = NULL;
    3892     return (cp);
    3893 }
    3894 
    3895 static int expand(char *cp, REGISTER struct wdblock **wbp, int f)
     3725    return getwords(wb);
     3726}
     3727
     3728static int expand(const char *cp, struct wdblock **wbp, int f)
    38963729{
    38973730    jmp_buf ev;
     3731    char *xp;
    38983732
    38993733#if __GNUC__
     
    39073741
    39083742    if (cp == NULL)
    3909         return (0);
    3910 
    3911     if (!anys("$`'\"", cp) &&
    3912         !anys(ifs->value, cp) && ((f & DOGLOB) == 0 || !anys("[*?", cp))) {
    3913         cp = strsave(cp, areanum);
     3743        return 0;
     3744
     3745    if (!anys("$`'\"", cp) && !anys(ifs->value, cp)
     3746     && ((f & DOGLOB) == 0 || !anys("[*?", cp))
     3747    ) {
     3748        xp = strsave(cp, areanum);
    39143749        if (f & DOTRIM)
    3915             unquote(cp);
    3916         *wbp = addword(cp, *wbp);
    3917         return (1);
    3918     }
    3919     if (newenv(setjmp(errpt = ev)) == 0) {
     3750            unquote(xp);
     3751        *wbp = addword(xp, *wbp);
     3752        return 1;
     3753    }
     3754    errpt = ev;
     3755    if (newenv(setjmp(errpt)) == 0) {
    39203756        PUSHIO(aword, cp, strchar);
    39213757        e.iobase = e.iop;
    3922         while ((cp = blank(f)) && gflg == 0) {
    3923             e.linep = cp;
    3924             cp = strsave(cp, areanum);
     3758        while ((xp = blank(f)) && gflg == 0) {
     3759            e.linep = xp;
     3760            xp = strsave(xp, areanum);
    39253761            if ((f & DOGLOB) == 0) {
    39263762                if (f & DOTRIM)
    3927                     unquote(cp);
    3928                 *wbp = addword(cp, *wbp);
     3763                    unquote(xp);
     3764                *wbp = addword(xp, *wbp);
    39293765            } else
    3930                 *wbp = glob(cp, *wbp);
     3766                *wbp = glob(xp, *wbp);
    39313767        }
    39323768        quitenv();
    39333769    } else
    39343770        gflg = 1;
    3935     return (gflg == 0);
    3936 }
     3771    return gflg == 0;
     3772}
     3773
     3774static char *evalstr(char *cp, int f)
     3775{
     3776    struct wdblock *wb;
     3777
     3778    DBGPRINTF6(("EVALSTR: enter, cp=%p, f=%d\n", cp, f));
     3779
     3780    wb = NULL;
     3781    if (expand(cp, &wb, f)) {
     3782        if (wb == NULL || wb->w_nword == 0
     3783         || (cp = wb->w_words[0]) == NULL
     3784        ) {
     3785// TODO: I suspect that
     3786// char *evalstr(char *cp, int f)  is actually
     3787// const char *evalstr(const char *cp, int f)!
     3788            cp = (char*)"";
     3789        }
     3790        DELETE(wb);
     3791    } else
     3792        cp = NULL;
     3793    return cp;
     3794}
     3795
    39373796
    39383797/*
     
    39413800static char *blank(int f)
    39423801{
    3943     REGISTER int c, c1;
    3944     REGISTER char *sp;
     3802    int c, c1;
     3803    char *sp;
    39453804    int scanequals, foundequals;
    39463805
     
    39513810    foundequals = 0;
    39523811
    3953   loop:
    3954     switch (c = subgetc('"', foundequals)) {
     3812 loop:
     3813    c = subgetc('"', foundequals);
     3814    switch (c) {
    39553815    case 0:
    39563816        if (sp == e.linep)
    3957             return (0);
     3817            return 0;
    39583818        *e.linep++ = 0;
    3959         return (sp);
     3819        return sp;
    39603820
    39613821    default:
     
    40023862    }
    40033863    *e.linep++ = 0;
    4004     return (sp);
     3864    return sp;
    40053865}
    40063866
     
    40083868 * Get characters, substituting for ` and $
    40093869 */
    4010 static int subgetc(REGISTER char ec, int quoted)
    4011 {
    4012     REGISTER char c;
     3870static int subgetc(char ec, int quoted)
     3871{
     3872    char c;
    40133873
    40143874    DBGPRINTF3(("SUBGETC: enter, quoted=%d\n", quoted));
    40153875
    4016   again:
     3876 again:
    40173877    c = my_getc(ec);
    40183878    if (!INSUB() && ec != '\'') {
    40193879        if (c == '`') {
    40203880            if (grave(quoted) == 0)
    4021                 return (0);
     3881                return 0;
    40223882            e.iop->task = XGRAVE;
    40233883            goto again;
    40243884        }
    4025         if (c == '$' && (c = dollar(quoted)) == 0) {
    4026             e.iop->task = XDOLL;
    4027             goto again;
    4028         }
    4029     }
    4030     return (c);
     3885        if (c == '$') {
     3886            c = dollar(quoted);
     3887            if (c == 0) {
     3888                e.iop->task = XDOLL;
     3889                goto again;
     3890            }
     3891        }
     3892    }
     3893    return c;
    40313894}
    40323895
     
    40393902    struct io *oiop;
    40403903    char *dolp;
    4041     REGISTER char *s, c, *cp = NULL;
     3904    char *s, c, *cp = NULL;
    40423905    struct var *vp;
    40433906
     
    40683931            err("unclosed ${");
    40693932            gflg++;
    4070             return (c);
     3933            return c;
    40713934        }
    40723935    }
     
    40903953            e.linep = s;
    40913954            PUSHIO(awordlist, dolv + 1, dolchar);
    4092             return (0);
     3955            return 0;
    40933956        } else {                /* trap the nasty ${=} */
    40943957            s[0] = '1';
    4095             s[1] = 0;
     3958            s[1] = '\0';
    40963959        }
    40973960    }
    40983961    vp = lookup(s);
    4099     if ((dolp = vp->value) == null) {
     3962    dolp = vp->value;
     3963    if (dolp == null) {
    41003964        switch (c) {
    41013965        case '=':
     
    41243988    } else if (c == '+')
    41253989        dolp = strsave(cp, areanum);
    4126     if (flag['u'] && dolp == null) {
     3990    if (FLAG['u'] && dolp == null) {
    41273991        prs("unset variable: ");
    41283992        err(s);
     
    41313995    e.linep = s;
    41323996    PUSHIO(aword, dolp, quoted ? qstrchar : strchar);
    4133     return (0);
     3997    return 0;
    41343998}
    41353999
     
    41404004static int grave(int quoted)
    41414005{
    4142     char *cp;
    4143     REGISTER int i;
     4006    /* moved to G: static char child_cmd[LINELIM]; */
     4007
     4008    const char *cp;
     4009    int i;
    41444010    int j;
    41454011    int pf[2];
    4146     static char child_cmd[LINELIM];
    4147     char *src;
     4012    const char *src;
    41484013    char *dest;
    41494014    int count;
     
    41584023#endif
    41594024
    4160     for (cp = e.iop->argp->aword; *cp != '`'; cp++)
     4025    for (cp = e.iop->argp->aword; *cp != '`'; cp++) {
    41614026        if (*cp == 0) {
    41624027            err("no closing `");
    4163             return (0);
    4164         }
     4028            return 0;
     4029        }
     4030    }
    41654031
    41664032    /* string copy with dollar expansion */
     
    42084074                default:
    42094075                    err("unclosed ${\n");
    4210                     return (0);
     4076                    return 0;
    42114077                }
    42124078                if (operator) {
     
    42184084                    if (*src != '}') {
    42194085                        err("unclosed ${\n");
    4220                         return (0);
     4086                        return 0;
    42214087                    }
    42224088                }
     
    42534119                else if (operator == '?') {
    42544120                    err(alt_value);
    4255                     return (0);
     4121                    return 0;
    42564122                } else if (alt_index && (operator != '+')) {
    42574123                    value = alt_value;
     
    42754141
    42764142    if (openpipe(pf) < 0)
    4277         return (0);
     4143        return 0;
    42784144
    42794145    while ((i = vfork()) == -1 && errno == EAGAIN);
     
    42844150        closepipe(pf);
    42854151        err((char *) bb_msg_memory_exhausted);
    4286         return (0);
     4152        return 0;
    42874153    }
    42884154    if (i != 0) {
     
    42914157        close(pf[1]);
    42924158        PUSHIO(afile, remap(pf[0]),
    4293                (int (*)(struct ioarg *)) ((quoted) ? qgravechar :
    4294                                           gravechar));
    4295         return (1);
     4159            (int (*)(struct ioarg *)) ((quoted) ? qgravechar : gravechar));
     4160        return 1;
    42964161    }
    42974162    /* allow trapped signals */
     
    43014166            signal(j, SIG_DFL);
    43024167
    4303     dup2(pf[1], 1);
    4304     closepipe(pf);
     4168    /* Testcase where below checks are needed:
     4169     * close stdout & run this script:
     4170     *  files=`ls`
     4171     *  echo "$files" >zz
     4172     */
     4173    xmove_fd(pf[1], 1);
     4174    if (pf[0] != 1) close(pf[0]);
    43054175
    43064176    argument_list[0] = (char *) DEFAULT_SHELL;
    4307     argument_list[1] = "-c";
     4177    argument_list[1] = (char *) "-c";
    43084178    argument_list[2] = child_cmd;
    4309     argument_list[3] = 0;
     4179    argument_list[3] = NULL;
    43104180
    43114181    cp = rexecve(argument_list[0], argument_list, makenv(1, wb));
     
    43174187
    43184188
    4319 static char *unquote(REGISTER char *as)
    4320 {
    4321     REGISTER char *s;
    4322 
    4323     if ((s = as) != NULL)
     4189static char *unquote(char *as)
     4190{
     4191    char *s;
     4192
     4193    s = as;
     4194    if (s != NULL)
    43244195        while (*s)
    43254196            *s++ &= ~QUOTE;
    4326     return (as);
     4197    return as;
    43274198}
    43284199
     
    43384209
    43394210static struct wdblock *cl, *nl;
    4340 static char spcl[] = "[?*";
     4211static const char spcl[] ALIGN1= "[?*";
    43414212
    43424213static struct wdblock *glob(char *cp, struct wdblock *wb)
    43434214{
    4344     REGISTER int i;
    4345     REGISTER char *pp;
     4215    int i;
     4216    char *pp;
    43464217
    43474218    if (cp == 0)
    4348         return (wb);
     4219        return wb;
    43494220    i = 0;
    43504221    for (pp = cp; *pp; pp++)
     
    43544225            *pp &= ~QUOTE;
    43554226    if (i != 0) {
    4356         for (cl = addword(scopy(cp), (struct wdblock *) 0); anyspcl(cl);
    4357              cl = nl) {
     4227        for (cl = addword(scopy(cp), NULL); anyspcl(cl); cl = nl) {
    43584228            nl = newword(cl->w_nword * 2);
    43594229            for (i = 0; i < cl->w_nword; i++) { /* for each argument */
     
    43774247                wb = addword(cl->w_words[i], wb);
    43784248            DELETE(cl);
    4379             return (wb);
     4249            return wb;
    43804250        }
    43814251    }
    43824252    wb = addword(unquote(cp), wb);
    4383     return (wb);
    4384 }
    4385 
    4386 static void globname(char *we, REGISTER char *pp)
    4387 {
    4388     REGISTER char *np, *cp;
     4253    return wb;
     4254}
     4255
     4256static void globname(char *we, char *pp)
     4257{
     4258    char *np, *cp;
    43894259    char *name, *gp, *dp;
    43904260    int k;
     
    44154285        /*
    44164286           if (ent[j].d_ino == 0)
    4417            continue;
     4287              continue;
    44184288         */
    44194289        strncpy(dname, de->d_name, NAME_MAX);
     
    44454315 * the slashes come for free
    44464316 */
    4447 static char *generate(char *start1, REGISTER char *end1, char *middle, char *end)
     4317static char *generate(char *start1, char *end1, char *middle, char *end)
    44484318{
    44494319    char *p;
    4450     REGISTER char *op, *xp;
    4451 
    4452     p = op =
    4453         space((int) (end1 - start1) + strlen(middle) + strlen(end) + 2);
     4320    char *op, *xp;
     4321
     4322    p = op = space((int)(end1 - start1) + strlen(middle) + strlen(end) + 2);
    44544323    for (xp = start1; xp != end1;)
    44554324        *op++ = *xp++;
     
    44574326    op--;
    44584327    for (xp = end; (*op++ = *xp++) != '\0';);
    4459     return (p);
    4460 }
    4461 
    4462 static int anyspcl(REGISTER struct wdblock *wb)
    4463 {
    4464     REGISTER int i;
    4465     REGISTER char **wd;
     4328    return p;
     4329}
     4330
     4331static int anyspcl(struct wdblock *wb)
     4332{
     4333    int i;
     4334    char **wd;
    44664335
    44674336    wd = wb->w_words;
    44684337    for (i = 0; i < wb->w_nword; i++)
    44694338        if (anys(spcl, *wd++))
    4470             return (1);
    4471     return (0);
     4339            return 1;
     4340    return 0;
    44724341}
    44734342
    44744343static int xstrcmp(char *p1, char *p2)
    44754344{
    4476     return (strcmp(*(char **) p1, *(char **) p2));
    4477 }
     4345    return strcmp(*(char **) p1, *(char **) p2);
     4346}
     4347
    44784348
    44794349/* -------- word.c -------- */
    44804350
    4481 static struct wdblock *newword(REGISTER int nw)
    4482 {
    4483     REGISTER struct wdblock *wb;
     4351static struct wdblock *newword(int nw)
     4352{
     4353    struct wdblock *wb;
    44844354
    44854355    wb = (struct wdblock *) space(sizeof(*wb) + nw * sizeof(char *));
    44864356    wb->w_bsize = nw;
    44874357    wb->w_nword = 0;
    4488     return (wb);
    4489 }
    4490 
    4491 static struct wdblock *addword(char *wd, REGISTER struct wdblock *wb)
    4492 {
    4493     REGISTER struct wdblock *wb2;
    4494     REGISTER int nw;
     4358    return wb;
     4359}
     4360
     4361static struct wdblock *addword(char *wd, struct wdblock *wb)
     4362{
     4363    struct wdblock *wb2;
     4364    int nw;
    44954365
    44964366    if (wb == NULL)
    44974367        wb = newword(NSTART);
    4498     if ((nw = wb->w_nword) >= wb->w_bsize) {
     4368    nw = wb->w_nword;
     4369    if (nw >= wb->w_bsize) {
    44994370        wb2 = newword(nw * 2);
    45004371        memcpy((char *) wb2->w_words, (char *) wb->w_words,
     
    45054376    }
    45064377    wb->w_words[wb->w_nword++] = wd;
    4507     return (wb);
    4508 }
    4509 
    4510 static
    4511 char **getwords(REGISTER struct wdblock *wb)
    4512 {
    4513     REGISTER char **wd;
    4514     REGISTER int nb;
     4378    return wb;
     4379}
     4380
     4381static char **getwords(struct wdblock *wb)
     4382{
     4383    char **wd;
     4384    int nb;
    45154385
    45164386    if (wb == NULL)
    4517         return ((char **) NULL);
     4387        return NULL;
    45184388    if (wb->w_nword == 0) {
    45194389        DELETE(wb);
    4520         return ((char **) NULL);
     4390        return NULL;
    45214391    }
    45224392    wd = (char **) space(nb = sizeof(*wd) * wb->w_nword);
    45234393    memcpy((char *) wd, (char *) wb->w_words, nb);
    45244394    DELETE(wb);                 /* perhaps should done by caller */
    4525     return (wd);
     4395    return wd;
    45264396}
    45274397
     
    45294399static int globv;
    45304400
    4531 static void glob0(char *a0, unsigned a1, int a2, int (*a3) (char *, char *))
    4532 {
    4533     func = a3;
    4534     globv = a2;
    4535     glob1(a0, a0 + a1 * a2);
    4536 }
    4537 
    4538 static void glob1(char *base, char *lim)
    4539 {
    4540     REGISTER char *i, *j;
    4541     int v2;
    4542     char *lptr, *hptr;
    4543     int c;
    4544     unsigned n;
    4545 
    4546 
    4547     v2 = globv;
    4548 
    4549   top:
    4550     if ((n = (int) (lim - base)) <= v2)
    4551         return;
    4552     n = v2 * (n / (2 * v2));
    4553     hptr = lptr = base + n;
    4554     i = base;
    4555     j = lim - v2;
    4556     for (;;) {
    4557         if (i < lptr) {
    4558             if ((c = (*func) (i, lptr)) == 0) {
    4559                 glob2(i, lptr -= v2);
    4560                 continue;
    4561             }
    4562             if (c < 0) {
    4563                 i += v2;
    4564                 continue;
    4565             }
    4566         }
    4567 
    4568       begin:
    4569         if (j > hptr) {
    4570             if ((c = (*func) (hptr, j)) == 0) {
    4571                 glob2(hptr += v2, j);
    4572                 goto begin;
    4573             }
    4574             if (c > 0) {
    4575                 if (i == lptr) {
    4576                     glob3(i, hptr += v2, j);
    4577                     i = lptr += v2;
    4578                     goto begin;
    4579                 }
    4580                 glob2(i, j);
    4581                 j -= v2;
    4582                 i += v2;
    4583                 continue;
    4584             }
    4585             j -= v2;
    4586             goto begin;
    4587         }
    4588 
    4589 
    4590         if (i == lptr) {
    4591             if (lptr - base >= lim - hptr) {
    4592                 glob1(hptr + v2, lim);
    4593                 lim = lptr;
    4594             } else {
    4595                 glob1(base, lptr);
    4596                 base = hptr + v2;
    4597             }
    4598             goto top;
    4599         }
    4600 
    4601 
    4602         glob3(j, lptr -= v2, i);
    4603         j = hptr -= v2;
    4604     }
    4605 }
    4606 
    4607 static void glob2(char *i, char *j)
    4608 {
    4609     REGISTER char *index1, *index2, c;
    4610     int m;
    4611 
    4612     m = globv;
    4613     index1 = i;
    4614     index2 = j;
    4615     do {
    4616         c = *index1;
    4617         *index1++ = *index2;
    4618         *index2++ = c;
    4619     } while (--m);
    4620 }
    4621 
    46224401static void glob3(char *i, char *j, char *k)
    46234402{
    4624     REGISTER char *index1, *index2, *index3;
     4403    char *index1, *index2, *index3;
    46254404    int c;
    46264405    int m;
     
    46384417}
    46394418
     4419static void glob2(char *i, char *j)
     4420{
     4421    char *index1, *index2, c;
     4422    int m;
     4423
     4424    m = globv;
     4425    index1 = i;
     4426    index2 = j;
     4427    do {
     4428        c = *index1;
     4429        *index1++ = *index2;
     4430        *index2++ = c;
     4431    } while (--m);
     4432}
     4433
     4434static void glob1(char *base, char *lim)
     4435{
     4436    char *i, *j;
     4437    int v2;
     4438    char *lptr, *hptr;
     4439    int c;
     4440    unsigned n;
     4441
     4442    v2 = globv;
     4443
     4444 top:
     4445    n = (int) (lim - base);
     4446    if (n <= v2)
     4447        return;
     4448    n = v2 * (n / (2 * v2));
     4449    hptr = lptr = base + n;
     4450    i = base;
     4451    j = lim - v2;
     4452    for (;;) {
     4453        if (i < lptr) {
     4454            c = (*func) (i, lptr);
     4455            if (c == 0) {
     4456                lptr -= v2;
     4457                glob2(i, lptr);
     4458                continue;
     4459            }
     4460            if (c < 0) {
     4461                i += v2;
     4462                continue;
     4463            }
     4464        }
     4465
     4466 begin:
     4467        if (j > hptr) {
     4468            c = (*func) (hptr, j);
     4469            if (c == 0) {
     4470                hptr += v2;
     4471                glob2(hptr, j);
     4472                goto begin;
     4473            }
     4474            if (c > 0) {
     4475                if (i == lptr) {
     4476                    hptr += v2;
     4477                    glob3(i, hptr, j);
     4478                    i = (lptr += v2);
     4479                    goto begin;
     4480                }
     4481                glob2(i, j);
     4482                j -= v2;
     4483                i += v2;
     4484                continue;
     4485            }
     4486            j -= v2;
     4487            goto begin;
     4488        }
     4489
     4490
     4491        if (i == lptr) {
     4492            if (lptr - base >= lim - hptr) {
     4493                glob1(hptr + v2, lim);
     4494                lim = lptr;
     4495            } else {
     4496                glob1(base, lptr);
     4497                base = hptr + v2;
     4498            }
     4499            goto top;
     4500        }
     4501
     4502        lptr -= v2;
     4503        glob3(j, lptr, i);
     4504        j = (hptr -= v2);
     4505    }
     4506}
     4507
     4508static void glob0(char *a0, unsigned a1, int a2, int (*a3) (char *, char *))
     4509{
     4510    func = a3;
     4511    globv = a2;
     4512    glob1(a0, a0 + a1 * a2);
     4513}
     4514
     4515
    46404516/* -------- io.c -------- */
    46414517
     
    46464522static int my_getc(int ec)
    46474523{
    4648     REGISTER int c;
     4524    int c;
    46494525
    46504526    if (e.linep > elinep) {
     
    46524528        err("input line too long");
    46534529        gflg++;
    4654         return (c);
     4530        return c;
    46554531    }
    46564532    c = readc();
     
    46594535            c = readc();
    46604536            if (c == '\n' && ec != '\"')
    4661                 return (my_getc(ec));
     4537                return my_getc(ec);
    46624538            c |= QUOTE;
    46634539        }
    46644540    }
    4665     return (c);
     4541    return c;
    46664542}
    46674543
     
    46794555static int readc(void)
    46804556{
    4681     REGISTER int c;
     4557    int c;
    46824558
    46834559    RCPRINTF(("READC: e.iop %p, e.iobase %p\n", e.iop, e.iobase));
     
    46854561    for (; e.iop >= e.iobase; e.iop--) {
    46864562        RCPRINTF(("READC: e.iop %p, peekc 0x%x\n", e.iop, e.iop->peekc));
    4687         if ((c = e.iop->peekc) != '\0') {
     4563        c = e.iop->peekc;
     4564        if (c != '\0') {
    46884565            e.iop->peekc = 0;
    4689             return (c);
    4690         } else {
    4691             if (e.iop->prev != 0) {
    4692                 if ((c = (*e.iop->iofn) (e.iop->argp, e.iop)) != '\0') {
    4693                     if (c == -1) {
    4694                         e.iop++;
    4695                         continue;
    4696                     }
    4697                     if (e.iop == iostack)
    4698                         ioecho(c);
    4699                     return (e.iop->prev = c);
    4700                 } else if (e.iop->task == XIO && e.iop->prev != '\n') {
    4701                     e.iop->prev = 0;
    4702                     if (e.iop == iostack)
    4703                         ioecho('\n');
    4704                     return '\n';
     4566            return c;
     4567        }
     4568        if (e.iop->prev != 0) {
     4569            c = (*e.iop->iofn)(e.iop->argp, e.iop);
     4570            if (c != '\0') {
     4571                if (c == -1) {
     4572                    e.iop++;
     4573                    continue;
    47054574                }
     4575                if (e.iop == iostack)
     4576                    ioecho(c);
     4577                e.iop->prev = c;
     4578                return e.iop->prev;
    47064579            }
    4707             if (e.iop->task == XIO) {
    4708                 if (multiline) {
    4709                     return e.iop->prev = 0;
    4710                 }
    4711                 if (interactive && e.iop == iostack + 1) {
    4712 #ifdef CONFIG_FEATURE_COMMAND_EDITING
    4713                     current_prompt = prompt->value;
     4580            if (e.iop->task == XIO && e.iop->prev != '\n') {
     4581                e.iop->prev = 0;
     4582                if (e.iop == iostack)
     4583                    ioecho('\n');
     4584                return '\n';
     4585            }
     4586        }
     4587        if (e.iop->task == XIO) {
     4588            if (multiline) {
     4589                e.iop->prev = 0;
     4590                return e.iop->prev;
     4591            }
     4592            if (interactive && e.iop == iostack + 1) {
     4593#if ENABLE_FEATURE_EDITING
     4594                current_prompt = prompt->value;
    47144595#else
    4715                     prs(prompt->value);
     4596                prs(prompt->value);
    47164597#endif
    4717                 }
    47184598            }
    47194599        }
    4720 
    47214600    }                           /* FOR */
    47224601
    47234602    if (e.iop >= iostack) {
    47244603        RCPRINTF(("READC: return 0, e.iop %p\n", e.iop));
    4725         return (0);
     4604        return 0;
    47264605    }
    47274606
     
    47304609
    47314610    /* NOTREACHED */
    4732     return (0);
     4611    return 0;
    47334612}
    47344613
    47354614static void ioecho(char c)
    47364615{
    4737     if (flag['v'])
     4616    if (FLAG['v'])
    47384617        write(2, &c, sizeof c);
    47394618}
     
    47754654        if ((isatty(e.iop->argp->afile) == 0)
    47764655            && (e.iop == &iostack[0]
    4777                 || lseek(e.iop->argp->afile, 0L, 1) != -1)) {
     4656                || lseek(e.iop->argp->afile, 0L, SEEK_CUR) != -1)) {
    47784657            if (++bufid == AFID_NOBUF)  /* counter rollover check, AFID_NOBUF = 11111111  */
    47794658                bufid = AFID_ID;    /* AFID_ID = 0 */
     
    47974676        e.iop->task = XIO;
    47984677    else if (fn == (int (*)(struct ioarg *)) gravechar
    4799             || fn == (int (*)(struct ioarg *)) qgravechar)
     4678    || fn == (int (*)(struct ioarg *)) qgravechar)
    48004679        e.iop->task = XGRAVE;
    48014680    else
    48024681        e.iop->task = XOTHER;
    4803 
    4804     return;
    48054682}
    48064683
    48074684static struct io *setbase(struct io *ip)
    48084685{
    4809     REGISTER struct io *xp;
     4686    struct io *xp;
    48104687
    48114688    xp = e.iobase;
    48124689    e.iobase = ip;
    4813     return (xp);
     4690    return xp;
    48144691}
    48154692
     
    48214698 * Produce the characters of a string, then a newline, then EOF.
    48224699 */
    4823 static int nlchar(REGISTER struct ioarg *ap)
    4824 {
    4825     REGISTER int c;
     4700static int nlchar(struct ioarg *ap)
     4701{
     4702    int c;
    48264703
    48274704    if (ap->aword == NULL)
    4828         return (0);
    4829     if ((c = *ap->aword++) == 0) {
     4705        return 0;
     4706    c = *ap->aword++;
     4707    if (c == 0) {
    48304708        ap->aword = NULL;
    4831         return ('\n');
    4832     }
    4833     return (c);
     4709        return '\n';
     4710    }
     4711    return c;
    48344712}
    48354713
     
    48384716 * in them, with a space after each word.
    48394717 */
    4840 static int wdchar(REGISTER struct ioarg *ap)
    4841 {
    4842     REGISTER char c;
    4843     REGISTER char **wl;
    4844 
    4845     if ((wl = ap->awordlist) == NULL)
    4846         return (0);
     4718static int wdchar(struct ioarg *ap)
     4719{
     4720    char c;
     4721    char **wl;
     4722
     4723    wl = ap->awordlist;
     4724    if (wl == NULL)
     4725        return 0;
    48474726    if (*wl != NULL) {
    4848         if ((c = *(*wl)++) != 0)
    4849             return (c & 0177);
     4727        c = *(*wl)++;
     4728        if (c != 0)
     4729            return c & 0177;
    48504730        ap->awordlist++;
    4851         return (' ');
     4731        return ' ';
    48524732    }
    48534733    ap->awordlist = NULL;
    4854     return ('\n');
     4734    return '\n';
    48554735}
    48564736
     
    48594739 * producing a space between them.
    48604740 */
    4861 static int dolchar(REGISTER struct ioarg *ap)
    4862 {
    4863     REGISTER char *wp;
    4864 
    4865     if ((wp = *ap->awordlist++) != NULL) {
     4741static int dolchar(struct ioarg *ap)
     4742{
     4743    char *wp;
     4744
     4745    wp = *ap->awordlist++;
     4746    if (wp != NULL) {
    48664747        PUSHIO(aword, wp, *ap->awordlist == NULL ? strchar : xxchar);
    4867         return (-1);
    4868     }
    4869     return (0);
    4870 }
    4871 
    4872 static int xxchar(REGISTER struct ioarg *ap)
    4873 {
    4874     REGISTER int c;
     4748        return -1;
     4749    }
     4750    return 0;
     4751}
     4752
     4753static int xxchar(struct ioarg *ap)
     4754{
     4755    int c;
    48754756
    48764757    if (ap->aword == NULL)
    4877         return (0);
    4878     if ((c = *ap->aword++) == '\0') {
     4758        return 0;
     4759    c = *ap->aword++;
     4760    if (c == '\0') {
    48794761        ap->aword = NULL;
    4880         return (' ');
    4881     }
    4882     return (c);
     4762        return ' ';
     4763    }
     4764    return c;
    48834765}
    48844766
     
    48864768 * Produce the characters from a single word (string).
    48874769 */
    4888 static int strchar(REGISTER struct ioarg *ap)
    4889 {
    4890     REGISTER int c;
    4891 
    4892     if (ap->aword == NULL || (c = *ap->aword++) == 0)
    4893         return (0);
    4894     return (c);
     4770static int strchar(struct ioarg *ap)
     4771{
     4772    if (ap->aword == NULL)
     4773        return 0;
     4774    return *ap->aword++;
    48954775}
    48964776
     
    48984778 * Produce quoted characters from a single word (string).
    48994779 */
    4900 static int qstrchar(REGISTER struct ioarg *ap)
    4901 {
    4902     REGISTER int c;
    4903 
    4904     if (ap->aword == NULL || (c = *ap->aword++) == 0)
    4905         return (0);
    4906     return (c | QUOTE);
     4780static int qstrchar(struct ioarg *ap)
     4781{
     4782    int c;
     4783
     4784    if (ap->aword == NULL)
     4785        return 0;
     4786    c = *ap->aword++;
     4787    if (c)
     4788        c |= QUOTE;
     4789    return c;
    49074790}
    49084791
     
    49104793 * Return the characters from a file.
    49114794 */
    4912 static int filechar(REGISTER struct ioarg *ap)
    4913 {
    4914     REGISTER int i;
     4795static int filechar(struct ioarg *ap)
     4796{
     4797    int i;
    49154798    char c;
    49164799    struct iobuf *bp = ap->afbuf;
    49174800
    49184801    if (ap->afid != AFID_NOBUF) {
    4919         if ((i = ap->afid != bp->id) || bp->bufp == bp->ebufp) {
    4920 
     4802        i = (ap->afid != bp->id);
     4803        if (i || bp->bufp == bp->ebufp) {
    49214804            if (i)
    4922                 lseek(ap->afile, ap->afpos, 0);
     4805                lseek(ap->afile, ap->afpos, SEEK_SET);
    49234806
    49244807            i = safe_read(ap->afile, bp->buf, sizeof(bp->buf));
    4925 
    49264808            if (i <= 0) {
    49274809                closef(ap->afile);
     
    49304812
    49314813            bp->id = ap->afid;
    4932             bp->ebufp = (bp->bufp = bp->buf) + i;
     4814            bp->bufp = bp->buf;
     4815            bp->ebufp = bp->bufp + i;
    49334816        }
    49344817
     
    49364819        return *bp->bufp++ & 0177;
    49374820    }
    4938 #ifdef CONFIG_FEATURE_COMMAND_EDITING
     4821#if ENABLE_FEATURE_EDITING
    49394822    if (interactive && isatty(ap->afile)) {
    4940         static char mycommand[BUFSIZ];
     4823        /* moved to G: static char filechar_cmdbuf[BUFSIZ]; */
    49414824        static int position = 0, size = 0;
    49424825
    49434826        while (size == 0 || position >= size) {
    4944             cmdedit_read_input(current_prompt, mycommand);
    4945             size = strlen(mycommand);
     4827            read_line_input(current_prompt, filechar_cmdbuf, BUFSIZ, line_input_state);
     4828            size = strlen(filechar_cmdbuf);
    49464829            position = 0;
    49474830        }
    4948         c = mycommand[position];
     4831        c = filechar_cmdbuf[position];
    49494832        position++;
    4950         return (c);
    4951     } else
     4833        return c;
     4834    }
    49524835#endif
    4953 
    4954     {
    4955         i = safe_read(ap->afile, &c, sizeof(c));
    4956         return (i == sizeof(c) ? (c & 0x7f) : (closef(ap->afile), 0));
    4957     }
     4836    i = safe_read(ap->afile, &c, sizeof(c));
     4837    return i == sizeof(c) ? (c & 0x7f) : (closef(ap->afile), 0);
    49584838}
    49594839
     
    49614841 * Return the characters from a here temp file.
    49624842 */
    4963 static int herechar(REGISTER struct ioarg *ap)
     4843static int herechar(struct ioarg *ap)
    49644844{
    49654845    char c;
    4966 
    49674846
    49684847    if (read(ap->afile, &c, sizeof(c)) != sizeof(c)) {
    49694848        close(ap->afile);
    4970         c = 0;
    4971     }
    4972     return (c);
    4973 
     4849        c = '\0';
     4850    }
     4851    return c;
    49744852}
    49754853
     
    49804858static int gravechar(struct ioarg *ap, struct io *iop)
    49814859{
    4982     REGISTER int c;
    4983 
    4984     if ((c = qgravechar(ap, iop) & ~QUOTE) == '\n')
     4860    int c;
     4861
     4862    c = qgravechar(ap, iop) & ~QUOTE;
     4863    if (c == '\n')
    49854864        c = ' ';
    4986     return (c);
    4987 }
    4988 
    4989 static int qgravechar(REGISTER struct ioarg *ap, struct io *iop)
    4990 {
    4991     REGISTER int c;
     4865    return c;
     4866}
     4867
     4868static int qgravechar(struct ioarg *ap, struct io *iop)
     4869{
     4870    int c;
    49924871
    49934872    DBGPRINTF3(("QGRAVECHAR: enter, ap=%p, iop=%p\n", ap, iop));
     
    49964875        if (iop->nlcount) {
    49974876            iop->nlcount--;
    4998             return ('\n' | QUOTE);
     4877            return '\n' | QUOTE;
    49994878        }
    50004879        c = iop->xchar;
     
    50064885        iop->xchar = c;
    50074886        if (c == 0)
    5008             return (c);
     4887            return c;
    50094888        iop->nlcount--;
    50104889        c = '\n';
    50114890    }
    5012     return (c != 0 ? c | QUOTE : 0);
     4891    return c != 0 ? c | QUOTE : 0;
    50134892}
    50144893
     
    50164895 * Return a single command (usually the first line) from a file.
    50174896 */
    5018 static int linechar(REGISTER struct ioarg *ap)
    5019 {
    5020     REGISTER int c;
    5021 
    5022     if ((c = filechar(ap)) == '\n') {
     4897static int linechar(struct ioarg *ap)
     4898{
     4899    int c;
     4900
     4901    c = filechar(ap);
     4902    if (c == '\n') {
    50234903        if (!multiline) {
    50244904            closef(ap->afile);
     
    50264906        }
    50274907    }
    5028     return (c);
    5029 }
    5030 
    5031 static void prs(REGISTER const char *s)
    5032 {
    5033     if (*s)
    5034         write(2, s, strlen(s));
    5035 }
    5036 
    5037 static void prn(unsigned u)
    5038 {
    5039     prs(itoa(u));
    5040 }
    5041 
    5042 static void closef(REGISTER int i)
    5043 {
    5044     if (i > 2)
    5045         close(i);
    5046 }
    5047 
    5048 static void closeall(void)
    5049 {
    5050     REGISTER int u;
    5051 
    5052     for (u = NUFILE; u < NOFILE;)
    5053         close(u++);
    5054 }
    5055 
     4908    return c;
     4909}
    50564910
    50574911/*
    50584912 * remap fd into Shell's fd space
    50594913 */
    5060 static int remap(REGISTER int fd)
    5061 {
    5062     REGISTER int i;
     4914static int remap(int fd)
     4915{
     4916    int i;
    50634917    int map[NOFILE];
    50644918    int newfd;
    5065 
    50664919
    50674920    DBGPRINTF(("REMAP: fd=%d, e.iofd=%d\n", fd, e.iofd));
     
    50854938    }
    50864939
    5087     return (fd);
    5088 }
    5089 
    5090 static int openpipe(REGISTER int *pv)
    5091 {
    5092     REGISTER int i;
    5093 
    5094     if ((i = pipe(pv)) < 0)
     4940    return fd;
     4941}
     4942
     4943static int openpipe(int *pv)
     4944{
     4945    int i;
     4946
     4947    i = pipe(pv);
     4948    if (i < 0)
    50954949        err("can't create pipe - try again");
    5096     return (i);
    5097 }
    5098 
    5099 static void closepipe(REGISTER int *pv)
     4950    return i;
     4951}
     4952
     4953static void closepipe(int *pv)
    51004954{
    51014955    if (pv != NULL) {
     
    51054959}
    51064960
     4961
    51074962/* -------- here.c -------- */
    51084963
     
    51114966 */
    51124967
    5113 static void markhere(REGISTER char *s, struct ioword *iop)
    5114 {
    5115     REGISTER struct here *h, *lh;
     4968static void markhere(char *s, struct ioword *iop)
     4969{
     4970    struct here *h, *lh;
    51164971
    51174972    DBGPRINTF7(("MARKHERE: enter, s=%p\n", s));
    51184973
    51194974    h = (struct here *) space(sizeof(struct here));
    5120     if (h == 0)
     4975    if (h == NULL)
    51214976        return;
    51224977
     
    51304985    if (inhere == 0)
    51314986        inhere = h;
    5132     else
    5133         for (lh = inhere; lh != NULL; lh = lh->h_next)
     4987    else {
     4988        for (lh = inhere; lh != NULL; lh = lh->h_next) {
    51344989            if (lh->h_next == 0) {
    51354990                lh->h_next = h;
    51364991                break;
    51374992            }
     4993        }
     4994    }
    51384995    iop->io_flag |= IOHERE | IOXHERE;
    5139     for (s = h->h_tag; *s; s++)
     4996    for (s = h->h_tag; *s; s++) {
    51404997        if (*s & QUOTE) {
    51414998            iop->io_flag &= ~IOXHERE;
    51424999            *s &= ~QUOTE;
    51435000        }
     5001    }
    51445002    h->h_dosub = iop->io_flag & IOXHERE;
    51455003}
     
    51475005static void gethere(void)
    51485006{
    5149     REGISTER struct here *h, *hp;
     5007    struct here *h, *hp;
    51505008
    51515009    DBGPRINTF7(("GETHERE: enter...\n"));
     
    51635021}
    51645022
    5165 static void readhere(char **name, REGISTER char *s, int ec)
     5023static void readhere(char **name, char *s, int ec)
    51665024{
    51675025    int tf;
    51685026    char tname[30] = ".msh_XXXXXX";
    5169     REGISTER int c;
     5027    int c;
    51705028    jmp_buf ev;
    51715029    char myline[LINELIM + 1];
     
    51795037
    51805038    *name = strsave(tname, areanum);
    5181     if (newenv(setjmp(errpt = ev)) != 0)
     5039    errpt = ev;
     5040    if (newenv(setjmp(errpt)) != 0)
    51825041        unlink(tname);
    51835042    else {
     
    51865045        for (;;) {
    51875046            if (interactive && e.iop <= iostack) {
    5188 #ifdef CONFIG_FEATURE_COMMAND_EDITING
     5047#if ENABLE_FEATURE_EDITING
    51895048                current_prompt = cprompt->value;
    51905049#else
     
    52245083static int herein(char *hname, int xdoll)
    52255084{
    5226     REGISTER int hf;
     5085    int hf;
    52275086    int tf;
    52285087
     
    52325091#endif
    52335092    if (hname == NULL)
    5234         return (-1);
     5093        return -1;
    52355094
    52365095    DBGPRINTF7(("HEREIN: hname is %s, xdoll=%d\n", hname, xdoll));
    52375096
    5238     hf = open(hname, 0);
     5097    hf = open(hname, O_RDONLY);
    52395098    if (hf < 0)
    5240         return (-1);
     5099        return -1;
    52415100
    52425101    if (xdoll) {
     
    52475106        tf = mkstemp(tname);
    52485107        if (tf < 0)
    5249             return (-1);
    5250         if (newenv(setjmp(errpt = ev)) == 0) {
     5108            return -1;
     5109        errpt = ev;
     5110        if (newenv(setjmp(errpt)) == 0) {
    52515111            PUSHIO(afile, hf, herechar);
    52525112            setbase(e.iop);
     
    52595119            unlink(tname);
    52605120        close(tf);
    5261         tf = open(tname, 0);
     5121        tf = open(tname, O_RDONLY);
    52625122        unlink(tname);
    5263         return (tf);
    5264     } else
    5265         return (hf);
     5123        return tf;
     5124    }
     5125    return hf;
    52665126}
    52675127
    52685128static void scraphere(void)
    52695129{
    5270     REGISTER struct here *h;
     5130    struct here *h;
    52715131
    52725132    DBGPRINTF7(("SCRAPHERE: enter...\n"));
     
    52825142static void freehere(int area)
    52835143{
    5284     REGISTER struct here *h, *hl;
     5144    struct here *h, *hl;
    52855145
    52865146    DBGPRINTF6(("FREEHERE: enter, area=%d\n", area));
     
    52995159}
    53005160
     5161
     5162/* -------- sh.c -------- */
     5163/*
     5164 * shell
     5165 */
     5166
     5167int msh_main(int argc, char **argv);
     5168int msh_main(int argc, char **argv)
     5169{
     5170    int f;
     5171    char *s;
     5172    int cflag;
     5173    char *name, **ap;
     5174    int (*iof) (struct ioarg *);
     5175
     5176    PTR_TO_GLOBALS = xzalloc(sizeof(G));
     5177    sharedbuf.id = AFID_NOBUF;
     5178    mainbuf.id = AFID_NOBUF;
     5179    e.linep = line;
     5180    elinep = line + sizeof(line) - 5;
     5181
     5182#if ENABLE_FEATURE_EDITING
     5183    line_input_state = new_line_input_t(FOR_SHELL);
     5184#endif
     5185
     5186    DBGPRINTF(("MSH_MAIN: argc %d, environ %p\n", argc, environ));
     5187
     5188    initarea();
     5189    ap = environ;
     5190    if (ap != NULL) {
     5191        while (*ap)
     5192            assign(*ap++, !COPYV);
     5193        for (ap = environ; *ap;)
     5194            export(lookup(*ap++));
     5195    }
     5196    closeall();
     5197    areanum = 1;
     5198
     5199    shell = lookup("SHELL");
     5200    if (shell->value == null)
     5201        setval(shell, (char *)DEFAULT_SHELL);
     5202    export(shell);
     5203
     5204    homedir = lookup("HOME");
     5205    if (homedir->value == null)
     5206        setval(homedir, "/");
     5207    export(homedir);
     5208
     5209    setval(lookup("$"), putn(getpid()));
     5210
     5211    path = lookup("PATH");
     5212    if (path->value == null) {
     5213        /* Can be merged with same string elsewhere in bbox */
     5214        if (geteuid() == 0)
     5215            setval(path, bb_default_root_path);
     5216        else
     5217            setval(path, bb_default_path);
     5218    }
     5219    export(path);
     5220
     5221    ifs = lookup("IFS");
     5222    if (ifs->value == null)
     5223        setval(ifs, " \t\n");
     5224
     5225#ifdef MSHDEBUG
     5226    mshdbg_var = lookup("MSHDEBUG");
     5227    if (mshdbg_var->value == null)
     5228        setval(mshdbg_var, "0");
     5229#endif
     5230
     5231    prompt = lookup("PS1");
     5232#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
     5233    if (prompt->value == null)
     5234#endif
     5235        setval(prompt, DEFAULT_USER_PROMPT);
     5236    if (geteuid() == 0) {
     5237        setval(prompt, DEFAULT_ROOT_PROMPT);
     5238        prompt->status &= ~EXPORT;
     5239    }
     5240    cprompt = lookup("PS2");
     5241#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
     5242    if (cprompt->value == null)
     5243#endif
     5244        setval(cprompt, "> ");
     5245
     5246    iof = filechar;
     5247    cflag = 0;
     5248    name = *argv++;
     5249    if (--argc >= 1) {
     5250        if (argv[0][0] == '-' && argv[0][1] != '\0') {
     5251            for (s = argv[0] + 1; *s; s++)
     5252                switch (*s) {
     5253                case 'c':
     5254                    prompt->status &= ~EXPORT;
     5255                    cprompt->status &= ~EXPORT;
     5256                    setval(prompt, "");
     5257                    setval(cprompt, "");
     5258                    cflag = 1;
     5259                    if (--argc > 0)
     5260                        PUSHIO(aword, *++argv, iof = nlchar);
     5261                    break;
     5262
     5263                case 'q':
     5264                    qflag = SIG_DFL;
     5265                    break;
     5266
     5267                case 's':
     5268                    /* standard input */
     5269                    break;
     5270
     5271                case 't':
     5272                    prompt->status &= ~EXPORT;
     5273                    setval(prompt, "");
     5274                    iof = linechar;
     5275                    break;
     5276
     5277                case 'i':
     5278                    interactive++;
     5279                default:
     5280                    if (*s >= 'a' && *s <= 'z')
     5281                        FLAG[(int) *s]++;
     5282                }
     5283        } else {
     5284            argv--;
     5285            argc++;
     5286        }
     5287
     5288        if (iof == filechar && --argc > 0) {
     5289            setval(prompt, "");
     5290            setval(cprompt, "");
     5291            prompt->status &= ~EXPORT;
     5292            cprompt->status &= ~EXPORT;
     5293
     5294/* Shell is non-interactive, activate printf-based debug */
     5295#ifdef MSHDEBUG
     5296            mshdbg = (int) (((char) (mshdbg_var->value[0])) - '0');
     5297            if (mshdbg < 0)
     5298                mshdbg = 0;
     5299#endif
     5300            DBGPRINTF(("MSH_MAIN: calling newfile()\n"));
     5301
     5302            name = *++argv;
     5303            if (newfile(name))
     5304                exit(1);        /* Exit on error */
     5305        }
     5306    }
     5307
     5308    setdash();
     5309
     5310    /* This won't be true if PUSHIO has been called, say from newfile() above */
     5311    if (e.iop < iostack) {
     5312        PUSHIO(afile, 0, iof);
     5313        if (isatty(0) && isatty(1) && !cflag) {
     5314            interactive++;
     5315#if !ENABLE_FEATURE_SH_EXTRA_QUIET
     5316#ifdef MSHDEBUG
     5317            printf("\n\n%s built-in shell (msh with debug)\n", bb_banner);
     5318#else
     5319            printf("\n\n%s built-in shell (msh)\n", bb_banner);
     5320#endif
     5321            printf("Enter 'help' for a list of built-in commands.\n\n");
     5322#endif
     5323        }
     5324    }
     5325
     5326    signal(SIGQUIT, qflag);
     5327    if (name && name[0] == '-') {
     5328        interactive++;
     5329        f = open(".profile", O_RDONLY);
     5330        if (f >= 0)
     5331            next(remap(f));
     5332        f = open("/etc/profile", O_RDONLY);
     5333        if (f >= 0)
     5334            next(remap(f));
     5335    }
     5336    if (interactive)
     5337        signal(SIGTERM, sig);
     5338
     5339    if (signal(SIGINT, SIG_IGN) != SIG_IGN)
     5340        signal(SIGINT, onintr);
     5341    dolv = argv;
     5342    dolc = argc;
     5343    dolv[0] = name;
     5344    if (dolc > 1) {
     5345        for (ap = ++argv; --argc > 0;) {
     5346            *ap = *argv++;
     5347            if (assign(*ap, !COPYV)) {
     5348                dolc--;         /* keyword */
     5349            } else {
     5350                ap++;
     5351            }
     5352        }
     5353    }
     5354    setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc));
     5355
     5356    DBGPRINTF(("MSH_MAIN: begin FOR loop, interactive %d, e.iop %p, iostack %p\n", interactive, e.iop, iostack));
     5357
     5358    for (;;) {
     5359        if (interactive && e.iop <= iostack) {
     5360#if ENABLE_FEATURE_EDITING
     5361            current_prompt = prompt->value;
     5362#else
     5363            prs(prompt->value);
     5364#endif
     5365        }
     5366        onecommand();
     5367        /* Ensure that getenv("PATH") stays current */
     5368        setenv("PATH", path->value, 1);
     5369    }
     5370
     5371    DBGPRINTF(("MSH_MAIN: returning.\n"));
     5372}
    53015373
    53025374
Note: See TracChangeset for help on using the changeset viewer.