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


Ignore:
Timestamp:
Nov 6, 2007, 11:01:53 AM (12 years ago)
Author:
Bruno Cornec
Message:
  • Better output for mindi-busybox revision
  • Remove dummy file created on NFS - report from Arnaud Tiger <arnaud.tiger_at_hp.com>
  • strace useful for debug
  • fix new versions for pb (2.0.0 for mindi and 1.7.2 for mindi-busybox)
  • fix build process for mindi-busybox + options used in that version (dd for label-partitions-as-necessary)
  • fix typo in label-partitions-as-necessary which doesn't seem to work
  • Update to busybox 1.7.2
  • perl is now required at restore time to support uuid swap partitions (and will be used for many other thigs

in the future for sure)

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

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

File:
1 edited

Legend:

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

    <
    r821 r1770  
    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;