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


Ignore:
Timestamp:
Nov 6, 2007, 11:01:53 AM (16 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;
    4619     }
    4620 }
    4621 
    4622 
    4623 /*
    4624  * Perform variable and command substitution.  If EXP_FULL is set, output CTLESC
    4625  * characters to allow for further processing.  Otherwise treat
    4626  * $@ like $* since no splitting will be performed.
    4627  */
    4628 
    4629 static void
    4630 argstr(char *p, int flag)
    4631 {
    4632     static const char spclchars[] = {
    4633         '=',
    4634         ':',
    4635         CTLQUOTEMARK,
    4636         CTLENDVAR,
    4637         CTLESC,
    4638         CTLVAR,
    4639         CTLBACKQ,
    4640         CTLBACKQ | CTLQUOTE,
    4641 #ifdef CONFIG_ASH_MATH_SUPPORT
    4642         CTLENDARI,
    4643 #endif
    4644         0
    4645     };
    4646     const char *reject = spclchars;
    4647     int c;
    4648     int quotes = flag & (EXP_FULL | EXP_CASE);      /* do CTLESC */
    4649     int breakall = flag & EXP_WORD;
    4650     int inquotes;
    4651     size_t length;
    4652     int startloc;
    4653 
    4654     if (!(flag & EXP_VARTILDE)) {
    4655         reject += 2;
    4656     } else if (flag & EXP_VARTILDE2) {
    4657         reject++;
    4658     }
    4659     inquotes = 0;
    4660     length = 0;
    4661     if (flag & EXP_TILDE) {
    4662         char *q;
    4663 
    4664         flag &= ~EXP_TILDE;
    4665 tilde:
    4666         q = p;
    4667         if (*q == CTLESC && (flag & EXP_QWORD))
    4668             q++;
    4669         if (*q == '~')
    4670             p = exptilde(p, q, flag);
    4671     }
    4672 start:
    4673     startloc = expdest - (char *)stackblock();
    4674     for (;;) {
    4675         length += strcspn(p + length, reject);
    4676         c = p[length];
    4677         if (c && (!(c & 0x80)
    4678 #ifdef CONFIG_ASH_MATH_SUPPORT
    4679                     || c == CTLENDARI
    4680 #endif
    4681            )) {
    4682             /* c == '=' || c == ':' || c == CTLENDARI */
    4683             length++;
    4684         }
    4685         if (length > 0) {
    4686             int newloc;
    4687             expdest = stnputs(p, length, expdest);
    4688             newloc = expdest - (char *)stackblock();
    4689             if (breakall && !inquotes && newloc > startloc) {
    4690                 recordregion(startloc, newloc, 0);
    4691             }
    4692             startloc = newloc;
    4693         }
    4694         p += length + 1;
    4695         length = 0;
    4696 
    4697         switch (c) {
    4698         case '\0':
    4699             goto breakloop;
    4700         case '=':
    4701             if (flag & EXP_VARTILDE2) {
    4702                 p--;
    4703                 continue;
    4704             }
    4705             flag |= EXP_VARTILDE2;
    4706             reject++;
    4707             /* fall through */
    4708         case ':':
    4709             /*
    4710              * sort of a hack - expand tildes in variable
    4711              * assignments (after the first '=' and after ':'s).
    4712              */
    4713             if (*--p == '~') {
    4714                 goto tilde;
    4715             }
    4716             continue;
    4717         }
    4718 
    4719         switch (c) {
    4720         case CTLENDVAR: /* ??? */
    4721             goto breakloop;
    4722         case CTLQUOTEMARK:
    4723             /* "$@" syntax adherence hack */
    4724             if (
    4725                 !inquotes &&
    4726                 !memcmp(p, dolatstr, DOLATSTRLEN) &&
    4727                 (p[4] == CTLQUOTEMARK || (
    4728                     p[4] == CTLENDVAR &&
    4729                     p[5] == CTLQUOTEMARK
    4730                 ))
    4731             ) {
    4732                 p = evalvar(p + 1, flag) + 1;
    4733                 goto start;
    4734             }
    4735             inquotes = !inquotes;
    4736 addquote:
    4737             if (quotes) {
    4738                 p--;
    4739                 length++;
    4740                 startloc++;
    4741             }
    4742             break;
    4743         case CTLESC:
    4744             startloc++;
    4745             length++;
    4746             goto addquote;
    4747         case CTLVAR:
    4748             p = evalvar(p, flag);
    4749             goto start;
    4750         case CTLBACKQ:
    4751             c = 0;
    4752         case CTLBACKQ|CTLQUOTE:
    4753             expbackq(argbackq->n, c, quotes);
    4754             argbackq = argbackq->next;
    4755             goto start;
    4756 #ifdef CONFIG_ASH_MATH_SUPPORT
    4757         case CTLENDARI:
    4758             p--;
    4759             expari(quotes);
    4760             goto start;
    4761 #endif
    4762         }
    4763     }
    4764 breakloop:
    4765     ;
    4766 }
    4767 
    4768 static char *
    4769 exptilde(char *startp, char *p, int flag)
    4770 {
    4771     char c;
    4772     char *name;
    4773     struct passwd *pw;
    4774     const char *home;
    4775     int quotes = flag & (EXP_FULL | EXP_CASE);
    4776     int startloc;
    4777 
    4778     name = p + 1;
    4779 
    4780     while ((c = *++p) != '\0') {
    4781         switch(c) {
    4782         case CTLESC:
    4783             return (startp);
    4784         case CTLQUOTEMARK:
    4785             return (startp);
    4786         case ':':
    4787             if (flag & EXP_VARTILDE)
    4788                 goto done;
    4789             break;
    4790         case '/':
    4791         case CTLENDVAR:
    4792             goto done;
    4793         }
    4794     }
    4795 done:
    4796     *p = '\0';
    4797     if (*name == '\0') {
    4798         home = lookupvar(homestr);
    4799     } else {
    4800         if ((pw = getpwnam(name)) == NULL)
    4801             goto lose;
    4802         home = pw->pw_dir;
    4803     }
    4804     if (!home || !*home)
    4805         goto lose;
    4806     *p = c;
    4807     startloc = expdest - (char *)stackblock();
    4808     strtodest(home, SQSYNTAX, quotes);
    4809     recordregion(startloc, expdest - (char *)stackblock(), 0);
    4810     return (p);
    4811 lose:
    4812     *p = c;
    4813     return (startp);
    4814 }
    4815 
    4816 
    4817 static void
    4818 removerecordregions(int endoff)
    4819 {
    4820     if (ifslastp == NULL)
    4821         return;
    4822 
    4823     if (ifsfirst.endoff > endoff) {
    4824         while (ifsfirst.next != NULL) {
    4825             struct ifsregion *ifsp;
    4826             INTOFF;
    4827             ifsp = ifsfirst.next->next;
    4828             ckfree(ifsfirst.next);
    4829             ifsfirst.next = ifsp;
    4830             INTON;
    4831         }
    4832         if (ifsfirst.begoff > endoff)
    4833             ifslastp = NULL;
    4834         else {
    4835             ifslastp = &ifsfirst;
    4836             ifsfirst.endoff = endoff;
    4837         }
    4838         return;
    4839     }
    4840 
    4841     ifslastp = &ifsfirst;
    4842     while (ifslastp->next && ifslastp->next->begoff < endoff)
    4843         ifslastp=ifslastp->next;
    4844     while (ifslastp->next != NULL) {
    4845         struct ifsregion *ifsp;
    4846         INTOFF;
    4847         ifsp = ifslastp->next->next;
    4848         ckfree(ifslastp->next);
    4849         ifslastp->next = ifsp;
    4850         INTON;
    4851     }
    4852     if (ifslastp->endoff > endoff)
    4853         ifslastp->endoff = endoff;
    4854 }
    4855 
    4856 
    4857 #ifdef CONFIG_ASH_MATH_SUPPORT
    4858 /*
    4859  * Expand arithmetic expression.  Backup to start of expression,
    4860  * evaluate, place result in (backed up) result, adjust string position.
    4861  */
    4862 void
    4863 expari(int quotes)
    4864 {
    4865     char *p, *start;
    4866     int begoff;
    4867     int flag;
    4868     int len;
    4869 
    4870     /*      ifsfree(); */
    4871 
    4872     /*
    4873      * This routine is slightly over-complicated for
    4874      * efficiency.  Next we scan backwards looking for the
    4875      * start of arithmetic.
    4876      */
    4877     start = stackblock();
    4878     p = expdest - 1;
    4879     *p = '\0';
    4880     p--;
    4881     do {
    4882         int esc;
    4883 
    4884         while (*p != CTLARI) {
    4885             p--;
    4886 #ifdef DEBUG
    4887             if (p < start) {
    4888                 sh_error("missing CTLARI (shouldn't happen)");
    4889             }
    4890 #endif
    4891         }
    4892 
    4893         esc = esclen(start, p);
    4894         if (!(esc % 2)) {
    4895             break;
    4896         }
    4897 
    4898         p -= esc + 1;
    4899     } while (1);
    4900 
    4901     begoff = p - start;
    4902 
    4903     removerecordregions(begoff);
    4904 
    4905     flag = p[1];
    4906 
    4907     expdest = p;
    4908 
    4909     if (quotes)
    4910         rmescapes(p + 2);
    4911 
    4912     len = cvtnum(dash_arith(p + 2));
    4913 
    4914     if (flag != '"')
    4915         recordregion(begoff, begoff + len, 0);
    4916 }
    4917 #endif
    4918 
    4919 /*
    4920  * Expand stuff in backwards quotes.
    4921  */
    4922 
    4923 static void
    4924 expbackq(union node *cmd, int quoted, int quotes)
    4925 {
    4926     struct backcmd in;
    4927     int i;
    4928     char buf[128];
    4929     char *p;
    4930     char *dest;
    4931     int startloc;
    4932     int syntax = quoted? DQSYNTAX : BASESYNTAX;
    4933     struct stackmark smark;
    4934 
    4935     INTOFF;
    4936     setstackmark(&smark);
    4937     dest = expdest;
    4938     startloc = dest - (char *)stackblock();
    4939     grabstackstr(dest);
    4940     evalbackcmd(cmd, (struct backcmd *) &in);
    4941     popstackmark(&smark);
    4942 
    4943     p = in.buf;
    4944     i = in.nleft;
    4945     if (i == 0)
    4946         goto read;
    4947     for (;;) {
    4948         memtodest(p, i, syntax, quotes);
    4949 read:
    4950         if (in.fd < 0)
    4951             break;
    4952         i = safe_read(in.fd, buf, sizeof buf);
    4953         TRACE(("expbackq: read returns %d\n", i));
    4954         if (i <= 0)
    4955             break;
    4956         p = buf;
    4957     }
    4958 
    4959     if (in.buf)
    4960         ckfree(in.buf);
    4961     if (in.fd >= 0) {
    4962         close(in.fd);
    4963         back_exitstatus = waitforjob(in.jp);
    4964     }
    4965     INTON;
    4966 
    4967     /* Eat all trailing newlines */
    4968     dest = expdest;
    4969     for (; dest > (char *)stackblock() && dest[-1] == '\n';)
    4970         STUNPUTC(dest);
    4971     expdest = dest;
    4972 
    4973     if (quoted == 0)
    4974         recordregion(startloc, dest - (char *)stackblock(), 0);
    4975     TRACE(("evalbackq: size=%d: \"%.*s\"\n",
    4976         (dest - (char *)stackblock()) - startloc,
    4977         (dest - (char *)stackblock()) - startloc,
    4978         stackblock() + startloc));
    4979 }
    4980 
    4981 
    4982 static char *
    4983 scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
    4984     int zero)
    4985 {
    4986     char *loc;
    4987     char *loc2;
    4988     char c;
    4989 
    4990     loc = startp;
    4991     loc2 = rmesc;
    4992     do {
    4993         int match;
    4994         const char *s = loc2;
    4995         c = *loc2;
    4996         if (zero) {
    4997             *loc2 = '\0';
    4998             s = rmesc;
    4999         }
    5000         match = pmatch(str, s);
    5001         *loc2 = c;
    5002         if (match)
    5003             return loc;
    5004         if (quotes && *loc == CTLESC)
    5005             loc++;
    5006         loc++;
    5007         loc2++;
    5008     } while (c);
    5009     return 0;
    5010 }
    5011 
    5012 
    5013 static char *
    5014 scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
    5015     int zero)
    5016 {
    5017     int esc = 0;
    5018     char *loc;
    5019     char *loc2;
    5020 
    5021     for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
    5022         int match;
    5023         char c = *loc2;
    5024         const char *s = loc2;
    5025         if (zero) {
    5026             *loc2 = '\0';
    5027             s = rmesc;
    5028         }
    5029         match = pmatch(str, s);
    5030         *loc2 = c;
    5031         if (match)
    5032             return loc;
    5033         loc--;
    5034         if (quotes) {
    5035             if (--esc < 0) {
    5036                 esc = esclen(startp, loc);
    5037             }
    5038             if (esc % 2) {
    5039                 esc--;
    5040                 loc--;
    5041             }
    5042         }
    5043     }
    5044     return 0;
    5045 }
    5046 
    5047 static const char *
    5048 subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
    5049 {
    5050     char *startp;
    5051     char *loc;
    5052     int saveherefd = herefd;
    5053     struct nodelist *saveargbackq = argbackq;
    5054     int amount;
    5055     char *rmesc, *rmescend;
    5056     int zero;
    5057     char *(*scan)(char *, char *, char *, char *, int , int);
    5058 
    5059     herefd = -1;
    5060     argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
    5061     STPUTC('\0', expdest);
    5062     herefd = saveherefd;
    5063     argbackq = saveargbackq;
    5064     startp = stackblock() + startloc;
    5065 
    5066     switch (subtype) {
    5067     case VSASSIGN:
    5068         setvar(str, startp, 0);
    5069         amount = startp - expdest;
    5070         STADJUST(amount, expdest);
    5071         return startp;
    5072 
    5073     case VSQUESTION:
    5074         varunset(p, str, startp, varflags);
    5075         /* NOTREACHED */
    5076     }
    5077 
    5078     subtype -= VSTRIMRIGHT;
    5079 #ifdef DEBUG
    5080     if (subtype < 0 || subtype > 3)
    5081         abort();
    5082 #endif
    5083 
    5084     rmesc = startp;
    5085     rmescend = stackblock() + strloc;
    5086     if (quotes) {
    5087         rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
    5088         if (rmesc != startp) {
    5089             rmescend = expdest;
    5090             startp = stackblock() + startloc;
    5091         }
    5092     }
    5093     rmescend--;
    5094     str = stackblock() + strloc;
    5095     preglob(str, varflags & VSQUOTE, 0);
    5096 
    5097     /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
    5098     zero = subtype >> 1;
    5099     /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
    5100     scan = (subtype & 1) ^ zero ? scanleft : scanright;
    5101 
    5102     loc = scan(startp, rmesc, rmescend, str, quotes, zero);
    5103     if (loc) {
    5104         if (zero) {
    5105             memmove(startp, loc, str - loc);
    5106             loc = startp + (str - loc) - 1;
    5107         }
    5108         *loc = '\0';
    5109         amount = loc - expdest;
    5110         STADJUST(amount, expdest);
    5111     }
    5112     return loc;
    5113 }
    5114 
    5115 
    5116 /*
    5117  * Expand a variable, and return a pointer to the next character in the
    5118  * input string.
    5119  */
    5120 static char *
    5121 evalvar(char *p, int flag)
    5122 {
    5123     int subtype;
    5124     int varflags;
    5125     char *var;
    5126     int patloc;
    5127     int c;
    5128     int startloc;
    5129     ssize_t varlen;
    5130     int easy;
    5131     int quotes;
    5132     int quoted;
    5133 
    5134     quotes = flag & (EXP_FULL | EXP_CASE);
    5135     varflags = *p++;
    5136     subtype = varflags & VSTYPE;
    5137     quoted = varflags & VSQUOTE;
    5138     var = p;
    5139     easy = (!quoted || (*var == '@' && shellparam.nparam));
    5140     startloc = expdest - (char *)stackblock();
    5141     p = strchr(p, '=') + 1;
    5142 
    5143 again:
    5144     varlen = varvalue(var, varflags, flag);
    5145     if (varflags & VSNUL)
    5146         varlen--;
    5147 
    5148     if (subtype == VSPLUS) {
    5149         varlen = -1 - varlen;
    5150         goto vsplus;
    5151     }
    5152 
    5153     if (subtype == VSMINUS) {
    5154 vsplus:
    5155         if (varlen < 0) {
    5156             argstr(
    5157                 p, flag | EXP_TILDE |
    5158                     (quoted ?  EXP_QWORD : EXP_WORD)
    5159             );
    5160             goto end;
    5161         }
    5162         if (easy)
    5163             goto record;
    5164         goto end;
    5165     }
    5166 
    5167     if (subtype == VSASSIGN || subtype == VSQUESTION) {
    5168         if (varlen < 0) {
    5169             if (subevalvar(p, var, 0, subtype, startloc,
    5170                        varflags, 0)) {
    5171                 varflags &= ~VSNUL;
    5172                 /*
    5173                  * Remove any recorded regions beyond
    5174                  * start of variable
    5175                  */
    5176                 removerecordregions(startloc);
    5177                 goto again;
    5178             }
    5179             goto end;
    5180         }
    5181         if (easy)
    5182             goto record;
    5183         goto end;
    5184     }
    5185 
    5186     if (varlen < 0 && uflag)
    5187         varunset(p, var, 0, 0);
    5188 
    5189     if (subtype == VSLENGTH) {
    5190         cvtnum(varlen > 0 ? varlen : 0);
    5191         goto record;
    5192     }
    5193 
    5194     if (subtype == VSNORMAL) {
    5195         if (!easy)
    5196             goto end;
    5197 record:
    5198         recordregion(startloc, expdest - (char *)stackblock(), quoted);
    5199         goto end;
    5200     }
    5201 
    5202 #ifdef DEBUG
    5203     switch (subtype) {
    5204     case VSTRIMLEFT:
    5205     case VSTRIMLEFTMAX:
    5206     case VSTRIMRIGHT:
    5207     case VSTRIMRIGHTMAX:
    5208         break;
    5209     default:
    5210         abort();
    5211     }
    5212 #endif
    5213 
    5214     if (varlen >= 0) {
    5215         /*
    5216          * Terminate the string and start recording the pattern
    5217          * right after it
    5218          */
    5219         STPUTC('\0', expdest);
    5220         patloc = expdest - (char *)stackblock();
    5221         if (subevalvar(p, NULL, patloc, subtype,
    5222                    startloc, varflags, quotes) == 0) {
    5223             int amount = expdest - (
    5224                 (char *)stackblock() + patloc - 1
    5225             );
    5226             STADJUST(-amount, expdest);
    5227         }
    5228         /* Remove any recorded regions beyond start of variable */
    5229         removerecordregions(startloc);
    5230         goto record;
    5231     }
    5232 
    5233 end:
    5234     if (subtype != VSNORMAL) {      /* skip to end of alternative */
    5235         int nesting = 1;
    5236         for (;;) {
    5237             if ((c = *p++) == CTLESC)
    5238                 p++;
    5239             else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
    5240                 if (varlen >= 0)
    5241                     argbackq = argbackq->next;
    5242             } else if (c == CTLVAR) {
    5243                 if ((*p++ & VSTYPE) != VSNORMAL)
    5244                     nesting++;
    5245             } else if (c == CTLENDVAR) {
    5246                 if (--nesting == 0)
    5247                     break;
    5248             }
    5249         }
    5250     }
    5251     return p;
    5252 }
    5253 
    5254 
    5255 /*
    5256  * Put a string on the stack.
    5257  */
    5258 
    5259 static void
    5260 memtodest(const char *p, size_t len, int syntax, int quotes) {
    5261     char *q = expdest;
    5262 
    5263     q = makestrspace(len * 2, q);
    5264 
    5265     while (len--) {
    5266         int c = SC2INT(*p++);
    5267         if (!c)
    5268             continue;
    5269         if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
    5270             USTPUTC(CTLESC, q);
    5271         USTPUTC(c, q);
    5272     }
    5273 
    5274     expdest = q;
    5275 }
    5276 
    5277 
    5278 static void
    5279 strtodest(const char *p, int syntax, int quotes)
    5280 {
    5281     memtodest(p, strlen(p), syntax, quotes);
    5282 }
    5283 
    5284 
    5285 /*
    5286  * Add the value of a specialized variable to the stack string.
    5287  */
    5288 
    5289 static ssize_t
    5290 varvalue(char *name, int varflags, int flags)
    5291 {
    5292     int num;
    5293     char *p;
    5294     int i;
    5295     int sep = 0;
    5296     int sepq = 0;
    5297     ssize_t len = 0;
    5298     char **ap;
    5299     int syntax;
    5300     int quoted = varflags & VSQUOTE;
    5301     int subtype = varflags & VSTYPE;
    5302     int quotes = flags & (EXP_FULL | EXP_CASE);
    5303 
    5304     if (quoted && (flags & EXP_FULL))
    5305         sep = 1 << CHAR_BIT;
    5306 
    5307     syntax = quoted ? DQSYNTAX : BASESYNTAX;
    5308     switch (*name) {
    5309     case '$':
    5310         num = rootpid;
    5311         goto numvar;
    5312     case '?':
    5313         num = exitstatus;
    5314         goto numvar;
    5315     case '#':
    5316         num = shellparam.nparam;
    5317         goto numvar;
    5318     case '!':
    5319         num = backgndpid;
    5320         if (num == 0)
    5321             return -1;
    5322 numvar:
    5323         len = cvtnum(num);
    5324         break;
    5325     case '-':
    5326         p = makestrspace(NOPTS, expdest);
    5327         for (i = NOPTS - 1; i >= 0; i--) {
    5328             if (optlist[i]) {
    5329                 USTPUTC(optletters(i), p);
    5330                 len++;
    5331             }
    5332         }
    5333         expdest = p;
    5334         break;
    5335     case '@':
    5336         if (sep)
    5337             goto param;
    5338         /* fall through */
    5339     case '*':
    5340         sep = ifsset() ? SC2INT(ifsval()[0]) : ' ';
    5341         if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))
    5342             sepq = 1;
    5343 param:
    5344         if (!(ap = shellparam.p))
    5345             return -1;
    5346         while ((p = *ap++)) {
    5347             size_t partlen;
    5348 
    5349             partlen = strlen(p);
    5350             len += partlen;
    5351 
    5352             if (!(subtype == VSPLUS || subtype == VSLENGTH))
    5353                 memtodest(p, partlen, syntax, quotes);
    5354 
    5355             if (*ap && sep) {
    5356                 char *q;
    5357 
    5358                 len++;
    5359                 if (subtype == VSPLUS || subtype == VSLENGTH) {
    5360                     continue;
    5361                 }
    5362                 q = expdest;
    5363                 if (sepq)
    5364                     STPUTC(CTLESC, q);
    5365                 STPUTC(sep, q);
    5366                 expdest = q;
    5367             }
    5368         }
    5369         return len;
    5370     case '0':
    5371     case '1':
    5372     case '2':
    5373     case '3':
    5374     case '4':
    5375     case '5':
    5376     case '6':
    5377     case '7':
    5378     case '8':
    5379     case '9':
    5380         num = atoi(name);
    5381         if (num < 0 || num > shellparam.nparam)
    5382             return -1;
    5383         p = num ? shellparam.p[num - 1] : arg0;
    5384         goto value;
    5385     default:
    5386         p = lookupvar(name);
    5387 value:
    5388         if (!p)
    5389             return -1;
    5390 
    5391         len = strlen(p);
    5392         if (!(subtype == VSPLUS || subtype == VSLENGTH))
    5393             memtodest(p, len, syntax, quotes);
    5394         return len;
    5395     }
    5396 
    5397     if (subtype == VSPLUS || subtype == VSLENGTH)
    5398         STADJUST(-len, expdest);
    5399     return len;
    5400 }
    5401 
    5402 
    5403 /*
    5404  * Record the fact that we have to scan this region of the
    5405  * string for IFS characters.
    5406  */
    5407 
    5408 static void
    5409 recordregion(int start, int end, int nulonly)
    5410 {
    5411     struct ifsregion *ifsp;
    5412 
    5413     if (ifslastp == NULL) {
    5414         ifsp = &ifsfirst;
    5415     } else {
    5416         INTOFF;
    5417         ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
    5418         ifsp->next = NULL;
    5419         ifslastp->next = ifsp;
    5420         INTON;
    5421     }
    5422     ifslastp = ifsp;
    5423     ifslastp->begoff = start;
    5424     ifslastp->endoff = end;
    5425     ifslastp->nulonly = nulonly;
    5426 }
    5427 
    5428 
    5429 /*
    5430  * Break the argument string into pieces based upon IFS and add the
    5431  * strings to the argument list.  The regions of the string to be
    5432  * searched for IFS characters have been stored by recordregion.
    5433  */
    5434 static void
    5435 ifsbreakup(char *string, struct arglist *arglist)
    5436 {
    5437     struct ifsregion *ifsp;
    5438     struct strlist *sp;
    5439     char *start;
    5440     char *p;
    5441     char *q;
    5442     const char *ifs, *realifs;
    5443     int ifsspc;
    5444     int nulonly;
    5445 
    5446 
    5447     start = string;
    5448     if (ifslastp != NULL) {
    5449         ifsspc = 0;
    5450         nulonly = 0;
    5451         realifs = ifsset() ? ifsval() : defifs;
    5452         ifsp = &ifsfirst;
    5453         do {
    5454             p = string + ifsp->begoff;
    5455             nulonly = ifsp->nulonly;
    5456             ifs = nulonly ? nullstr : realifs;
    5457             ifsspc = 0;
    5458             while (p < string + ifsp->endoff) {
    5459                 q = p;
    5460                 if (*p == CTLESC)
    5461                     p++;
    5462                 if (strchr(ifs, *p)) {
    5463                     if (!nulonly)
    5464                         ifsspc = (strchr(defifs, *p) != NULL);
    5465                     /* Ignore IFS whitespace at start */
    5466                     if (q == start && ifsspc) {
    5467                         p++;
    5468                         start = p;
    5469                         continue;
    5470                     }
    5471                     *q = '\0';
    5472                     sp = (struct strlist *)stalloc(sizeof *sp);
    5473                     sp->text = start;
    5474                     *arglist->lastp = sp;
    5475                     arglist->lastp = &sp->next;
    5476                     p++;
    5477                     if (!nulonly) {
    5478                         for (;;) {
    5479                             if (p >= string + ifsp->endoff) {
    5480                                 break;
    5481                             }
    5482                             q = p;
    5483                             if (*p == CTLESC)
    5484                                 p++;
    5485                             if (strchr(ifs, *p) == NULL ) {
    5486                                 p = q;
    5487                                 break;
    5488                             } else if (strchr(defifs, *p) == NULL) {
    5489                                 if (ifsspc) {
    5490                                     p++;
    5491                                     ifsspc = 0;
    5492                                 } else {
    5493                                     p = q;
    5494                                     break;
    5495                                 }
    5496                             } else
    5497                                 p++;
    5498                         }
    5499                     }
    5500                     start = p;
    5501                 } else
    5502                     p++;
    5503             }
    5504         } while ((ifsp = ifsp->next) != NULL);
    5505         if (nulonly)
    5506             goto add;
    5507     }
    5508 
    5509     if (!*start)
    5510         return;
    5511 
    5512 add:
    5513     sp = (struct strlist *)stalloc(sizeof *sp);
    5514     sp->text = start;
    5515     *arglist->lastp = sp;
    5516     arglist->lastp = &sp->next;
    5517 }
    5518 
    5519 static void
    5520 ifsfree(void)
    5521 {
    5522     struct ifsregion *p;
    5523 
    5524     INTOFF;
    5525     p = ifsfirst.next;
    5526     do {
    5527         struct ifsregion *ifsp;
    5528         ifsp = p->next;
    5529         ckfree(p);
    5530         p = ifsp;
    5531     } while (p);
    5532     ifslastp = NULL;
    5533     ifsfirst.next = NULL;
    5534     INTON;
    5535 }
    5536 
    5537 static void expmeta(char *, char *);
    5538 static struct strlist *expsort(struct strlist *);
    5539 static struct strlist *msort(struct strlist *, int);
    5540 
    5541 static char *expdir;
    5542 
    5543 
    5544 static void
    5545 expandmeta(struct strlist *str, int flag)
    5546 {
    5547     static const char metachars[] = {
    5548         '*', '?', '[', 0
    5549     };
    5550     /* TODO - EXP_REDIR */
    5551 
    5552     while (str) {
    5553         struct strlist **savelastp;
    5554         struct strlist *sp;
    5555         char *p;
    5556 
    5557         if (fflag)
    5558             goto nometa;
    5559         if (!strpbrk(str->text, metachars))
    5560             goto nometa;
    5561         savelastp = exparg.lastp;
    5562 
    5563         INTOFF;
    5564         p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
    5565         {
    5566             int i = strlen(str->text);
    5567             expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
    5568         }
    5569 
    5570         expmeta(expdir, p);
    5571         ckfree(expdir);
    5572         if (p != str->text)
    5573             ckfree(p);
    5574         INTON;
    5575         if (exparg.lastp == savelastp) {
    5576             /*
    5577              * no matches
    5578              */
    5579 nometa:
    5580             *exparg.lastp = str;
    5581             rmescapes(str->text);
    5582             exparg.lastp = &str->next;
    5583         } else {
    5584             *exparg.lastp = NULL;
    5585             *savelastp = sp = expsort(*savelastp);
    5586             while (sp->next != NULL)
    5587                 sp = sp->next;
    5588             exparg.lastp = &sp->next;
    5589         }
    5590         str = str->next;
    5591     }
    5592 }
    5593 
    5594 /*
    5595  * Add a file name to the list.
    5596  */
    5597 
    5598 static void
    5599 addfname(const char *name)
    5600 {
    5601     struct strlist *sp;
    5602 
    5603     sp = (struct strlist *)stalloc(sizeof *sp);
    5604     sp->text = sstrdup(name);
    5605     *exparg.lastp = sp;
    5606     exparg.lastp = &sp->next;
    5607 }
    5608 
    5609 
    5610 /*
    5611  * Do metacharacter (i.e. *, ?, [...]) expansion.
    5612  */
    5613 
    5614 static void
    5615 expmeta(char *enddir, char *name)
    5616 {
    5617     char *p;
    5618     const char *cp;
    5619     char *start;
    5620     char *endname;
    5621     int metaflag;
    5622     struct stat statb;
    5623     DIR *dirp;
    5624     struct dirent *dp;
    5625     int atend;
    5626     int matchdot;
    5627 
    5628     metaflag = 0;
    5629     start = name;
    5630     for (p = name; *p; p++) {
    5631         if (*p == '*' || *p == '?')
    5632             metaflag = 1;
    5633         else if (*p == '[') {
    5634             char *q = p + 1;
    5635             if (*q == '!')
    5636                 q++;
    5637             for (;;) {
    5638                 if (*q == '\\')
    5639                     q++;
    5640                 if (*q == '/' || *q == '\0')
    5641                     break;
    5642                 if (*++q == ']') {
    5643                     metaflag = 1;
    5644                     break;
    5645                 }
    5646             }
    5647         } else if (*p == '\\')
    5648             p++;
    5649         else if (*p == '/') {
    5650             if (metaflag)
    5651                 goto out;
    5652             start = p + 1;
    5653         }
    5654     }
    5655 out:
    5656     if (metaflag == 0) {    /* we've reached the end of the file name */
    5657         if (enddir != expdir)
    5658             metaflag++;
    5659         p = name;
    5660         do {
    5661             if (*p == '\\')
    5662                 p++;
    5663             *enddir++ = *p;
    5664         } while (*p++);
    5665         if (metaflag == 0 || lstat(expdir, &statb) >= 0)
    5666             addfname(expdir);
    5667         return;
    5668     }
    5669     endname = p;
    5670     if (name < start) {
    5671         p = name;
    5672         do {
    5673             if (*p == '\\')
    5674                 p++;
    5675             *enddir++ = *p++;
    5676         } while (p < start);
    5677     }
    5678     if (enddir == expdir) {
    5679         cp = ".";
    5680     } else if (enddir == expdir + 1 && *expdir == '/') {
    5681         cp = "/";
    5682     } else {
    5683         cp = expdir;
    5684         enddir[-1] = '\0';
    5685     }
    5686     if ((dirp = opendir(cp)) == NULL)
    5687         return;
    5688     if (enddir != expdir)
    5689         enddir[-1] = '/';
    5690     if (*endname == 0) {
    5691         atend = 1;
    5692     } else {
    5693         atend = 0;
    5694         *endname++ = '\0';
    5695     }
    5696     matchdot = 0;
    5697     p = start;
    5698     if (*p == '\\')
    5699         p++;
    5700     if (*p == '.')
    5701         matchdot++;
    5702     while (! intpending && (dp = readdir(dirp)) != NULL) {
    5703         if (dp->d_name[0] == '.' && ! matchdot)
    5704             continue;
    5705         if (pmatch(start, dp->d_name)) {
    5706             if (atend) {
    5707                 scopy(dp->d_name, enddir);
    5708                 addfname(expdir);
    5709             } else {
    5710                 for (p = enddir, cp = dp->d_name;
    5711                      (*p++ = *cp++) != '\0';)
    5712                     continue;
    5713                 p[-1] = '/';
    5714                 expmeta(p, endname);
    5715             }
    5716         }
    5717     }
    5718     closedir(dirp);
    5719     if (! atend)
    5720         endname[-1] = '/';
    5721 }
    5722 
    5723 /*
    5724  * Sort the results of file name expansion.  It calculates the number of
    5725  * strings to sort and then calls msort (short for merge sort) to do the
    5726  * work.
    5727  */
    5728 
    5729 static struct strlist *
    5730 expsort(struct strlist *str)
    5731 {
    5732     int len;
    5733     struct strlist *sp;
    5734 
    5735     len = 0;
    5736     for (sp = str ; sp ; sp = sp->next)
    5737         len++;
    5738     return msort(str, len);
    5739 }
    5740 
    5741 
    5742 static struct strlist *
    5743 msort(struct strlist *list, int len)
    5744 {
    5745     struct strlist *p, *q = NULL;
    5746     struct strlist **lpp;
    5747     int half;
    5748     int n;
    5749 
    5750     if (len <= 1)
    5751         return list;
    5752     half = len >> 1;
    5753     p = list;
    5754     for (n = half ; --n >= 0 ; ) {
    5755         q = p;
    5756         p = p->next;
    5757     }
    5758     q->next = NULL;                 /* terminate first half of list */
    5759     q = msort(list, half);          /* sort first half of list */
    5760     p = msort(p, len - half);               /* sort second half */
    5761     lpp = &list;
    5762     for (;;) {
    5763 #ifdef CONFIG_LOCALE_SUPPORT
    5764         if (strcoll(p->text, q->text) < 0)
    5765 #else
    5766         if (strcmp(p->text, q->text) < 0)
    5767 #endif
    5768                         {
    5769             *lpp = p;
    5770             lpp = &p->next;
    5771             if ((p = *lpp) == NULL) {
    5772                 *lpp = q;
    5773                 break;
    5774             }
    5775         } else {
    5776             *lpp = q;
    5777             lpp = &q->next;
    5778             if ((q = *lpp) == NULL) {
    5779                 *lpp = p;
    5780                 break;
    5781             }
    5782         }
    5783     }
    5784     return list;
    5785 }
    5786 
    5787 
    5788 /*
    5789  * Returns true if the pattern matches the string.
    5790  */
    5791 
    5792 static inline int
    5793 patmatch(char *pattern, const char *string)
    5794 {
    5795     return pmatch(preglob(pattern, 0, 0), string);
    5796 }
    5797 
    5798 
    5799 /*
    5800  * Remove any CTLESC characters from a string.
    5801  */
    5802 
    5803 static char *
    5804 _rmescapes(char *str, int flag)
    5805 {
    5806     char *p, *q, *r;
    5807     static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
    5808     unsigned inquotes;
    5809     int notescaped;
    5810     int globbing;
    5811 
    5812     p = strpbrk(str, qchars);
    5813     if (!p) {
    5814         return str;
    5815     }
    5816     q = p;
    5817     r = str;
    5818     if (flag & RMESCAPE_ALLOC) {
    5819         size_t len = p - str;
    5820         size_t fulllen = len + strlen(p) + 1;
    5821 
    5822         if (flag & RMESCAPE_GROW) {
    5823             r = makestrspace(fulllen, expdest);
    5824         } else if (flag & RMESCAPE_HEAP) {
    5825             r = ckmalloc(fulllen);
    5826         } else {
    5827             r = stalloc(fulllen);
    5828         }
    5829         q = r;
    5830         if (len > 0) {
    5831             q = mempcpy(q, str, len);
    5832         }
    5833     }
    5834     inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
    5835     globbing = flag & RMESCAPE_GLOB;
    5836     notescaped = globbing;
    5837     while (*p) {
    5838         if (*p == CTLQUOTEMARK) {
    5839             inquotes = ~inquotes;
    5840             p++;
    5841             notescaped = globbing;
    5842             continue;
    5843         }
    5844         if (*p == '\\') {
    5845             /* naked back slash */
    5846             notescaped = 0;
    5847             goto copy;
    5848         }
    5849         if (*p == CTLESC) {
    5850             p++;
    5851             if (notescaped && inquotes && *p != '/') {
    5852                 *q++ = '\\';
    5853             }
    5854         }
    5855         notescaped = globbing;
    5856 copy:
    5857         *q++ = *p++;
    5858     }
    5859     *q = '\0';
    5860     if (flag & RMESCAPE_GROW) {
    5861         expdest = r;
    5862         STADJUST(q - r + 1, expdest);
    5863     }
    5864     return r;
    5865 }
    5866 
    5867 
    5868 /*
    5869  * See if a pattern matches in a case statement.
    5870  */
    5871 
    5872 int
    5873 casematch(union node *pattern, char *val)
    5874 {
    5875     struct stackmark smark;
    5876     int result;
    5877 
    5878     setstackmark(&smark);
    5879     argbackq = pattern->narg.backquote;
    5880     STARTSTACKSTR(expdest);
    5881     ifslastp = NULL;
    5882     argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
    5883     STACKSTRNUL(expdest);
    5884     result = patmatch(stackblock(), val);
    5885     popstackmark(&smark);
    5886     return result;
    5887 }
    5888 
    5889 /*
    5890  * Our own itoa().
    5891  */
    5892 
    5893 static int
    5894 cvtnum(arith_t num)
    5895 {
    5896     int len;
    5897 
    5898     expdest = makestrspace(32, expdest);
    5899 #ifdef CONFIG_ASH_MATH_SUPPORT_64
    5900     len = fmtstr(expdest, 32, "%lld", (long long) num);
    5901 #else
    5902     len = fmtstr(expdest, 32, "%ld", num);
    5903 #endif
    5904     STADJUST(len, expdest);
    5905     return len;
    5906 }
    5907 
    5908 static void
    5909 varunset(const char *end, const char *var, const char *umsg, int varflags)
    5910 {
    5911     const char *msg;
    5912     const char *tail;
    5913 
    5914     tail = nullstr;
    5915     msg = "parameter not set";
    5916     if (umsg) {
    5917         if (*end == CTLENDVAR) {
    5918             if (varflags & VSNUL)
    5919                 tail = " or null";
    5920         } else
    5921             msg = umsg;
    5922     }
    5923     sh_error("%.*s: %s%s", end - var - 1, var, msg, tail);
    5924 }
    5925 
    5926 
    5927 /*      input.c      */
    5928 
    5929 /*
    5930  * This implements the input routines used by the parser.
    5931  */
    5932 
    5933 #define EOF_NLEFT -99           /* value of parsenleft when EOF pushed back */
    5934 
    5935 static void pushfile(void);
    5936 
    5937 /*
    5938  * Read a character from the script, returning PEOF on end of file.
    5939  * Nul characters in the input are silently discarded.
    5940  */
    5941 
    5942 
    5943 #define pgetc_as_macro()   (--parsenleft >= 0? SC2INT(*parsenextc++) : preadbuffer())
    5944 
    5945 #ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
    5946 #define pgetc_macro() pgetc()
    5947 static int
    5948 pgetc(void)
    5949 {
    5950     return pgetc_as_macro();
    5951 }
    5952 #else
    5953 #define pgetc_macro()   pgetc_as_macro()
    5954 static int
    5955 pgetc(void)
    5956 {
    5957     return pgetc_macro();
    5958 }
    5959 #endif
    5960 
    5961 
    5962 /*
    5963  * Same as pgetc(), but ignores PEOA.
    5964  */
    5965 #ifdef CONFIG_ASH_ALIAS
    5966 static int pgetc2(void)
    5967 {
    5968     int c;
    5969 
    5970     do {
    5971         c = pgetc_macro();
    5972     } while (c == PEOA);
    5973     return c;
    5974 }
    5975 #else
    5976 static inline int pgetc2(void)
    5977 {
    5978     return pgetc_macro();
    5979 }
    5980 #endif
    5981 
    5982 /*
    5983  * Read a line from the script.
    5984  */
    5985 
    5986 static inline char *
    5987 pfgets(char *line, int len)
    5988 {
    5989     char *p = line;
    5990     int nleft = len;
    5991     int c;
    5992 
    5993     while (--nleft > 0) {
    5994         c = pgetc2();
    5995         if (c == PEOF) {
    5996             if (p == line)
    5997                 return NULL;
    5998             break;
    5999         }
    6000         *p++ = c;
    6001         if (c == '\n')
    6002             break;
    6003     }
    6004     *p = '\0';
    6005     return line;
    6006 }
    6007 
    6008 
    6009 
    6010 #ifdef CONFIG_FEATURE_COMMAND_EDITING
    6011 #ifdef CONFIG_ASH_EXPAND_PRMT
    6012 static char *cmdedit_prompt;
    6013 #else
    6014 static const char *cmdedit_prompt;
    6015 #endif
    6016 static inline void putprompt(const char *s)
    6017 {
    6018 #ifdef CONFIG_ASH_EXPAND_PRMT
    6019     free(cmdedit_prompt);
    6020     cmdedit_prompt = bb_xstrdup(s);
    6021 #else
    6022     cmdedit_prompt = s;
    6023 #endif
    6024 }
    6025 #else
    6026 static inline void putprompt(const char *s)
    6027 {
    6028     out2str(s);
    6029 }
    6030 #endif
    6031 
    6032 static inline int
    6033 preadfd(void)
    6034 {
    6035     int nr;
    6036     char *buf =  parsefile->buf;
    6037     parsenextc = buf;
    6038 
    6039 retry:
    6040 #ifdef CONFIG_FEATURE_COMMAND_EDITING
    6041     if (!iflag || parsefile->fd)
    6042         nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
    6043     else {
    6044 #ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
    6045         cmdedit_path_lookup = pathval();
    6046 #endif
    6047         nr = cmdedit_read_input((char *) cmdedit_prompt, buf);
    6048         if(nr == 0) {
    6049             /* Ctrl+C presend */
    6050             if(trap[SIGINT]) {
    6051                 buf[0] = '\n';
    6052                 buf[1] = 0;
    6053                 raise(SIGINT);
    6054                 return 1;
    6055             }
    6056             goto retry;
    6057         }
    6058         if(nr < 0 && errno == 0) {
    6059             /* Ctrl+D presend */
    6060             nr = 0;
    6061         }
    6062     }
    6063 #else
    6064     nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
    6065 #endif
    6066 
    6067     if (nr < 0) {
    6068         if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
    6069             int flags = fcntl(0, F_GETFL, 0);
    6070             if (flags >= 0 && flags & O_NONBLOCK) {
    6071                 flags &=~ O_NONBLOCK;
    6072                 if (fcntl(0, F_SETFL, flags) >= 0) {
    6073                     out2str("sh: turning off NDELAY mode\n");
    6074                     goto retry;
    6075                 }
    6076             }
    6077         }
    6078     }
    6079     return nr;
    6080 }
    6081 
    6082 /*
    6083  * Refill the input buffer and return the next input character:
    6084  *
    6085  * 1) If a string was pushed back on the input, pop it;
    6086  * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
    6087  *    from a string so we can't refill the buffer, return EOF.
    6088  * 3) If the is more stuff in this buffer, use it else call read to fill it.
    6089  * 4) Process input up to the next newline, deleting nul characters.
    6090  */
    6091 
    6092 int
    6093 preadbuffer(void)
    6094 {
    6095     char *q;
    6096     int more;
    6097     char savec;
    6098 
    6099     while (parsefile->strpush) {
    6100 #ifdef CONFIG_ASH_ALIAS
    6101         if (parsenleft == -1 && parsefile->strpush->ap &&
    6102             parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
    6103             return PEOA;
    6104         }
    6105 #endif
    6106         popstring();
    6107         if (--parsenleft >= 0)
    6108             return SC2INT(*parsenextc++);
    6109     }
    6110     if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
    6111         return PEOF;
    6112     flushall();
    6113 
    6114     more = parselleft;
    6115     if (more <= 0) {
    6116 again:
    6117         if ((more = preadfd()) <= 0) {
    6118             parselleft = parsenleft = EOF_NLEFT;
    6119             return PEOF;
    6120         }
    6121     }
    6122 
    6123     q = parsenextc;
    6124 
    6125     /* delete nul characters */
    6126     for (;;) {
    6127         int c;
    6128 
    6129         more--;
    6130         c = *q;
    6131 
    6132         if (!c)
    6133             memmove(q, q + 1, more);
    6134         else {
    6135             q++;
    6136             if (c == '\n') {
    6137                 parsenleft = q - parsenextc - 1;
    6138                 break;
    6139             }
    6140         }
    6141 
    6142         if (more <= 0) {
    6143             parsenleft = q - parsenextc - 1;
    6144             if (parsenleft < 0)
    6145                 goto again;
    6146             break;
    6147         }
    6148     }
    6149     parselleft = more;
    6150 
    6151     savec = *q;
    6152     *q = '\0';
    6153 
    6154     if (vflag) {
    6155         out2str(parsenextc);
    6156     }
    6157 
    6158     *q = savec;
    6159 
    6160     return SC2INT(*parsenextc++);
    6161 }
    6162 
    6163 /*
    6164  * Undo the last call to pgetc.  Only one character may be pushed back.
    6165  * PEOF may be pushed back.
    6166  */
    6167 
    6168 void
    6169 pungetc(void)
    6170 {
    6171     parsenleft++;
    6172     parsenextc--;
    6173 }
    6174 
    6175 /*
    6176  * Push a string back onto the input at this current parsefile level.
    6177  * We handle aliases this way.
    6178  */
    6179 void
    6180 pushstring(char *s, void *ap)
    6181 {
    6182     struct strpush *sp;
    6183     size_t len;
    6184 
    6185     len = strlen(s);
    6186     INTOFF;
    6187 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
    6188     if (parsefile->strpush) {
    6189         sp = ckmalloc(sizeof (struct strpush));
    6190         sp->prev = parsefile->strpush;
    6191         parsefile->strpush = sp;
    6192     } else
    6193         sp = parsefile->strpush = &(parsefile->basestrpush);
    6194     sp->prevstring = parsenextc;
    6195     sp->prevnleft = parsenleft;
    6196 #ifdef CONFIG_ASH_ALIAS
    6197     sp->ap = (struct alias *)ap;
    6198     if (ap) {
    6199         ((struct alias *)ap)->flag |= ALIASINUSE;
    6200         sp->string = s;
    6201     }
    6202 #endif
    6203     parsenextc = s;
    6204     parsenleft = len;
    6205     INTON;
    6206 }
    6207 
    6208 void
    6209 popstring(void)
    6210 {
    6211     struct strpush *sp = parsefile->strpush;
    6212 
    6213     INTOFF;
    6214 #ifdef CONFIG_ASH_ALIAS
    6215     if (sp->ap) {
    6216         if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
    6217             checkkwd |= CHKALIAS;
    6218         }
    6219         if (sp->string != sp->ap->val) {
    6220             ckfree(sp->string);
    6221         }
    6222         sp->ap->flag &= ~ALIASINUSE;
    6223         if (sp->ap->flag & ALIASDEAD) {
    6224             unalias(sp->ap->name);
    6225         }
    6226     }
    6227 #endif
    6228     parsenextc = sp->prevstring;
    6229     parsenleft = sp->prevnleft;
    6230 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
    6231     parsefile->strpush = sp->prev;
    6232     if (sp != &(parsefile->basestrpush))
    6233         ckfree(sp);
    6234     INTON;
    6235 }
    6236 
    6237 /*
    6238  * Set the input to take input from a file.  If push is set, push the
    6239  * old input onto the stack first.
    6240  */
    6241 
    6242 static int
    6243 setinputfile(const char *fname, int flags)
    6244 {
    6245     int fd;
    6246     int fd2;
    6247 
    6248     INTOFF;
    6249     if ((fd = open(fname, O_RDONLY)) < 0) {
    6250         if (flags & INPUT_NOFILE_OK)
    6251             goto out;
    6252         sh_error("Can't open %s", fname);
    6253     }
    6254     if (fd < 10) {
    6255         fd2 = copyfd(fd, 10);
    6256         close(fd);
    6257         if (fd2 < 0)
    6258             sh_error("Out of file descriptors");
    6259         fd = fd2;
    6260     }
    6261     setinputfd(fd, flags & INPUT_PUSH_FILE);
    6262 out:
    6263     INTON;
    6264     return fd;
    6265 }
    6266 
    6267 
    6268 /*
    6269  * Like setinputfile, but takes an open file descriptor.  Call this with
    6270  * interrupts off.
    6271  */
    6272 
    6273 static void
    6274 setinputfd(int fd, int push)
    6275 {
    6276     (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
    6277     if (push) {
    6278         pushfile();
    6279         parsefile->buf = 0;
    6280     }
    6281     parsefile->fd = fd;
    6282     if (parsefile->buf == NULL)
    6283         parsefile->buf = ckmalloc(IBUFSIZ);
    6284     parselleft = parsenleft = 0;
    6285     plinno = 1;
    6286 }
    6287 
    6288 
    6289 /*
    6290  * Like setinputfile, but takes input from a string.
    6291  */
    6292 
    6293 static void
    6294 setinputstring(char *string)
    6295 {
    6296     INTOFF;
    6297     pushfile();
    6298     parsenextc = string;
    6299     parsenleft = strlen(string);
    6300     parsefile->buf = NULL;
    6301     plinno = 1;
    6302     INTON;
    6303 }
    6304 
    6305 
    6306 /*
    6307  * To handle the "." command, a stack of input files is used.  Pushfile
    6308  * adds a new entry to the stack and popfile restores the previous level.
    6309  */
    6310 
    6311 static void
    6312 pushfile(void)
    6313 {
    6314     struct parsefile *pf;
    6315 
    6316     parsefile->nleft = parsenleft;
    6317     parsefile->lleft = parselleft;
    6318     parsefile->nextc = parsenextc;
    6319     parsefile->linno = plinno;
    6320     pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
    6321     pf->prev = parsefile;
    6322     pf->fd = -1;
    6323     pf->strpush = NULL;
    6324     pf->basestrpush.prev = NULL;
    6325     parsefile = pf;
    6326 }
    6327 
    6328 
    6329 static void
    6330 popfile(void)
    6331 {
    6332     struct parsefile *pf = parsefile;
    6333 
    6334     INTOFF;
    6335     if (pf->fd >= 0)
    6336         close(pf->fd);
    6337     if (pf->buf)
    6338         ckfree(pf->buf);
    6339     while (pf->strpush)
    6340         popstring();
    6341     parsefile = pf->prev;
    6342     ckfree(pf);
    6343     parsenleft = parsefile->nleft;
    6344     parselleft = parsefile->lleft;
    6345     parsenextc = parsefile->nextc;
    6346     plinno = parsefile->linno;
    6347     INTON;
    6348 }
    6349 
    6350 
    6351 /*
    6352  * Return to top level.
    6353  */
    6354 
    6355 static void
    6356 popallfiles(void)
    6357 {
    6358     while (parsefile != &basepf)
    6359         popfile();
    6360 }
    6361 
    6362 
    6363 /*
    6364  * Close the file(s) that the shell is reading commands from.  Called
    6365  * after a fork is done.
    6366  */
    6367 
    6368 static void
    6369 closescript(void)
    6370 {
    6371     popallfiles();
    6372     if (parsefile->fd > 0) {
    6373         close(parsefile->fd);
    6374         parsefile->fd = 0;
    6375     }
    6376 }
    6377 
    6378 /*      jobs.c    */
     3239        act.sa_handler = SIG_DFL;
     3240    }
     3241    *t = action;
     3242    act.sa_flags = 0;
     3243    sigfillset(&act.sa_mask);
     3244    sigaction(signo, &act, 0);
     3245}
    63793246
    63803247/* mode flags for set_curjob */
     
    63873254#define DOWAIT_BLOCK 1
    63883255
     3256#if JOBS
     3257/* pgrp of shell on invocation */
     3258static int initialpgrp;
     3259static int ttyfd = -1;
     3260#endif
    63893261/* array of jobs */
    63903262static struct job *jobtab;
    63913263/* size of array */
    63923264static unsigned njobs;
    6393 #if JOBS
    6394 /* pgrp of shell on invocation */
    6395 static int initialpgrp;
    6396 static int ttyfd = -1;
    6397 #endif
    63983265/* current job */
    63993266static struct job *curjob;
    64003267/* number of presumed living untracked jobs */
    64013268static int jobless;
    6402 
    6403 static void set_curjob(struct job *, unsigned);
    6404 #if JOBS
    6405 static int restartjob(struct job *, int);
    6406 static void xtcsetpgrp(int, pid_t);
    6407 static char *commandtext(union node *);
    6408 static void cmdlist(union node *, int);
    6409 static void cmdtxt(union node *);
    6410 static void cmdputs(const char *);
    6411 static void showpipe(struct job *, FILE *);
    6412 #endif
    6413 static int sprint_status(char *, int, int);
    6414 static void freejob(struct job *);
    6415 static struct job *getjob(const char *, int);
    6416 static struct job *growjobtab(void);
    6417 static void forkchild(struct job *, union node *, int);
    6418 static void forkparent(struct job *, union node *, int, pid_t);
    6419 static int dowait(int, struct job *);
    6420 static int getstatus(struct job *);
    64213269
    64223270static void
     
    64403288    switch (mode) {
    64413289    default:
    6442 #ifdef DEBUG
     3290#if DEBUG
    64433291        abort();
    64443292#endif
     
    64683316}
    64693317
     3318#if JOBS || DEBUG
     3319static int
     3320jobno(const struct job *jp)
     3321{
     3322    return jp - jobtab + 1;
     3323}
     3324#endif
     3325
     3326/*
     3327 * Convert a job name to a job structure.
     3328 */
     3329static struct job *
     3330getjob(const char *name, int getctl)
     3331{
     3332    struct job *jp;
     3333    struct job *found;
     3334    const char *err_msg = "No such job: %s";
     3335    unsigned num;
     3336    int c;
     3337    const char *p;
     3338    char *(*match)(const char *, const char *);
     3339
     3340    jp = curjob;
     3341    p = name;
     3342    if (!p)
     3343        goto currentjob;
     3344
     3345    if (*p != '%')
     3346        goto err;
     3347
     3348    c = *++p;
     3349    if (!c)
     3350        goto currentjob;
     3351
     3352    if (!p[1]) {
     3353        if (c == '+' || c == '%') {
     3354 currentjob:
     3355            err_msg = "No current job";
     3356            goto check;
     3357        }
     3358        if (c == '-') {
     3359            if (jp)
     3360                jp = jp->prev_job;
     3361            err_msg = "No previous job";
     3362 check:
     3363            if (!jp)
     3364                goto err;
     3365            goto gotit;
     3366        }
     3367    }
     3368
     3369    if (is_number(p)) {
     3370        num = atoi(p);
     3371        if (num < njobs) {
     3372            jp = jobtab + num - 1;
     3373            if (jp->used)
     3374                goto gotit;
     3375            goto err;
     3376        }
     3377    }
     3378
     3379    match = prefix;
     3380    if (*p == '?') {
     3381        match = strstr;
     3382        p++;
     3383    }
     3384
     3385    found = 0;
     3386    while (1) {
     3387        if (!jp)
     3388            goto err;
     3389        if (match(jp->ps[0].cmd, p)) {
     3390            if (found)
     3391                goto err;
     3392            found = jp;
     3393            err_msg = "%s: ambiguous";
     3394        }
     3395        jp = jp->prev_job;
     3396    }
     3397
     3398 gotit:
    64703399#if JOBS
     3400    err_msg = "job %s not created under job control";
     3401    if (getctl && jp->jobctl == 0)
     3402        goto err;
     3403#endif
     3404    return jp;
     3405 err:
     3406    ash_msg_and_raise_error(err_msg, name);
     3407}
     3408
     3409/*
     3410 * Mark a job structure as unused.
     3411 */
     3412static void
     3413freejob(struct job *jp)
     3414{
     3415    struct procstat *ps;
     3416    int i;
     3417
     3418    INT_OFF;
     3419    for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
     3420        if (ps->cmd != nullstr)
     3421            free(ps->cmd);
     3422    }
     3423    if (jp->ps != &jp->ps0)
     3424        free(jp->ps);
     3425    jp->used = 0;
     3426    set_curjob(jp, CUR_DELETE);
     3427    INT_ON;
     3428}
     3429
     3430#if JOBS
     3431static void
     3432xtcsetpgrp(int fd, pid_t pgrp)
     3433{
     3434    if (tcsetpgrp(fd, pgrp))
     3435        ash_msg_and_raise_error("cannot set tty process group (%m)");
     3436}
     3437
    64713438/*
    64723439 * Turn job control on and off.
     
    64783445 * Called with interrupts off.
    64793446 */
    6480 
    6481 void
     3447static void
    64823448setjobctl(int on)
    64833449{
     
    64913457        ofd = fd = open(_PATH_TTY, O_RDWR);
    64923458        if (fd < 0) {
     3459    /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
     3460     * That sometimes helps to acquire controlling tty.
     3461     * Obviously, a workaround for bugs when someone
     3462     * failed to provide a controlling tty to bash! :) */
    64933463            fd += 3;
    64943464            while (!isatty(fd) && --fd >= 0)
     
    65013471        fcntl(fd, F_SETFD, FD_CLOEXEC);
    65023472        do { /* while we are in the background */
    6503             if ((pgrp = tcgetpgrp(fd)) < 0) {
    6504 out:
    6505                 sh_warnx("can't access tty; job control turned off");
     3473            pgrp = tcgetpgrp(fd);
     3474            if (pgrp < 0) {
     3475 out:
     3476                ash_msg("can't access tty; job control turned off");
    65063477                mflag = on = 0;
    65073478                goto close;
     
    65233494        fd = ttyfd;
    65243495        pgrp = initialpgrp;
    6525         xtcsetpgrp(fd, pgrp);
     3496        /* was xtcsetpgrp, but this can make exiting ash
     3497         * with pty already deleted loop forever */
     3498        tcsetpgrp(fd, pgrp);
    65263499        setpgid(0, pgrp);
    65273500        setsignal(SIGTSTP);
    65283501        setsignal(SIGTTOU);
    65293502        setsignal(SIGTTIN);
    6530 close:
     3503 close:
    65313504        close(fd);
    65323505        fd = -1;
     
    65393512killcmd(int argc, char **argv)
    65403513{
    6541     int signo = -1;
    6542     int list = 0;
    6543     int i;
    6544     pid_t pid;
    6545     struct job *jp;
    6546 
    6547     if (argc <= 1) {
    6548 usage:
    6549         sh_error(
    6550 "Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
    6551 "kill -l [exitstatus]"
    6552         );
    6553     }
    6554 
    6555     if (**++argv == '-') {
    6556         signo = decode_signal(*argv + 1, 1);
    6557         if (signo < 0) {
    6558             int c;
    6559 
    6560             while ((c = nextopt("ls:")) != '\0')
    6561                 switch (c) {
    6562                 default:
    6563 #ifdef DEBUG
    6564                     abort();
    6565 #endif
    6566                 case 'l':
    6567                     list = 1;
    6568                     break;
    6569                 case 's':
    6570                     signo = decode_signal(optionarg, 1);
    6571                     if (signo < 0) {
    6572                         sh_error(
    6573                             "invalid signal number or name: %s",
    6574                             optionarg
    6575                         );
    6576                     }
    6577                     break;
    6578                 }
    6579             argv = argptr;
    6580         } else
    6581             argv++;
    6582     }
    6583 
    6584     if (!list && signo < 0)
    6585         signo = SIGTERM;
    6586 
    6587     if ((signo < 0 || !*argv) ^ list) {
    6588         goto usage;
    6589     }
    6590 
    6591     if (list) {
    6592         const char *name;
    6593 
    6594         if (!*argv) {
    6595             for (i = 1; i < NSIG; i++) {
    6596                 name = u_signal_names(0, &i, 1);
    6597                 if (name)
    6598                     out1fmt(snlfmt, name);
     3514    if (argv[1] && strcmp(argv[1], "-l") != 0) {
     3515        int i = 1;
     3516        do {
     3517            if (argv[i][0] == '%') {
     3518                struct job *jp = getjob(argv[i], 0);
     3519                unsigned pid = jp->ps[0].pid;
     3520                /* Enough space for ' -NNN<nul>' */
     3521                argv[i] = alloca(sizeof(int)*3 + 3);
     3522                /* kill_main has matching code to expect
     3523                 * leading space. Needed to not confuse
     3524                 * negative pids with "kill -SIGNAL_NO" syntax */
     3525                sprintf(argv[i], " -%u", pid);
    65993526            }
    6600             return 0;
    6601         }
    6602         name = u_signal_names(*argptr, &signo, -1);
    6603         if (name)
    6604             out1fmt(snlfmt, name);
    6605         else
    6606             sh_error("invalid signal number or exit status: %s", *argptr);
    6607         return 0;
    6608     }
    6609 
    6610     i = 0;
    6611     do {
    6612         if (**argv == '%') {
    6613             jp = getjob(*argv, 0);
    6614             pid = -jp->ps[0].pid;
    6615         } else {
    6616             pid = **argv == '-' ?
    6617                 -number(*argv + 1) : number(*argv);
    6618         }
    6619         if (kill(pid, signo) != 0) {
    6620             sh_warnx("(%d) - %m", pid);
    6621             i = 1;
    6622         }
    6623     } while (*++argv);
    6624 
    6625     return i;
    6626 }
    6627 #endif /* JOBS */
    6628 
    6629 #if defined(JOBS) || defined(DEBUG)
    6630 static int
    6631 jobno(const struct job *jp)
    6632 {
    6633     return jp - jobtab + 1;
    6634 }
    6635 #endif
    6636 
    6637 #if JOBS
    6638 static int
    6639 fgcmd(int argc, char **argv)
    6640 {
    6641     struct job *jp;
    6642     FILE *out;
    6643     int mode;
    6644     int retval;
    6645 
    6646     mode = (**argv == 'f') ? FORK_FG : FORK_BG;
    6647     nextopt(nullstr);
    6648     argv = argptr;
    6649     out = stdout;
    6650     do {
    6651         jp = getjob(*argv, 1);
    6652         if (mode == FORK_BG) {
    6653             set_curjob(jp, CUR_RUNNING);
    6654             fprintf(out, "[%d] ", jobno(jp));
    6655         }
    6656         outstr(jp->ps->cmd, out);
    6657         showpipe(jp, out);
    6658         retval = restartjob(jp, mode);
    6659     } while (*argv && *++argv);
    6660     return retval;
    6661 }
    6662 
    6663 static int bgcmd(int, char **) __attribute__((__alias__("fgcmd")));
     3527        } while (argv[++i]);
     3528    }
     3529    return kill_main(argc, argv);
     3530}
     3531
     3532static void
     3533showpipe(struct job *jp, FILE *out)
     3534{
     3535    struct procstat *sp;
     3536    struct procstat *spend;
     3537
     3538    spend = jp->ps + jp->nprocs;
     3539    for (sp = jp->ps + 1; sp < spend; sp++)
     3540        fprintf(out, " | %s", sp->cmd);
     3541    outcslow('\n', out);
     3542    flush_stdout_stderr();
     3543}
    66643544
    66653545
     
    66723552    pid_t pgid;
    66733553
    6674     INTOFF;
     3554    INT_OFF;
    66753555    if (jp->state == JOBDONE)
    66763556        goto out;
     
    66863566            ps->status = -1;
    66873567        }
    6688     } while (ps++, --i);
    6689 out:
     3568        ps++;
     3569    } while (--i);
     3570 out:
    66903571    status = (mode == FORK_FG) ? waitforjob(jp) : 0;
    6691     INTON;
     3572    INT_ON;
    66923573    return status;
     3574}
     3575
     3576static int
     3577fg_bgcmd(int argc, char **argv)
     3578{
     3579    struct job *jp;
     3580    FILE *out;
     3581    int mode;
     3582    int retval;
     3583
     3584    mode = (**argv == 'f') ? FORK_FG : FORK_BG;
     3585    nextopt(nullstr);
     3586    argv = argptr;
     3587    out = stdout;
     3588    do {
     3589        jp = getjob(*argv, 1);
     3590        if (mode == FORK_BG) {
     3591            set_curjob(jp, CUR_RUNNING);
     3592            fprintf(out, "[%d] ", jobno(jp));
     3593        }
     3594        outstr(jp->ps->cmd, out);
     3595        showpipe(jp, out);
     3596        retval = restartjob(jp, mode);
     3597    } while (*argv && *++argv);
     3598    return retval;
    66933599}
    66943600#endif
     
    67283634            col = fmtstr(s, 16, "Done");
    67293635    }
    6730 
    6731 out:
     3636 out:
    67323637    return col;
    67333638}
    6734 
    6735 #if JOBS
    6736 static void
    6737 showjob(FILE *out, struct job *jp, int mode)
    6738 {
    6739     struct procstat *ps;
    6740     struct procstat *psend;
    6741     int col;
    6742     int indent;
    6743     char s[80];
    6744 
    6745     ps = jp->ps;
    6746 
    6747     if (mode & SHOW_PGID) {
    6748         /* just output process (group) id of pipeline */
    6749         fprintf(out, "%d\n", ps->pid);
    6750         return;
    6751     }
    6752 
    6753     col = fmtstr(s, 16, "[%d]   ", jobno(jp));
    6754     indent = col;
    6755 
    6756     if (jp == curjob)
    6757         s[col - 2] = '+';
    6758     else if (curjob && jp == curjob->prev_job)
    6759         s[col - 2] = '-';
    6760 
    6761     if (mode & SHOW_PID)
    6762         col += fmtstr(s + col, 16, "%d ", ps->pid);
    6763 
    6764     psend = ps + jp->nprocs;
    6765 
    6766     if (jp->state == JOBRUNNING) {
    6767         scopy("Running", s + col);
    6768         col += strlen("Running");
    6769     } else {
    6770         int status = psend[-1].status;
    6771 #if JOBS
    6772         if (jp->state == JOBSTOPPED)
    6773             status = jp->stopstatus;
    6774 #endif
    6775         col += sprint_status(s + col, status, 0);
    6776     }
    6777 
    6778     goto start;
    6779 
    6780     do {
    6781         /* for each process */
    6782         col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;
    6783 
    6784 start:
    6785         fprintf(out, "%s%*c%s",
    6786             s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
    6787         );
    6788         if (!(mode & SHOW_PID)) {
    6789             showpipe(jp, out);
    6790             break;
    6791         }
    6792         if (++ps == psend) {
    6793             outcslow('\n', out);
    6794             break;
    6795         }
    6796     } while (1);
    6797 
    6798     jp->changed = 0;
    6799 
    6800     if (jp->state == JOBDONE) {
    6801         TRACE(("showjob: freeing job %d\n", jobno(jp)));
    6802         freejob(jp);
    6803     }
    6804 }
    6805 
    6806 
    6807 static int
    6808 jobscmd(int argc, char **argv)
    6809 {
    6810     int mode, m;
    6811     FILE *out;
    6812 
    6813     mode = 0;
    6814     while ((m = nextopt("lp")))
    6815         if (m == 'l')
    6816             mode = SHOW_PID;
    6817         else
    6818             mode = SHOW_PGID;
    6819 
    6820     out = stdout;
    6821     argv = argptr;
    6822     if (*argv)
    6823         do
    6824             showjob(out, getjob(*argv,0), mode);
    6825         while (*++argv);
    6826     else
    6827         showjobs(out, mode);
    6828 
    6829     return 0;
    6830 }
    6831 
    6832 
    6833 /*
    6834  * Print a list of jobs.  If "change" is nonzero, only print jobs whose
    6835  * statuses have changed since the last call to showjobs.
    6836  */
    6837 
    6838 static void
    6839 showjobs(FILE *out, int mode)
    6840 {
    6841     struct job *jp;
    6842 
    6843     TRACE(("showjobs(%x) called\n", mode));
    6844 
    6845     /* If not even one one job changed, there is nothing to do */
    6846     while (dowait(DOWAIT_NORMAL, NULL) > 0)
    6847         continue;
    6848 
    6849     for (jp = curjob; jp; jp = jp->prev_job) {
    6850         if (!(mode & SHOW_CHANGED) || jp->changed)
    6851             showjob(out, jp, mode);
    6852     }
    6853 }
    6854 #endif /* JOBS */
    6855 
    6856 /*
    6857  * Mark a job structure as unused.
    6858  */
    6859 
    6860 static void
    6861 freejob(struct job *jp)
    6862 {
    6863     struct procstat *ps;
    6864     int i;
    6865 
    6866     INTOFF;
    6867     for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
    6868         if (ps->cmd != nullstr)
    6869             ckfree(ps->cmd);
    6870     }
    6871     if (jp->ps != &jp->ps0)
    6872         ckfree(jp->ps);
    6873     jp->used = 0;
    6874     set_curjob(jp, CUR_DELETE);
    6875     INTON;
    6876 }
    6877 
    6878 
    6879 static int
    6880 waitcmd(int argc, char **argv)
    6881 {
    6882     struct job *job;
    6883     int retval;
    6884     struct job *jp;
    6885 
    6886     EXSIGON();
    6887 
    6888     nextopt(nullstr);
    6889     retval = 0;
    6890 
    6891     argv = argptr;
    6892     if (!*argv) {
    6893         /* wait for all jobs */
    6894         for (;;) {
    6895             jp = curjob;
    6896             while (1) {
    6897                 if (!jp) {
    6898                     /* no running procs */
    6899                     goto out;
    6900                 }
    6901                 if (jp->state == JOBRUNNING)
    6902                     break;
    6903                 jp->waited = 1;
    6904                 jp = jp->prev_job;
    6905             }
    6906             dowait(DOWAIT_BLOCK, 0);
    6907         }
    6908     }
    6909 
    6910     retval = 127;
    6911     do {
    6912         if (**argv != '%') {
    6913             pid_t pid = number(*argv);
    6914             job = curjob;
    6915             goto start;
    6916             do {
    6917                 if (job->ps[job->nprocs - 1].pid == pid)
    6918                     break;
    6919                 job = job->prev_job;
    6920 start:
    6921                 if (!job)
    6922                     goto repeat;
    6923             } while (1);
    6924         } else
    6925             job = getjob(*argv, 0);
    6926         /* loop until process terminated or stopped */
    6927         while (job->state == JOBRUNNING)
    6928             dowait(DOWAIT_BLOCK, 0);
    6929         job->waited = 1;
    6930         retval = getstatus(job);
    6931 repeat:
    6932         ;
    6933     } while (*++argv);
    6934 
    6935 out:
    6936     return retval;
    6937 }
    6938 
    6939 
    6940 /*
    6941  * Convert a job name to a job structure.
    6942  */
    6943 
    6944 static struct job *
    6945 getjob(const char *name, int getctl)
    6946 {
    6947     struct job *jp;
    6948     struct job *found;
    6949     const char *err_msg = "No such job: %s";
    6950     unsigned num;
    6951     int c;
    6952     const char *p;
    6953     char *(*match)(const char *, const char *);
    6954 
    6955     jp = curjob;
    6956     p = name;
    6957     if (!p)
    6958         goto currentjob;
    6959 
    6960     if (*p != '%')
    6961         goto err;
    6962 
    6963     c = *++p;
    6964     if (!c)
    6965         goto currentjob;
    6966 
    6967     if (!p[1]) {
    6968         if (c == '+' || c == '%') {
    6969 currentjob:
    6970             err_msg = "No current job";
    6971             goto check;
    6972         } else if (c == '-') {
    6973             if (jp)
    6974                 jp = jp->prev_job;
    6975             err_msg = "No previous job";
    6976 check:
    6977             if (!jp)
    6978                 goto err;
    6979             goto gotit;
    6980         }
    6981     }
    6982 
    6983     if (is_number(p)) {
    6984         num = atoi(p);
    6985         if (num < njobs) {
    6986             jp = jobtab + num - 1;
    6987             if (jp->used)
    6988                 goto gotit;
    6989             goto err;
    6990         }
    6991     }
    6992 
    6993     match = prefix;
    6994     if (*p == '?') {
    6995         match = strstr;
    6996         p++;
    6997     }
    6998 
    6999     found = 0;
    7000     while (1) {
    7001         if (!jp)
    7002             goto err;
    7003         if (match(jp->ps[0].cmd, p)) {
    7004             if (found)
    7005                 goto err;
    7006             found = jp;
    7007             err_msg = "%s: ambiguous";
    7008         }
    7009         jp = jp->prev_job;
    7010     }
    7011 
    7012 gotit:
    7013 #if JOBS
    7014     err_msg = "job %s not created under job control";
    7015     if (getctl && jp->jobctl == 0)
    7016         goto err;
    7017 #endif
    7018     return jp;
    7019 err:
    7020     sh_error(err_msg, name);
    7021 }
    7022 
    7023 
    7024 /*
    7025  * Return a new job structure.
    7026  * Called with interrupts off.
    7027  */
    7028 
    7029 static struct job *
    7030 makejob(union node *node, int nprocs)
    7031 {
    7032     int i;
    7033     struct job *jp;
    7034 
    7035     for (i = njobs, jp = jobtab ; ; jp++) {
    7036         if (--i < 0) {
    7037             jp = growjobtab();
    7038             break;
    7039         }
    7040         if (jp->used == 0)
    7041             break;
    7042         if (jp->state != JOBDONE || !jp->waited)
    7043             continue;
    7044 #if JOBS
    7045         if (jobctl)
    7046             continue;
    7047 #endif
    7048         freejob(jp);
    7049         break;
    7050     }
    7051     memset(jp, 0, sizeof(*jp));
    7052 #if JOBS
    7053     if (jobctl)
    7054         jp->jobctl = 1;
    7055 #endif
    7056     jp->prev_job = curjob;
    7057     curjob = jp;
    7058     jp->used = 1;
    7059     jp->ps = &jp->ps0;
    7060     if (nprocs > 1) {
    7061         jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
    7062     }
    7063     TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
    7064         jobno(jp)));
    7065     return jp;
    7066 }
    7067 
    7068 static struct job *
    7069 growjobtab(void)
    7070 {
    7071     size_t len;
    7072     ptrdiff_t offset;
    7073     struct job *jp, *jq;
    7074 
    7075     len = njobs * sizeof(*jp);
    7076     jq = jobtab;
    7077     jp = ckrealloc(jq, len + 4 * sizeof(*jp));
    7078 
    7079     offset = (char *)jp - (char *)jq;
    7080     if (offset) {
    7081         /* Relocate pointers */
    7082         size_t l = len;
    7083 
    7084         jq = (struct job *)((char *)jq + l);
    7085         while (l) {
    7086             l -= sizeof(*jp);
    7087             jq--;
    7088 #define joff(p) ((struct job *)((char *)(p) + l))
    7089 #define jmove(p) (p) = (void *)((char *)(p) + offset)
    7090             if (xlikely(joff(jp)->ps == &jq->ps0))
    7091                 jmove(joff(jp)->ps);
    7092             if (joff(jp)->prev_job)
    7093                 jmove(joff(jp)->prev_job);
    7094         }
    7095         if (curjob)
    7096             jmove(curjob);
    7097 #undef joff
    7098 #undef jmove
    7099     }
    7100 
    7101     njobs += 4;
    7102     jobtab = jp;
    7103     jp = (struct job *)((char *)jp + len);
    7104     jq = jp + 3;
    7105     do {
    7106         jq->used = 0;
    7107     } while (--jq >= jp);
    7108     return jp;
    7109 }
    7110 
    7111 
    7112 /*
    7113  * Fork off a subshell.  If we are doing job control, give the subshell its
    7114  * own process group.  Jp is a job structure that the job is to be added to.
    7115  * N is the command that will be evaluated by the child.  Both jp and n may
    7116  * be NULL.  The mode parameter can be one of the following:
    7117  *      FORK_FG - Fork off a foreground process.
    7118  *      FORK_BG - Fork off a background process.
    7119  *      FORK_NOJOB - Like FORK_FG, but don't give the process its own
    7120  *                   process group even if job control is on.
    7121  *
    7122  * When job control is turned off, background processes have their standard
    7123  * input redirected to /dev/null (except for the second and later processes
    7124  * in a pipeline).
    7125  *
    7126  * Called with interrupts off.
    7127  */
    7128 
    7129 static inline void
    7130 forkchild(struct job *jp, union node *n, int mode)
    7131 {
    7132     int oldlvl;
    7133 
    7134     TRACE(("Child shell %d\n", getpid()));
    7135     oldlvl = shlvl;
    7136     shlvl++;
    7137 
    7138     closescript();
    7139     clear_traps();
    7140 #if JOBS
    7141     /* do job control only in root shell */
    7142     jobctl = 0;
    7143     if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) {
    7144         pid_t pgrp;
    7145 
    7146         if (jp->nprocs == 0)
    7147             pgrp = getpid();
    7148         else
    7149             pgrp = jp->ps[0].pid;
    7150         /* This can fail because we are doing it in the parent also */
    7151         (void)setpgid(0, pgrp);
    7152         if (mode == FORK_FG)
    7153             xtcsetpgrp(ttyfd, pgrp);
    7154         setsignal(SIGTSTP);
    7155         setsignal(SIGTTOU);
    7156     } else
    7157 #endif
    7158     if (mode == FORK_BG) {
    7159         ignoresig(SIGINT);
    7160         ignoresig(SIGQUIT);
    7161         if (jp->nprocs == 0) {
    7162             close(0);
    7163             if (open(bb_dev_null, O_RDONLY) != 0)
    7164                 sh_error("Can't open %s", bb_dev_null);
    7165         }
    7166     }
    7167     if (!oldlvl && iflag) {
    7168         setsignal(SIGINT);
    7169         setsignal(SIGQUIT);
    7170         setsignal(SIGTERM);
    7171     }
    7172     for (jp = curjob; jp; jp = jp->prev_job)
    7173         freejob(jp);
    7174     jobless = 0;
    7175 }
    7176 
    7177 static inline void
    7178 forkparent(struct job *jp, union node *n, int mode, pid_t pid)
    7179 {
    7180     TRACE(("In parent shell:  child = %d\n", pid));
    7181     if (!jp) {
    7182         while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
    7183         jobless++;
    7184         return;
    7185     }
    7186 #if JOBS
    7187     if (mode != FORK_NOJOB && jp->jobctl) {
    7188         int pgrp;
    7189 
    7190         if (jp->nprocs == 0)
    7191             pgrp = pid;
    7192         else
    7193             pgrp = jp->ps[0].pid;
    7194         /* This can fail because we are doing it in the child also */
    7195         (void)setpgid(pid, pgrp);
    7196     }
    7197 #endif
    7198     if (mode == FORK_BG) {
    7199         backgndpid = pid;               /* set $! */
    7200         set_curjob(jp, CUR_RUNNING);
    7201     }
    7202     if (jp) {
    7203         struct procstat *ps = &jp->ps[jp->nprocs++];
    7204         ps->pid = pid;
    7205         ps->status = -1;
    7206         ps->cmd = nullstr;
    7207 #if JOBS
    7208         if (jobctl && n)
    7209             ps->cmd = commandtext(n);
    7210 #endif
    7211     }
    7212 }
    7213 
    7214 static int
    7215 forkshell(struct job *jp, union node *n, int mode)
    7216 {
    7217     int pid;
    7218 
    7219     TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
    7220     pid = fork();
    7221     if (pid < 0) {
    7222         TRACE(("Fork failed, errno=%d", errno));
    7223         if (jp)
    7224             freejob(jp);
    7225         sh_error("Cannot fork");
    7226     }
    7227     if (pid == 0)
    7228         forkchild(jp, n, mode);
    7229     else
    7230         forkparent(jp, n, mode, pid);
    7231     return pid;
    7232 }
    7233 
    7234 /*
    7235  * Wait for job to finish.
    7236  *
    7237  * Under job control we have the problem that while a child process is
    7238  * running interrupts generated by the user are sent to the child but not
    7239  * to the shell.  This means that an infinite loop started by an inter-
    7240  * active user may be hard to kill.  With job control turned off, an
    7241  * interactive user may place an interactive program inside a loop.  If
    7242  * the interactive program catches interrupts, the user doesn't want
    7243  * these interrupts to also abort the loop.  The approach we take here
    7244  * is to have the shell ignore interrupt signals while waiting for a
    7245  * foreground process to terminate, and then send itself an interrupt
    7246  * signal if the child process was terminated by an interrupt signal.
    7247  * Unfortunately, some programs want to do a bit of cleanup and then
    7248  * exit on interrupt; unless these processes terminate themselves by
    7249  * sending a signal to themselves (instead of calling exit) they will
    7250  * confuse this approach.
    7251  *
    7252  * Called with interrupts off.
    7253  */
    7254 
    7255 int
    7256 waitforjob(struct job *jp)
    7257 {
    7258     int st;
    7259 
    7260     TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
    7261     while (jp->state == JOBRUNNING) {
    7262         dowait(DOWAIT_BLOCK, jp);
    7263     }
    7264     st = getstatus(jp);
    7265 #if JOBS
    7266     if (jp->jobctl) {
    7267         xtcsetpgrp(ttyfd, rootpid);
    7268         /*
    7269          * This is truly gross.
    7270          * If we're doing job control, then we did a TIOCSPGRP which
    7271          * caused us (the shell) to no longer be in the controlling
    7272          * session -- so we wouldn't have seen any ^C/SIGINT.  So, we
    7273          * intuit from the subprocess exit status whether a SIGINT
    7274          * occurred, and if so interrupt ourselves.  Yuck.  - mycroft
    7275          */
    7276         if (jp->sigint)
    7277             raise(SIGINT);
    7278     }
    7279     if (jp->state == JOBDONE)
    7280 #endif
    7281         freejob(jp);
    7282     return st;
    7283 }
    7284 
    72853639
    72863640/*
     
    73123666 * and the jobs command may give out of date information.
    73133667 */
    7314 
    7315 static inline int
     3668static int
    73163669waitproc(int block, int *status)
    73173670{
     
    73303683 * Wait for a process to terminate.
    73313684 */
    7332 
    73333685static int
    73343686dowait(int block, struct job *job)
     
    73453697    if (pid <= 0)
    73463698        return pid;
    7347     INTOFF;
     3699    INT_OFF;
    73483700    thisjob = NULL;
    73493701    for (jp = curjob; jp; jp = jp->prev_job) {
     
    73573709        do {
    73583710            if (sp->pid == pid) {
    7359                 TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->status, status));
     3711                TRACE(("Job %d: changing status of proc %d "
     3712                    "from 0x%x to 0x%x\n",
     3713                    jobno(jp), pid, sp->status, status));
    73603714                sp->status = status;
    73613715                thisjob = jp;
     
    73823736    goto out;
    73833737
    7384 gotjob:
     3738 gotjob:
    73853739    if (state != JOBRUNNING) {
    73863740        thisjob->changed = 1;
    73873741
    73883742        if (thisjob->state != state) {
    7389             TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state));
     3743            TRACE(("Job %d: changing state from %d to %d\n",
     3744                jobno(thisjob), thisjob->state, state));
    73903745            thisjob->state = state;
    73913746#if JOBS
     
    73973752    }
    73983753
    7399 out:
    7400     INTON;
     3754 out:
     3755    INT_ON;
    74013756
    74023757    if (thisjob && thisjob == job) {
     
    74143769}
    74153770
    7416 
    7417 /*
    7418  * return 1 if there are stopped jobs, otherwise 0
    7419  */
    7420 
    7421 int
    7422 stoppedjobs(void)
     3771#if JOBS
     3772static void
     3773showjob(FILE *out, struct job *jp, int mode)
     3774{
     3775    struct procstat *ps;
     3776    struct procstat *psend;
     3777    int col;
     3778    int indent_col;
     3779    char s[80];
     3780
     3781    ps = jp->ps;
     3782
     3783    if (mode & SHOW_PGID) {
     3784        /* just output process (group) id of pipeline */
     3785        fprintf(out, "%d\n", ps->pid);
     3786        return;
     3787    }
     3788
     3789    col = fmtstr(s, 16, "[%d]   ", jobno(jp));
     3790    indent_col = col;
     3791
     3792    if (jp == curjob)
     3793        s[col - 2] = '+';
     3794    else if (curjob && jp == curjob->prev_job)
     3795        s[col - 2] = '-';
     3796
     3797    if (mode & SHOW_PID)
     3798        col += fmtstr(s + col, 16, "%d ", ps->pid);
     3799
     3800    psend = ps + jp->nprocs;
     3801
     3802    if (jp->state == JOBRUNNING) {
     3803        strcpy(s + col, "Running");
     3804        col += sizeof("Running") - 1;
     3805    } else {
     3806        int status = psend[-1].status;
     3807        if (jp->state == JOBSTOPPED)
     3808            status = jp->stopstatus;
     3809        col += sprint_status(s + col, status, 0);
     3810    }
     3811
     3812    goto start;
     3813
     3814    do {
     3815        /* for each process */
     3816        col = fmtstr(s, 48, " |\n%*c%d ", indent_col, ' ', ps->pid) - 3;
     3817 start:
     3818        fprintf(out, "%s%*c%s",
     3819            s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
     3820        );
     3821        if (!(mode & SHOW_PID)) {
     3822            showpipe(jp, out);
     3823            break;
     3824        }
     3825        if (++ps == psend) {
     3826            outcslow('\n', out);
     3827            break;
     3828        }
     3829    } while (1);
     3830
     3831    jp->changed = 0;
     3832
     3833    if (jp->state == JOBDONE) {
     3834        TRACE(("showjob: freeing job %d\n", jobno(jp)));
     3835        freejob(jp);
     3836    }
     3837}
     3838
     3839/*
     3840 * Print a list of jobs.  If "change" is nonzero, only print jobs whose
     3841 * statuses have changed since the last call to showjobs.
     3842 */
     3843static void
     3844showjobs(FILE *out, int mode)
    74233845{
    74243846    struct job *jp;
     3847
     3848    TRACE(("showjobs(%x) called\n", mode));
     3849
     3850    /* If not even one one job changed, there is nothing to do */
     3851    while (dowait(DOWAIT_NORMAL, NULL) > 0)
     3852        continue;
     3853
     3854    for (jp = curjob; jp; jp = jp->prev_job) {
     3855        if (!(mode & SHOW_CHANGED) || jp->changed) {
     3856            showjob(out, jp, mode);
     3857        }
     3858    }
     3859}
     3860
     3861static int
     3862jobscmd(int argc, char **argv)
     3863{
     3864    int mode, m;
     3865
     3866    mode = 0;
     3867    while ((m = nextopt("lp"))) {
     3868        if (m == 'l')
     3869            mode = SHOW_PID;
     3870        else
     3871            mode = SHOW_PGID;
     3872    }
     3873
     3874    argv = argptr;
     3875    if (*argv) {
     3876        do
     3877            showjob(stdout, getjob(*argv,0), mode);
     3878        while (*++argv);
     3879    } else
     3880        showjobs(stdout, mode);
     3881
     3882    return 0;
     3883}
     3884#endif /* JOBS */
     3885
     3886static int
     3887getstatus(struct job *job)
     3888{
     3889    int status;
    74253890    int retval;
    74263891
     3892    status = job->ps[job->nprocs - 1].status;
     3893    retval = WEXITSTATUS(status);
     3894    if (!WIFEXITED(status)) {
     3895#if JOBS
     3896        retval = WSTOPSIG(status);
     3897        if (!WIFSTOPPED(status))
     3898#endif
     3899        {
     3900            /* XXX: limits number of signals */
     3901            retval = WTERMSIG(status);
     3902#if JOBS
     3903            if (retval == SIGINT)
     3904                job->sigint = 1;
     3905#endif
     3906        }
     3907        retval += 128;
     3908    }
     3909    TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
     3910        jobno(job), job->nprocs, status, retval));
     3911    return retval;
     3912}
     3913
     3914static int
     3915waitcmd(int argc, char **argv)
     3916{
     3917    struct job *job;
     3918    int retval;
     3919    struct job *jp;
     3920
     3921    EXSIGON;
     3922
     3923    nextopt(nullstr);
    74273924    retval = 0;
    7428     if (job_warning)
    7429         goto out;
    7430     jp = curjob;
    7431     if (jp && jp->state == JOBSTOPPED) {
    7432         out2str("You have stopped jobs.\n");
    7433         job_warning = 2;
    7434         retval++;
    7435     }
    7436 
    7437 out:
     3925
     3926    argv = argptr;
     3927    if (!*argv) {
     3928        /* wait for all jobs */
     3929        for (;;) {
     3930            jp = curjob;
     3931            while (1) {
     3932                if (!jp) {
     3933                    /* no running procs */
     3934                    goto out;
     3935                }
     3936                if (jp->state == JOBRUNNING)
     3937                    break;
     3938                jp->waited = 1;
     3939                jp = jp->prev_job;
     3940            }
     3941            dowait(DOWAIT_BLOCK, 0);
     3942        }
     3943    }
     3944
     3945    retval = 127;
     3946    do {
     3947        if (**argv != '%') {
     3948            pid_t pid = number(*argv);
     3949            job = curjob;
     3950            goto start;
     3951            do {
     3952                if (job->ps[job->nprocs - 1].pid == pid)
     3953                    break;
     3954                job = job->prev_job;
     3955 start:
     3956                if (!job)
     3957                    goto repeat;
     3958            } while (1);
     3959        } else
     3960            job = getjob(*argv, 0);
     3961        /* loop until process terminated or stopped */
     3962        while (job->state == JOBRUNNING)
     3963            dowait(DOWAIT_BLOCK, 0);
     3964        job->waited = 1;
     3965        retval = getstatus(job);
     3966 repeat:
     3967        ;
     3968    } while (*++argv);
     3969
     3970 out:
    74383971    return retval;
    74393972}
    74403973
     3974static struct job *
     3975growjobtab(void)
     3976{
     3977    size_t len;
     3978    ptrdiff_t offset;
     3979    struct job *jp, *jq;
     3980
     3981    len = njobs * sizeof(*jp);
     3982    jq = jobtab;
     3983    jp = ckrealloc(jq, len + 4 * sizeof(*jp));
     3984
     3985    offset = (char *)jp - (char *)jq;
     3986    if (offset) {
     3987        /* Relocate pointers */
     3988        size_t l = len;
     3989
     3990        jq = (struct job *)((char *)jq + l);
     3991        while (l) {
     3992            l -= sizeof(*jp);
     3993            jq--;
     3994#define joff(p) ((struct job *)((char *)(p) + l))
     3995#define jmove(p) (p) = (void *)((char *)(p) + offset)
     3996            if (joff(jp)->ps == &jq->ps0)
     3997                jmove(joff(jp)->ps);
     3998            if (joff(jp)->prev_job)
     3999                jmove(joff(jp)->prev_job);
     4000        }
     4001        if (curjob)
     4002            jmove(curjob);
     4003#undef joff
     4004#undef jmove
     4005    }
     4006
     4007    njobs += 4;
     4008    jobtab = jp;
     4009    jp = (struct job *)((char *)jp + len);
     4010    jq = jp + 3;
     4011    do {
     4012        jq->used = 0;
     4013    } while (--jq >= jp);
     4014    return jp;
     4015}
     4016
     4017/*
     4018 * Return a new job structure.
     4019 * Called with interrupts off.
     4020 */
     4021static struct job *
     4022makejob(union node *node, int nprocs)
     4023{
     4024    int i;
     4025    struct job *jp;
     4026
     4027    for (i = njobs, jp = jobtab; ; jp++) {
     4028        if (--i < 0) {
     4029            jp = growjobtab();
     4030            break;
     4031        }
     4032        if (jp->used == 0)
     4033            break;
     4034        if (jp->state != JOBDONE || !jp->waited)
     4035            continue;
     4036#if JOBS
     4037        if (jobctl)
     4038            continue;
     4039#endif
     4040        freejob(jp);
     4041        break;
     4042    }
     4043    memset(jp, 0, sizeof(*jp));
     4044#if JOBS
     4045    /* jp->jobctl is a bitfield.
     4046     * "jp->jobctl |= jobctl" likely to give awful code */
     4047    if (jobctl)
     4048        jp->jobctl = 1;
     4049#endif
     4050    jp->prev_job = curjob;
     4051    curjob = jp;
     4052    jp->used = 1;
     4053    jp->ps = &jp->ps0;
     4054    if (nprocs > 1) {
     4055        jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
     4056    }
     4057    TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
     4058                jobno(jp)));
     4059    return jp;
     4060}
     4061
     4062#if JOBS
    74414063/*
    74424064 * Return a string identifying a command (to be printed by the
    74434065 * jobs command).
    74444066 */
    7445 
    7446 #if JOBS
    74474067static char *cmdnextc;
    7448 
    7449 static char *
    7450 commandtext(union node *n)
    7451 {
    7452     char *name;
    7453 
    7454     STARTSTACKSTR(cmdnextc);
    7455     cmdtxt(n);
    7456     name = stackblock();
    7457     TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
    7458         name, cmdnextc, cmdnextc));
    7459     return savestr(name);
    7460 }
    7461 
    7462 static void
    7463 cmdtxt(union node *n)
    7464 {
    7465     union node *np;
    7466     struct nodelist *lp;
    7467     const char *p;
    7468     char s[2];
    7469 
    7470     if (!n)
    7471         return;
    7472     switch (n->type) {
    7473     default:
    7474 #if DEBUG
    7475         abort();
    7476 #endif
    7477     case NPIPE:
    7478         lp = n->npipe.cmdlist;
    7479         for (;;) {
    7480             cmdtxt(lp->n);
    7481             lp = lp->next;
    7482             if (!lp)
    7483                 break;
    7484             cmdputs(" | ");
    7485         }
    7486         break;
    7487     case NSEMI:
    7488         p = "; ";
    7489         goto binop;
    7490     case NAND:
    7491         p = " && ";
    7492         goto binop;
    7493     case NOR:
    7494         p = " || ";
    7495 binop:
    7496         cmdtxt(n->nbinary.ch1);
    7497         cmdputs(p);
    7498         n = n->nbinary.ch2;
    7499         goto donode;
    7500     case NREDIR:
    7501     case NBACKGND:
    7502         n = n->nredir.n;
    7503         goto donode;
    7504     case NNOT:
    7505         cmdputs("!");
    7506         n = n->nnot.com;
    7507 donode:
    7508         cmdtxt(n);
    7509         break;
    7510     case NIF:
    7511         cmdputs("if ");
    7512         cmdtxt(n->nif.test);
    7513         cmdputs("; then ");
    7514         n = n->nif.ifpart;
    7515         if (n->nif.elsepart) {
    7516             cmdtxt(n);
    7517             cmdputs("; else ");
    7518             n = n->nif.elsepart;
    7519         }
    7520         p = "; fi";
    7521         goto dotail;
    7522     case NSUBSHELL:
    7523         cmdputs("(");
    7524         n = n->nredir.n;
    7525         p = ")";
    7526         goto dotail;
    7527     case NWHILE:
    7528         p = "while ";
    7529         goto until;
    7530     case NUNTIL:
    7531         p = "until ";
    7532 until:
    7533         cmdputs(p);
    7534         cmdtxt(n->nbinary.ch1);
    7535         n = n->nbinary.ch2;
    7536         p = "; done";
    7537 dodo:
    7538         cmdputs("; do ");
    7539 dotail:
    7540         cmdtxt(n);
    7541         goto dotail2;
    7542     case NFOR:
    7543         cmdputs("for ");
    7544         cmdputs(n->nfor.var);
    7545         cmdputs(" in ");
    7546         cmdlist(n->nfor.args, 1);
    7547         n = n->nfor.body;
    7548         p = "; done";
    7549         goto dodo;
    7550     case NDEFUN:
    7551         cmdputs(n->narg.text);
    7552         p = "() { ... }";
    7553         goto dotail2;
    7554     case NCMD:
    7555         cmdlist(n->ncmd.args, 1);
    7556         cmdlist(n->ncmd.redirect, 0);
    7557         break;
    7558     case NARG:
    7559         p = n->narg.text;
    7560 dotail2:
    7561         cmdputs(p);
    7562         break;
    7563     case NHERE:
    7564     case NXHERE:
    7565         p = "<<...";
    7566         goto dotail2;
    7567     case NCASE:
    7568         cmdputs("case ");
    7569         cmdputs(n->ncase.expr->narg.text);
    7570         cmdputs(" in ");
    7571         for (np = n->ncase.cases; np; np = np->nclist.next) {
    7572             cmdtxt(np->nclist.pattern);
    7573             cmdputs(") ");
    7574             cmdtxt(np->nclist.body);
    7575             cmdputs(";; ");
    7576         }
    7577         p = "esac";
    7578         goto dotail2;
    7579     case NTO:
    7580         p = ">";
    7581         goto redir;
    7582     case NCLOBBER:
    7583         p = ">|";
    7584         goto redir;
    7585     case NAPPEND:
    7586         p = ">>";
    7587         goto redir;
    7588     case NTOFD:
    7589         p = ">&";
    7590         goto redir;
    7591     case NFROM:
    7592         p = "<";
    7593         goto redir;
    7594     case NFROMFD:
    7595         p = "<&";
    7596         goto redir;
    7597     case NFROMTO:
    7598         p = "<>";
    7599 redir:
    7600         s[0] = n->nfile.fd + '0';
    7601         s[1] = '\0';
    7602         cmdputs(s);
    7603         cmdputs(p);
    7604         if (n->type == NTOFD || n->type == NFROMFD) {
    7605             s[0] = n->ndup.dupfd + '0';
    7606             p = s;
    7607             goto dotail2;
    7608         } else {
    7609             n = n->nfile.fname;
    7610             goto donode;
    7611         }
    7612     }
    7613 }
    7614 
    7615 static void
    7616 cmdlist(union node *np, int sep)
    7617 {
    7618     for (; np; np = np->narg.next) {
    7619         if (!sep)
    7620             cmdputs(spcstr);
    7621         cmdtxt(np);
    7622         if (sep && np->narg.next)
    7623             cmdputs(spcstr);
    7624     }
    7625 }
    76264068
    76274069static void
     
    76374079        "%", "%%", "#", "##"
    76384080    };
     4081
    76394082    nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
    76404083    p = s;
     
    76514094            else
    76524095                str = "${";
    7653             if (!(subtype & VSQUOTE) != !(quoted & 1)) {
    7654                 quoted ^= 1;
    7655                 c = '"';
    7656             } else
     4096            if (!(subtype & VSQUOTE) == !(quoted & 1))
    76574097                goto dostr;
     4098            quoted ^= 1;
     4099            c = '"';
    76584100            break;
    76594101        case CTLENDVAR:
     
    76684110            str = "\"$(...)\"";
    76694111            goto dostr;
    7670 #ifdef CONFIG_ASH_MATH_SUPPORT
     4112#if ENABLE_ASH_MATH_SUPPORT
    76714113        case CTLARI:
    76724114            str = "$((";
     
    77044146        }
    77054147        USTPUTC(c, nextc);
    7706 checkstr:
     4148 checkstr:
    77074149        if (!str)
    77084150            continue;
    7709 dostr:
     4151 dostr:
    77104152        while ((c = *str++)) {
    77114153            USTPUTC(c, nextc);
     
    77194161}
    77204162
    7721 
    7722 static void
    7723 showpipe(struct job *jp, FILE *out)
    7724 {
    7725     struct procstat *sp;
    7726     struct procstat *spend;
    7727 
    7728     spend = jp->ps + jp->nprocs;
    7729     for (sp = jp->ps + 1; sp < spend; sp++)
    7730         fprintf(out, " | %s", sp->cmd);
    7731     outcslow('\n', out);
    7732     flushall();
    7733 }
    7734 
    7735 static void
    7736 xtcsetpgrp(int fd, pid_t pgrp)
    7737 {
    7738     if (tcsetpgrp(fd, pgrp))
    7739         sh_error("Cannot set tty process group (%m)");
     4163/* cmdtxt() and cmdlist() call each other */
     4164static void cmdtxt(union node *n);
     4165
     4166static void
     4167cmdlist(union node *np, int sep)
     4168{
     4169    for (; np; np = np->narg.next) {
     4170        if (!sep)
     4171            cmdputs(" ");
     4172        cmdtxt(np);
     4173        if (sep && np->narg.next)
     4174            cmdputs(" ");
     4175    }
     4176}
     4177
     4178static void
     4179cmdtxt(union node *n)
     4180{
     4181    union node *np;
     4182    struct nodelist *lp;
     4183    const char *p;
     4184    char s[2];
     4185
     4186    if (!n)
     4187        return;
     4188    switch (n->type) {
     4189    default:
     4190#if DEBUG
     4191        abort();
     4192#endif
     4193    case NPIPE:
     4194        lp = n->npipe.cmdlist;
     4195        for (;;) {
     4196            cmdtxt(lp->n);
     4197            lp = lp->next;
     4198            if (!lp)
     4199                break;
     4200            cmdputs(" | ");
     4201        }
     4202        break;
     4203    case NSEMI:
     4204        p = "; ";
     4205        goto binop;
     4206    case NAND:
     4207        p = " && ";
     4208        goto binop;
     4209    case NOR:
     4210        p = " || ";
     4211 binop:
     4212        cmdtxt(n->nbinary.ch1);
     4213        cmdputs(p);
     4214        n = n->nbinary.ch2;
     4215        goto donode;
     4216    case NREDIR:
     4217    case NBACKGND:
     4218        n = n->nredir.n;
     4219        goto donode;
     4220    case NNOT:
     4221        cmdputs("!");
     4222        n = n->nnot.com;
     4223 donode:
     4224        cmdtxt(n);
     4225        break;
     4226    case NIF:
     4227        cmdputs("if ");
     4228        cmdtxt(n->nif.test);
     4229        cmdputs("; then ");
     4230        n = n->nif.ifpart;
     4231        if (n->nif.elsepart) {
     4232            cmdtxt(n);
     4233            cmdputs("; else ");
     4234            n = n->nif.elsepart;
     4235        }
     4236        p = "; fi";
     4237        goto dotail;
     4238    case NSUBSHELL:
     4239        cmdputs("(");
     4240        n = n->nredir.n;
     4241        p = ")";
     4242        goto dotail;
     4243    case NWHILE:
     4244        p = "while ";
     4245        goto until;
     4246    case NUNTIL:
     4247        p = "until ";
     4248 until:
     4249        cmdputs(p);
     4250        cmdtxt(n->nbinary.ch1);
     4251        n = n->nbinary.ch2;
     4252        p = "; done";
     4253 dodo:
     4254        cmdputs("; do ");
     4255 dotail:
     4256        cmdtxt(n);
     4257        goto dotail2;
     4258    case NFOR:
     4259        cmdputs("for ");
     4260        cmdputs(n->nfor.var);
     4261        cmdputs(" in ");
     4262        cmdlist(n->nfor.args, 1);
     4263        n = n->nfor.body;
     4264        p = "; done";
     4265        goto dodo;
     4266    case NDEFUN:
     4267        cmdputs(n->narg.text);
     4268        p = "() { ... }";
     4269        goto dotail2;
     4270    case NCMD:
     4271        cmdlist(n->ncmd.args, 1);
     4272        cmdlist(n->ncmd.redirect, 0);
     4273        break;
     4274    case NARG:
     4275        p = n->narg.text;
     4276 dotail2:
     4277        cmdputs(p);
     4278        break;
     4279    case NHERE:
     4280    case NXHERE:
     4281        p = "<<...";
     4282        goto dotail2;
     4283    case NCASE:
     4284        cmdputs("case ");
     4285        cmdputs(n->ncase.expr->narg.text);
     4286        cmdputs(" in ");
     4287        for (np = n->ncase.cases; np; np = np->nclist.next) {
     4288            cmdtxt(np->nclist.pattern);
     4289            cmdputs(") ");
     4290            cmdtxt(np->nclist.body);
     4291            cmdputs(";; ");
     4292        }
     4293        p = "esac";
     4294        goto dotail2;
     4295    case NTO:
     4296        p = ">";
     4297        goto redir;
     4298    case NCLOBBER:
     4299        p = ">|";
     4300        goto redir;
     4301    case NAPPEND:
     4302        p = ">>";
     4303        goto redir;
     4304    case NTOFD:
     4305        p = ">&";
     4306        goto redir;
     4307    case NFROM:
     4308        p = "<";
     4309        goto redir;
     4310    case NFROMFD:
     4311        p = "<&";
     4312        goto redir;
     4313    case NFROMTO:
     4314        p = "<>";
     4315 redir:
     4316        s[0] = n->nfile.fd + '0';
     4317        s[1] = '\0';
     4318        cmdputs(s);
     4319        cmdputs(p);
     4320        if (n->type == NTOFD || n->type == NFROMFD) {
     4321            s[0] = n->ndup.dupfd + '0';
     4322            p = s;
     4323            goto dotail2;
     4324        }
     4325        n = n->nfile.fname;
     4326        goto donode;
     4327    }
     4328}
     4329
     4330static char *
     4331commandtext(union node *n)
     4332{
     4333    char *name;
     4334
     4335    STARTSTACKSTR(cmdnextc);
     4336    cmdtxt(n);
     4337    name = stackblock();
     4338    TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
     4339            name, cmdnextc, cmdnextc));
     4340    return ckstrdup(name);
    77404341}
    77414342#endif /* JOBS */
    77424343
     4344/*
     4345 * Fork off a subshell.  If we are doing job control, give the subshell its
     4346 * own process group.  Jp is a job structure that the job is to be added to.
     4347 * N is the command that will be evaluated by the child.  Both jp and n may
     4348 * be NULL.  The mode parameter can be one of the following:
     4349 *      FORK_FG - Fork off a foreground process.
     4350 *      FORK_BG - Fork off a background process.
     4351 *      FORK_NOJOB - Like FORK_FG, but don't give the process its own
     4352 *                   process group even if job control is on.
     4353 *
     4354 * When job control is turned off, background processes have their standard
     4355 * input redirected to /dev/null (except for the second and later processes
     4356 * in a pipeline).
     4357 *
     4358 * Called with interrupts off.
     4359 */
     4360/*
     4361 * Clear traps on a fork.
     4362 */
     4363static void
     4364clear_traps(void)
     4365{
     4366    char **tp;
     4367
     4368    for (tp = trap; tp < &trap[NSIG]; tp++) {
     4369        if (*tp && **tp) {      /* trap not NULL or SIG_IGN */
     4370            INT_OFF;
     4371            free(*tp);
     4372            *tp = NULL;
     4373            if (tp != &trap[0])
     4374                setsignal(tp - trap);
     4375            INT_ON;
     4376        }
     4377    }
     4378}
     4379
     4380/* Lives far away from here, needed for forkchild */
     4381static void closescript(void);
     4382/* Called after fork(), in child */
     4383static void
     4384forkchild(struct job *jp, union node *n, int mode)
     4385{
     4386    int oldlvl;
     4387
     4388    TRACE(("Child shell %d\n", getpid()));
     4389    oldlvl = shlvl;
     4390    shlvl++;
     4391
     4392    closescript();
     4393    clear_traps();
     4394#if JOBS
     4395    /* do job control only in root shell */
     4396    jobctl = 0;
     4397    if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) {
     4398        pid_t pgrp;
     4399
     4400        if (jp->nprocs == 0)
     4401            pgrp = getpid();
     4402        else
     4403            pgrp = jp->ps[0].pid;
     4404        /* This can fail because we are doing it in the parent also */
     4405        (void)setpgid(0, pgrp);
     4406        if (mode == FORK_FG)
     4407            xtcsetpgrp(ttyfd, pgrp);
     4408        setsignal(SIGTSTP);
     4409        setsignal(SIGTTOU);
     4410    } else
     4411#endif
     4412    if (mode == FORK_BG) {
     4413        ignoresig(SIGINT);
     4414        ignoresig(SIGQUIT);
     4415        if (jp->nprocs == 0) {
     4416            close(0);
     4417            if (open(bb_dev_null, O_RDONLY) != 0)
     4418                ash_msg_and_raise_error("can't open %s", bb_dev_null);
     4419        }
     4420    }
     4421    if (!oldlvl && iflag) {
     4422        setsignal(SIGINT);
     4423        setsignal(SIGQUIT);
     4424        setsignal(SIGTERM);
     4425    }
     4426#if JOBS
     4427    /* For "jobs | cat" to work like in bash, we must retain list of jobs
     4428     * in child, but we do need to remove ourself */
     4429    if (jp)
     4430        freejob(jp);
     4431#else
     4432    for (jp = curjob; jp; jp = jp->prev_job)
     4433        freejob(jp);
     4434#endif
     4435    jobless = 0;
     4436}
     4437
     4438/* Called after fork(), in parent */
     4439static void
     4440forkparent(struct job *jp, union node *n, int mode, pid_t pid)
     4441{
     4442    TRACE(("In parent shell: child = %d\n", pid));
     4443    if (!jp) {
     4444        while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
     4445        jobless++;
     4446        return;
     4447    }
     4448#if JOBS
     4449    if (mode != FORK_NOJOB && jp->jobctl) {
     4450        int pgrp;
     4451
     4452        if (jp->nprocs == 0)
     4453            pgrp = pid;
     4454        else
     4455            pgrp = jp->ps[0].pid;
     4456        /* This can fail because we are doing it in the child also */
     4457        setpgid(pid, pgrp);
     4458    }
     4459#endif
     4460    if (mode == FORK_BG) {
     4461        backgndpid = pid;               /* set $! */
     4462        set_curjob(jp, CUR_RUNNING);
     4463    }
     4464    if (jp) {
     4465        struct procstat *ps = &jp->ps[jp->nprocs++];
     4466        ps->pid = pid;
     4467        ps->status = -1;
     4468        ps->cmd = nullstr;
     4469#if JOBS
     4470        if (jobctl && n)
     4471            ps->cmd = commandtext(n);
     4472#endif
     4473    }
     4474}
     4475
    77434476static int
    7744 getstatus(struct job *job) {
     4477forkshell(struct job *jp, union node *n, int mode)
     4478{
     4479    int pid;
     4480
     4481    TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
     4482    pid = fork();
     4483    if (pid < 0) {
     4484        TRACE(("Fork failed, errno=%d", errno));
     4485        if (jp)
     4486            freejob(jp);
     4487        ash_msg_and_raise_error("cannot fork");
     4488    }
     4489    if (pid == 0)
     4490        forkchild(jp, n, mode);
     4491    else
     4492        forkparent(jp, n, mode, pid);
     4493    return pid;
     4494}
     4495
     4496/*
     4497 * Wait for job to finish.
     4498 *
     4499 * Under job control we have the problem that while a child process is
     4500 * running interrupts generated by the user are sent to the child but not
     4501 * to the shell.  This means that an infinite loop started by an inter-
     4502 * active user may be hard to kill.  With job control turned off, an
     4503 * interactive user may place an interactive program inside a loop.  If
     4504 * the interactive program catches interrupts, the user doesn't want
     4505 * these interrupts to also abort the loop.  The approach we take here
     4506 * is to have the shell ignore interrupt signals while waiting for a
     4507 * foreground process to terminate, and then send itself an interrupt
     4508 * signal if the child process was terminated by an interrupt signal.
     4509 * Unfortunately, some programs want to do a bit of cleanup and then
     4510 * exit on interrupt; unless these processes terminate themselves by
     4511 * sending a signal to themselves (instead of calling exit) they will
     4512 * confuse this approach.
     4513 *
     4514 * Called with interrupts off.
     4515 */
     4516static int
     4517waitforjob(struct job *jp)
     4518{
     4519    int st;
     4520
     4521    TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
     4522    while (jp->state == JOBRUNNING) {
     4523        dowait(DOWAIT_BLOCK, jp);
     4524    }
     4525    st = getstatus(jp);
     4526#if JOBS
     4527    if (jp->jobctl) {
     4528        xtcsetpgrp(ttyfd, rootpid);
     4529        /*
     4530         * This is truly gross.
     4531         * If we're doing job control, then we did a TIOCSPGRP which
     4532         * caused us (the shell) to no longer be in the controlling
     4533         * session -- so we wouldn't have seen any ^C/SIGINT.  So, we
     4534         * intuit from the subprocess exit status whether a SIGINT
     4535         * occurred, and if so interrupt ourselves.  Yuck.  - mycroft
     4536         */
     4537        if (jp->sigint)
     4538            raise(SIGINT);
     4539    }
     4540    if (jp->state == JOBDONE)
     4541#endif
     4542        freejob(jp);
     4543    return st;
     4544}
     4545
     4546/*
     4547 * return 1 if there are stopped jobs, otherwise 0
     4548 */
     4549static int
     4550stoppedjobs(void)
     4551{
     4552    struct job *jp;
     4553    int retval;
     4554
     4555    retval = 0;
     4556    if (job_warning)
     4557        goto out;
     4558    jp = curjob;
     4559    if (jp && jp->state == JOBSTOPPED) {
     4560        out2str("You have stopped jobs.\n");
     4561        job_warning = 2;
     4562        retval++;
     4563    }
     4564 out:
     4565    return retval;
     4566}
     4567
     4568
     4569/* ============ redir.c
     4570 *
     4571 * Code for dealing with input/output redirection.
     4572 */
     4573
     4574#define EMPTY -2                /* marks an unused slot in redirtab */
     4575#ifndef PIPE_BUF
     4576# define PIPESIZE 4096          /* amount of buffering in a pipe */
     4577#else
     4578# define PIPESIZE PIPE_BUF
     4579#endif
     4580
     4581/*
     4582 * Open a file in noclobber mode.
     4583 * The code was copied from bash.
     4584 */
     4585static int
     4586noclobberopen(const char *fname)
     4587{
     4588    int r, fd;
     4589    struct stat finfo, finfo2;
     4590
     4591    /*
     4592     * If the file exists and is a regular file, return an error
     4593     * immediately.
     4594     */
     4595    r = stat(fname, &finfo);
     4596    if (r == 0 && S_ISREG(finfo.st_mode)) {
     4597        errno = EEXIST;
     4598        return -1;
     4599    }
     4600
     4601    /*
     4602     * If the file was not present (r != 0), make sure we open it
     4603     * exclusively so that if it is created before we open it, our open
     4604     * will fail.  Make sure that we do not truncate an existing file.
     4605     * Note that we don't turn on O_EXCL unless the stat failed -- if the
     4606     * file was not a regular file, we leave O_EXCL off.
     4607     */
     4608    if (r != 0)
     4609        return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
     4610    fd = open(fname, O_WRONLY|O_CREAT, 0666);
     4611
     4612    /* If the open failed, return the file descriptor right away. */
     4613    if (fd < 0)
     4614        return fd;
     4615
     4616    /*
     4617     * OK, the open succeeded, but the file may have been changed from a
     4618     * non-regular file to a regular file between the stat and the open.
     4619     * We are assuming that the O_EXCL open handles the case where FILENAME
     4620     * did not exist and is symlinked to an existing file between the stat
     4621     * and open.
     4622     */
     4623
     4624    /*
     4625     * If we can open it and fstat the file descriptor, and neither check
     4626     * revealed that it was a regular file, and the file has not been
     4627     * replaced, return the file descriptor.
     4628     */
     4629    if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode)
     4630     && finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
     4631        return fd;
     4632
     4633    /* The file has been replaced.  badness. */
     4634    close(fd);
     4635    errno = EEXIST;
     4636    return -1;
     4637}
     4638
     4639/*
     4640 * Handle here documents.  Normally we fork off a process to write the
     4641 * data to a pipe.  If the document is short, we can stuff the data in
     4642 * the pipe without forking.
     4643 */
     4644/* openhere needs this forward reference */
     4645static void expandhere(union node *arg, int fd);
     4646static int
     4647openhere(union node *redir)
     4648{
     4649    int pip[2];
     4650    size_t len = 0;
     4651
     4652    if (pipe(pip) < 0)
     4653        ash_msg_and_raise_error("pipe call failed");
     4654    if (redir->type == NHERE) {
     4655        len = strlen(redir->nhere.doc->narg.text);
     4656        if (len <= PIPESIZE) {
     4657            full_write(pip[1], redir->nhere.doc->narg.text, len);
     4658            goto out;
     4659        }
     4660    }
     4661    if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
     4662        close(pip[0]);
     4663        signal(SIGINT, SIG_IGN);
     4664        signal(SIGQUIT, SIG_IGN);
     4665        signal(SIGHUP, SIG_IGN);
     4666#ifdef SIGTSTP
     4667        signal(SIGTSTP, SIG_IGN);
     4668#endif
     4669        signal(SIGPIPE, SIG_DFL);
     4670        if (redir->type == NHERE)
     4671            full_write(pip[1], redir->nhere.doc->narg.text, len);
     4672        else
     4673            expandhere(redir->nhere.doc, pip[1]);
     4674        _exit(0);
     4675    }
     4676 out:
     4677    close(pip[1]);
     4678    return pip[0];
     4679}
     4680
     4681static int
     4682openredirect(union node *redir)
     4683{
     4684    char *fname;
     4685    int f;
     4686
     4687    switch (redir->nfile.type) {
     4688    case NFROM:
     4689        fname = redir->nfile.expfname;
     4690        f = open(fname, O_RDONLY);
     4691        if (f < 0)
     4692            goto eopen;
     4693        break;
     4694    case NFROMTO:
     4695        fname = redir->nfile.expfname;
     4696        f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666);
     4697        if (f < 0)
     4698            goto ecreate;
     4699        break;
     4700    case NTO:
     4701        /* Take care of noclobber mode. */
     4702        if (Cflag) {
     4703            fname = redir->nfile.expfname;
     4704            f = noclobberopen(fname);
     4705            if (f < 0)
     4706                goto ecreate;
     4707            break;
     4708        }
     4709        /* FALLTHROUGH */
     4710    case NCLOBBER:
     4711        fname = redir->nfile.expfname;
     4712        f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
     4713        if (f < 0)
     4714            goto ecreate;
     4715        break;
     4716    case NAPPEND:
     4717        fname = redir->nfile.expfname;
     4718        f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
     4719        if (f < 0)
     4720            goto ecreate;
     4721        break;
     4722    default:
     4723#if DEBUG
     4724        abort();
     4725#endif
     4726        /* Fall through to eliminate warning. */
     4727    case NTOFD:
     4728    case NFROMFD:
     4729        f = -1;
     4730        break;
     4731    case NHERE:
     4732    case NXHERE:
     4733        f = openhere(redir);
     4734        break;
     4735    }
     4736
     4737    return f;
     4738 ecreate:
     4739    ash_msg_and_raise_error("cannot create %s: %s", fname, errmsg(errno, "nonexistent directory"));
     4740 eopen:
     4741    ash_msg_and_raise_error("cannot open %s: %s", fname, errmsg(errno, "no such file"));
     4742}
     4743
     4744/*
     4745 * Copy a file descriptor to be >= to.  Returns -1
     4746 * if the source file descriptor is closed, EMPTY if there are no unused
     4747 * file descriptors left.
     4748 */
     4749static int
     4750copyfd(int from, int to)
     4751{
     4752    int newfd;
     4753
     4754    newfd = fcntl(from, F_DUPFD, to);
     4755    if (newfd < 0) {
     4756        if (errno == EMFILE)
     4757            return EMPTY;
     4758        ash_msg_and_raise_error("%d: %m", from);
     4759    }
     4760    return newfd;
     4761}
     4762
     4763static void
     4764dupredirect(union node *redir, int f)
     4765{
     4766    int fd = redir->nfile.fd;
     4767
     4768    if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
     4769        if (redir->ndup.dupfd >= 0) {   /* if not ">&-" */
     4770            copyfd(redir->ndup.dupfd, fd);
     4771        }
     4772        return;
     4773    }
     4774
     4775    if (f != fd) {
     4776        copyfd(f, fd);
     4777        close(f);
     4778    }
     4779}
     4780
     4781/*
     4782 * Process a list of redirection commands.  If the REDIR_PUSH flag is set,
     4783 * old file descriptors are stashed away so that the redirection can be
     4784 * undone by calling popredir.  If the REDIR_BACKQ flag is set, then the
     4785 * standard output, and the standard error if it becomes a duplicate of
     4786 * stdout, is saved in memory.
     4787 */
     4788/* flags passed to redirect */
     4789#define REDIR_PUSH    01        /* save previous values of file descriptors */
     4790#define REDIR_SAVEFD2 03        /* set preverrout */
     4791static void
     4792redirect(union node *redir, int flags)
     4793{
     4794    union node *n;
     4795    struct redirtab *sv;
     4796    int i;
     4797    int fd;
     4798    int newfd;
     4799    int *p;
     4800    nullredirs++;
     4801    if (!redir) {
     4802        return;
     4803    }
     4804    sv = NULL;
     4805    INT_OFF;
     4806    if (flags & REDIR_PUSH) {
     4807        struct redirtab *q;
     4808        q = ckmalloc(sizeof(struct redirtab));
     4809        q->next = redirlist;
     4810        redirlist = q;
     4811        q->nullredirs = nullredirs - 1;
     4812        for (i = 0; i < 10; i++)
     4813            q->renamed[i] = EMPTY;
     4814        nullredirs = 0;
     4815        sv = q;
     4816    }
     4817    n = redir;
     4818    do {
     4819        fd = n->nfile.fd;
     4820        if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD)
     4821         && n->ndup.dupfd == fd)
     4822            continue; /* redirect from/to same file descriptor */
     4823
     4824        newfd = openredirect(n);
     4825        if (fd == newfd)
     4826            continue;
     4827        if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
     4828            i = fcntl(fd, F_DUPFD, 10);
     4829
     4830            if (i == -1) {
     4831                i = errno;
     4832                if (i != EBADF) {
     4833                    close(newfd);
     4834                    errno = i;
     4835                    ash_msg_and_raise_error("%d: %m", fd);
     4836                    /* NOTREACHED */
     4837                }
     4838            } else {
     4839                *p = i;
     4840                close(fd);
     4841            }
     4842        } else {
     4843            close(fd);
     4844        }
     4845        dupredirect(n, newfd);
     4846    } while ((n = n->nfile.next));
     4847    INT_ON;
     4848    if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0)
     4849        preverrout_fd = sv->renamed[2];
     4850}
     4851
     4852/*
     4853 * Undo the effects of the last redirection.
     4854 */
     4855static void
     4856popredir(int drop)
     4857{
     4858    struct redirtab *rp;
     4859    int i;
     4860
     4861    if (--nullredirs >= 0)
     4862        return;
     4863    INT_OFF;
     4864    rp = redirlist;
     4865    for (i = 0; i < 10; i++) {
     4866        if (rp->renamed[i] != EMPTY) {
     4867            if (!drop) {
     4868                close(i);
     4869                copyfd(rp->renamed[i], i);
     4870            }
     4871            close(rp->renamed[i]);
     4872        }
     4873    }
     4874    redirlist = rp->next;
     4875    nullredirs = rp->nullredirs;
     4876    free(rp);
     4877    INT_ON;
     4878}
     4879
     4880/*
     4881 * Undo all redirections.  Called on error or interrupt.
     4882 */
     4883
     4884/*
     4885 * Discard all saved file descriptors.
     4886 */
     4887static void
     4888clearredir(int drop)
     4889{
     4890    for (;;) {
     4891        nullredirs = 0;
     4892        if (!redirlist)
     4893            break;
     4894        popredir(drop);
     4895    }
     4896}
     4897
     4898static int
     4899redirectsafe(union node *redir, int flags)
     4900{
     4901    int err;
     4902    volatile int saveint;
     4903    struct jmploc *volatile savehandler = exception_handler;
     4904    struct jmploc jmploc;
     4905
     4906    SAVE_INT(saveint);
     4907    err = setjmp(jmploc.loc) * 2;
     4908    if (!err) {
     4909        exception_handler = &jmploc;
     4910        redirect(redir, flags);
     4911    }
     4912    exception_handler = savehandler;
     4913    if (err && exception != EXERROR)
     4914        longjmp(exception_handler->loc, 1);
     4915    RESTORE_INT(saveint);
     4916    return err;
     4917}
     4918
     4919
     4920/* ============ Routines to expand arguments to commands
     4921 *
     4922 * We have to deal with backquotes, shell variables, and file metacharacters.
     4923 */
     4924
     4925/*
     4926 * expandarg flags
     4927 */
     4928#define EXP_FULL        0x1     /* perform word splitting & file globbing */
     4929#define EXP_TILDE       0x2     /* do normal tilde expansion */
     4930#define EXP_VARTILDE    0x4     /* expand tildes in an assignment */
     4931#define EXP_REDIR       0x8     /* file glob for a redirection (1 match only) */
     4932#define EXP_CASE        0x10    /* keeps quotes around for CASE pattern */
     4933#define EXP_RECORD      0x20    /* need to record arguments for ifs breakup */
     4934#define EXP_VARTILDE2   0x40    /* expand tildes after colons only */
     4935#define EXP_WORD        0x80    /* expand word in parameter expansion */
     4936#define EXP_QWORD       0x100   /* expand word in quoted parameter expansion */
     4937/*
     4938 * _rmescape() flags
     4939 */
     4940#define RMESCAPE_ALLOC  0x1     /* Allocate a new string */
     4941#define RMESCAPE_GLOB   0x2     /* Add backslashes for glob */
     4942#define RMESCAPE_QUOTED 0x4     /* Remove CTLESC unless in quotes */
     4943#define RMESCAPE_GROW   0x8     /* Grow strings instead of stalloc */
     4944#define RMESCAPE_HEAP   0x10    /* Malloc strings instead of stalloc */
     4945
     4946/*
     4947 * Structure specifying which parts of the string should be searched
     4948 * for IFS characters.
     4949 */
     4950struct ifsregion {
     4951    struct ifsregion *next; /* next region in list */
     4952    int begoff;             /* offset of start of region */
     4953    int endoff;             /* offset of end of region */
     4954    int nulonly;            /* search for nul bytes only */
     4955};
     4956
     4957struct arglist {
     4958    struct strlist *list;
     4959    struct strlist **lastp;
     4960};
     4961
     4962/* output of current string */
     4963static char *expdest;
     4964/* list of back quote expressions */
     4965static struct nodelist *argbackq;
     4966/* first struct in list of ifs regions */
     4967static struct ifsregion ifsfirst;
     4968/* last struct in list */
     4969static struct ifsregion *ifslastp;
     4970/* holds expanded arg list */
     4971static struct arglist exparg;
     4972
     4973/*
     4974 * Our own itoa().
     4975 */
     4976static int
     4977cvtnum(arith_t num)
     4978{
     4979    int len;
     4980
     4981    expdest = makestrspace(32, expdest);
     4982#if ENABLE_ASH_MATH_SUPPORT_64
     4983    len = fmtstr(expdest, 32, "%lld", (long long) num);
     4984#else
     4985    len = fmtstr(expdest, 32, "%ld", num);
     4986#endif
     4987    STADJUST(len, expdest);
     4988    return len;
     4989}
     4990
     4991static size_t
     4992esclen(const char *start, const char *p)
     4993{
     4994    size_t esc = 0;
     4995
     4996    while (p > start && *--p == CTLESC) {
     4997        esc++;
     4998    }
     4999    return esc;
     5000}
     5001
     5002/*
     5003 * Remove any CTLESC characters from a string.
     5004 */
     5005static char *
     5006_rmescapes(char *str, int flag)
     5007{
     5008    static const char qchars[] ALIGN1 = { CTLESC, CTLQUOTEMARK, '\0' };
     5009
     5010    char *p, *q, *r;
     5011    unsigned inquotes;
     5012    int notescaped;
     5013    int globbing;
     5014
     5015    p = strpbrk(str, qchars);
     5016    if (!p) {
     5017        return str;
     5018    }
     5019    q = p;
     5020    r = str;
     5021    if (flag & RMESCAPE_ALLOC) {
     5022        size_t len = p - str;
     5023        size_t fulllen = len + strlen(p) + 1;
     5024
     5025        if (flag & RMESCAPE_GROW) {
     5026            r = makestrspace(fulllen, expdest);
     5027        } else if (flag & RMESCAPE_HEAP) {
     5028            r = ckmalloc(fulllen);
     5029        } else {
     5030            r = stalloc(fulllen);
     5031        }
     5032        q = r;
     5033        if (len > 0) {
     5034            q = memcpy(q, str, len) + len;
     5035        }
     5036    }
     5037    inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
     5038    globbing = flag & RMESCAPE_GLOB;
     5039    notescaped = globbing;
     5040    while (*p) {
     5041        if (*p == CTLQUOTEMARK) {
     5042            inquotes = ~inquotes;
     5043            p++;
     5044            notescaped = globbing;
     5045            continue;
     5046        }
     5047        if (*p == '\\') {
     5048            /* naked back slash */
     5049            notescaped = 0;
     5050            goto copy;
     5051        }
     5052        if (*p == CTLESC) {
     5053            p++;
     5054            if (notescaped && inquotes && *p != '/') {
     5055                *q++ = '\\';
     5056            }
     5057        }
     5058        notescaped = globbing;
     5059 copy:
     5060        *q++ = *p++;
     5061    }
     5062    *q = '\0';
     5063    if (flag & RMESCAPE_GROW) {
     5064        expdest = r;
     5065        STADJUST(q - r + 1, expdest);
     5066    }
     5067    return r;
     5068}
     5069#define rmescapes(p) _rmescapes((p), 0)
     5070
     5071#define pmatch(a, b) !fnmatch((a), (b), 0)
     5072
     5073/*
     5074 * Prepare a pattern for a expmeta (internal glob(3)) call.
     5075 *
     5076 * Returns an stalloced string.
     5077 */
     5078static char *
     5079preglob(const char *pattern, int quoted, int flag)
     5080{
     5081    flag |= RMESCAPE_GLOB;
     5082    if (quoted) {
     5083        flag |= RMESCAPE_QUOTED;
     5084    }
     5085    return _rmescapes((char *)pattern, flag);
     5086}
     5087
     5088/*
     5089 * Put a string on the stack.
     5090 */
     5091static void
     5092memtodest(const char *p, size_t len, int syntax, int quotes)
     5093{
     5094    char *q = expdest;
     5095
     5096    q = makestrspace(len * 2, q);
     5097
     5098    while (len--) {
     5099        int c = signed_char2int(*p++);
     5100        if (!c)
     5101            continue;
     5102        if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
     5103            USTPUTC(CTLESC, q);
     5104        USTPUTC(c, q);
     5105    }
     5106
     5107    expdest = q;
     5108}
     5109
     5110static void
     5111strtodest(const char *p, int syntax, int quotes)
     5112{
     5113    memtodest(p, strlen(p), syntax, quotes);
     5114}
     5115
     5116/*
     5117 * Record the fact that we have to scan this region of the
     5118 * string for IFS characters.
     5119 */
     5120static void
     5121recordregion(int start, int end, int nulonly)
     5122{
     5123    struct ifsregion *ifsp;
     5124
     5125    if (ifslastp == NULL) {
     5126        ifsp = &ifsfirst;
     5127    } else {
     5128        INT_OFF;
     5129        ifsp = ckmalloc(sizeof(*ifsp));
     5130        ifsp->next = NULL;
     5131        ifslastp->next = ifsp;
     5132        INT_ON;
     5133    }
     5134    ifslastp = ifsp;
     5135    ifslastp->begoff = start;
     5136    ifslastp->endoff = end;
     5137    ifslastp->nulonly = nulonly;
     5138}
     5139
     5140static void
     5141removerecordregions(int endoff)
     5142{
     5143    if (ifslastp == NULL)
     5144        return;
     5145
     5146    if (ifsfirst.endoff > endoff) {
     5147        while (ifsfirst.next != NULL) {
     5148            struct ifsregion *ifsp;
     5149            INT_OFF;
     5150            ifsp = ifsfirst.next->next;
     5151            free(ifsfirst.next);
     5152            ifsfirst.next = ifsp;
     5153            INT_ON;
     5154        }
     5155        if (ifsfirst.begoff > endoff)
     5156            ifslastp = NULL;
     5157        else {
     5158            ifslastp = &ifsfirst;
     5159            ifsfirst.endoff = endoff;
     5160        }
     5161        return;
     5162    }
     5163
     5164    ifslastp = &ifsfirst;
     5165    while (ifslastp->next && ifslastp->next->begoff < endoff)
     5166        ifslastp=ifslastp->next;
     5167    while (ifslastp->next != NULL) {
     5168        struct ifsregion *ifsp;
     5169        INT_OFF;
     5170        ifsp = ifslastp->next->next;
     5171        free(ifslastp->next);
     5172        ifslastp->next = ifsp;
     5173        INT_ON;
     5174    }
     5175    if (ifslastp->endoff > endoff)
     5176        ifslastp->endoff = endoff;
     5177}
     5178
     5179static char *
     5180exptilde(char *startp, char *p, int flag)
     5181{
     5182    char c;
     5183    char *name;
     5184    struct passwd *pw;
     5185    const char *home;
     5186    int quotes = flag & (EXP_FULL | EXP_CASE);
     5187    int startloc;
     5188
     5189    name = p + 1;
     5190
     5191    while ((c = *++p) != '\0') {
     5192        switch (c) {
     5193        case CTLESC:
     5194            return startp;
     5195        case CTLQUOTEMARK:
     5196            return startp;
     5197        case ':':
     5198            if (flag & EXP_VARTILDE)
     5199                goto done;
     5200            break;
     5201        case '/':
     5202        case CTLENDVAR:
     5203            goto done;
     5204        }
     5205    }
     5206 done:
     5207    *p = '\0';
     5208    if (*name == '\0') {
     5209        home = lookupvar(homestr);
     5210    } else {
     5211        pw = getpwnam(name);
     5212        if (pw == NULL)
     5213            goto lose;
     5214        home = pw->pw_dir;
     5215    }
     5216    if (!home || !*home)
     5217        goto lose;
     5218    *p = c;
     5219    startloc = expdest - (char *)stackblock();
     5220    strtodest(home, SQSYNTAX, quotes);
     5221    recordregion(startloc, expdest - (char *)stackblock(), 0);
     5222    return p;
     5223 lose:
     5224    *p = c;
     5225    return startp;
     5226}
     5227
     5228/*
     5229 * Execute a command inside back quotes.  If it's a builtin command, we
     5230 * want to save its output in a block obtained from malloc.  Otherwise
     5231 * we fork off a subprocess and get the output of the command via a pipe.
     5232 * Should be called with interrupts off.
     5233 */
     5234struct backcmd {                /* result of evalbackcmd */
     5235    int fd;                 /* file descriptor to read from */
     5236    char *buf;              /* buffer */
     5237    int nleft;              /* number of chars in buffer */
     5238    struct job *jp;         /* job structure for command */
     5239};
     5240
     5241/* These forward decls are needed to use "eval" code for backticks handling: */
     5242static int back_exitstatus; /* exit status of backquoted command */
     5243#define EV_EXIT 01              /* exit after evaluating tree */
     5244static void evaltree(union node *, int);
     5245
     5246static void
     5247evalbackcmd(union node *n, struct backcmd *result)
     5248{
     5249    int saveherefd;
     5250
     5251    result->fd = -1;
     5252    result->buf = NULL;
     5253    result->nleft = 0;
     5254    result->jp = NULL;
     5255    if (n == NULL) {
     5256        goto out;
     5257    }
     5258
     5259    saveherefd = herefd;
     5260    herefd = -1;
     5261
     5262    {
     5263        int pip[2];
     5264        struct job *jp;
     5265
     5266        if (pipe(pip) < 0)
     5267            ash_msg_and_raise_error("pipe call failed");
     5268        jp = makejob(n, 1);
     5269        if (forkshell(jp, n, FORK_NOJOB) == 0) {
     5270            FORCE_INT_ON;
     5271            close(pip[0]);
     5272            if (pip[1] != 1) {
     5273                close(1);
     5274                copyfd(pip[1], 1);
     5275                close(pip[1]);
     5276            }
     5277            eflag = 0;
     5278            evaltree(n, EV_EXIT); /* actually evaltreenr... */
     5279            /* NOTREACHED */
     5280        }
     5281        close(pip[1]);
     5282        result->fd = pip[0];
     5283        result->jp = jp;
     5284    }
     5285    herefd = saveherefd;
     5286 out:
     5287    TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
     5288        result->fd, result->buf, result->nleft, result->jp));
     5289}
     5290
     5291/*
     5292 * Expand stuff in backwards quotes.
     5293 */
     5294static void
     5295expbackq(union node *cmd, int quoted, int quotes)
     5296{
     5297    struct backcmd in;
     5298    int i;
     5299    char buf[128];
     5300    char *p;
     5301    char *dest;
     5302    int startloc;
     5303    int syntax = quoted? DQSYNTAX : BASESYNTAX;
     5304    struct stackmark smark;
     5305
     5306    INT_OFF;
     5307    setstackmark(&smark);
     5308    dest = expdest;
     5309    startloc = dest - (char *)stackblock();
     5310    grabstackstr(dest);
     5311    evalbackcmd(cmd, &in);
     5312    popstackmark(&smark);
     5313
     5314    p = in.buf;
     5315    i = in.nleft;
     5316    if (i == 0)
     5317        goto read;
     5318    for (;;) {
     5319        memtodest(p, i, syntax, quotes);
     5320 read:
     5321        if (in.fd < 0)
     5322            break;
     5323        i = safe_read(in.fd, buf, sizeof(buf));
     5324        TRACE(("expbackq: read returns %d\n", i));
     5325        if (i <= 0)
     5326            break;
     5327        p = buf;
     5328    }
     5329
     5330    if (in.buf)
     5331        free(in.buf);
     5332    if (in.fd >= 0) {
     5333        close(in.fd);
     5334        back_exitstatus = waitforjob(in.jp);
     5335    }
     5336    INT_ON;
     5337
     5338    /* Eat all trailing newlines */
     5339    dest = expdest;
     5340    for (; dest > (char *)stackblock() && dest[-1] == '\n';)
     5341        STUNPUTC(dest);
     5342    expdest = dest;
     5343
     5344    if (quoted == 0)
     5345        recordregion(startloc, dest - (char *)stackblock(), 0);
     5346    TRACE(("evalbackq: size=%d: \"%.*s\"\n",
     5347        (dest - (char *)stackblock()) - startloc,
     5348        (dest - (char *)stackblock()) - startloc,
     5349        stackblock() + startloc));
     5350}
     5351
     5352#if ENABLE_ASH_MATH_SUPPORT
     5353/*
     5354 * Expand arithmetic expression.  Backup to start of expression,
     5355 * evaluate, place result in (backed up) result, adjust string position.
     5356 */
     5357static void
     5358expari(int quotes)
     5359{
     5360    char *p, *start;
     5361    int begoff;
     5362    int flag;
     5363    int len;
     5364
     5365    /*      ifsfree(); */
     5366
     5367    /*
     5368     * This routine is slightly over-complicated for
     5369     * efficiency.  Next we scan backwards looking for the
     5370     * start of arithmetic.
     5371     */
     5372    start = stackblock();
     5373    p = expdest - 1;
     5374    *p = '\0';
     5375    p--;
     5376    do {
     5377        int esc;
     5378
     5379        while (*p != CTLARI) {
     5380            p--;
     5381#if DEBUG
     5382            if (p < start) {
     5383                ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
     5384            }
     5385#endif
     5386        }
     5387
     5388        esc = esclen(start, p);
     5389        if (!(esc % 2)) {
     5390            break;
     5391        }
     5392
     5393        p -= esc + 1;
     5394    } while (1);
     5395
     5396    begoff = p - start;
     5397
     5398    removerecordregions(begoff);
     5399
     5400    flag = p[1];
     5401
     5402    expdest = p;
     5403
     5404    if (quotes)
     5405        rmescapes(p + 2);
     5406
     5407    len = cvtnum(dash_arith(p + 2));
     5408
     5409    if (flag != '"')
     5410        recordregion(begoff, begoff + len, 0);
     5411}
     5412#endif
     5413
     5414/* argstr needs it */
     5415static char *evalvar(char *p, int flag);
     5416
     5417/*
     5418 * Perform variable and command substitution.  If EXP_FULL is set, output CTLESC
     5419 * characters to allow for further processing.  Otherwise treat
     5420 * $@ like $* since no splitting will be performed.
     5421 */
     5422static void
     5423argstr(char *p, int flag)
     5424{
     5425    static const char spclchars[] ALIGN1 = {
     5426        '=',
     5427        ':',
     5428        CTLQUOTEMARK,
     5429        CTLENDVAR,
     5430        CTLESC,
     5431        CTLVAR,
     5432        CTLBACKQ,
     5433        CTLBACKQ | CTLQUOTE,
     5434#if ENABLE_ASH_MATH_SUPPORT
     5435        CTLENDARI,
     5436#endif
     5437        0
     5438    };
     5439    const char *reject = spclchars;
     5440    int c;
     5441    int quotes = flag & (EXP_FULL | EXP_CASE);      /* do CTLESC */
     5442    int breakall = flag & EXP_WORD;
     5443    int inquotes;
     5444    size_t length;
     5445    int startloc;
     5446
     5447    if (!(flag & EXP_VARTILDE)) {
     5448        reject += 2;
     5449    } else if (flag & EXP_VARTILDE2) {
     5450        reject++;
     5451    }
     5452    inquotes = 0;
     5453    length = 0;
     5454    if (flag & EXP_TILDE) {
     5455        char *q;
     5456
     5457        flag &= ~EXP_TILDE;
     5458 tilde:
     5459        q = p;
     5460        if (*q == CTLESC && (flag & EXP_QWORD))
     5461            q++;
     5462        if (*q == '~')
     5463            p = exptilde(p, q, flag);
     5464    }
     5465 start:
     5466    startloc = expdest - (char *)stackblock();
     5467    for (;;) {
     5468        length += strcspn(p + length, reject);
     5469        c = p[length];
     5470        if (c && (!(c & 0x80)
     5471#if ENABLE_ASH_MATH_SUPPORT
     5472                    || c == CTLENDARI
     5473#endif
     5474           )) {
     5475            /* c == '=' || c == ':' || c == CTLENDARI */
     5476            length++;
     5477        }
     5478        if (length > 0) {
     5479            int newloc;
     5480            expdest = stack_nputstr(p, length, expdest);
     5481            newloc = expdest - (char *)stackblock();
     5482            if (breakall && !inquotes && newloc > startloc) {
     5483                recordregion(startloc, newloc, 0);
     5484            }
     5485            startloc = newloc;
     5486        }
     5487        p += length + 1;
     5488        length = 0;
     5489
     5490        switch (c) {
     5491        case '\0':
     5492            goto breakloop;
     5493        case '=':
     5494            if (flag & EXP_VARTILDE2) {
     5495                p--;
     5496                continue;
     5497            }
     5498            flag |= EXP_VARTILDE2;
     5499            reject++;
     5500            /* fall through */
     5501        case ':':
     5502            /*
     5503             * sort of a hack - expand tildes in variable
     5504             * assignments (after the first '=' and after ':'s).
     5505             */
     5506            if (*--p == '~') {
     5507                goto tilde;
     5508            }
     5509            continue;
     5510        }
     5511
     5512        switch (c) {
     5513        case CTLENDVAR: /* ??? */
     5514            goto breakloop;
     5515        case CTLQUOTEMARK:
     5516            /* "$@" syntax adherence hack */
     5517            if (
     5518                !inquotes &&
     5519                !memcmp(p, dolatstr, 4) &&
     5520                (p[4] == CTLQUOTEMARK || (
     5521                    p[4] == CTLENDVAR &&
     5522                    p[5] == CTLQUOTEMARK
     5523                ))
     5524            ) {
     5525                p = evalvar(p + 1, flag) + 1;
     5526                goto start;
     5527            }
     5528            inquotes = !inquotes;
     5529 addquote:
     5530            if (quotes) {
     5531                p--;
     5532                length++;
     5533                startloc++;
     5534            }
     5535            break;
     5536        case CTLESC:
     5537            startloc++;
     5538            length++;
     5539            goto addquote;
     5540        case CTLVAR:
     5541            p = evalvar(p, flag);
     5542            goto start;
     5543        case CTLBACKQ:
     5544            c = 0;
     5545        case CTLBACKQ|CTLQUOTE:
     5546            expbackq(argbackq->n, c, quotes);
     5547            argbackq = argbackq->next;
     5548            goto start;
     5549#if ENABLE_ASH_MATH_SUPPORT
     5550        case CTLENDARI:
     5551            p--;
     5552            expari(quotes);
     5553            goto start;
     5554#endif
     5555        }
     5556    }
     5557 breakloop:
     5558    ;
     5559}
     5560
     5561static char *
     5562scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
     5563    int zero)
     5564{
     5565    char *loc;
     5566    char *loc2;
     5567    char c;
     5568
     5569    loc = startp;
     5570    loc2 = rmesc;
     5571    do {
     5572        int match;
     5573        const char *s = loc2;
     5574        c = *loc2;
     5575        if (zero) {
     5576            *loc2 = '\0';
     5577            s = rmesc;
     5578        }
     5579        match = pmatch(str, s);
     5580        *loc2 = c;
     5581        if (match)
     5582            return loc;
     5583        if (quotes && *loc == CTLESC)
     5584            loc++;
     5585        loc++;
     5586        loc2++;
     5587    } while (c);
     5588    return 0;
     5589}
     5590
     5591static char *
     5592scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
     5593    int zero)
     5594{
     5595    int esc = 0;
     5596    char *loc;
     5597    char *loc2;
     5598
     5599    for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
     5600        int match;
     5601        char c = *loc2;
     5602        const char *s = loc2;
     5603        if (zero) {
     5604            *loc2 = '\0';
     5605            s = rmesc;
     5606        }
     5607        match = pmatch(str, s);
     5608        *loc2 = c;
     5609        if (match)
     5610            return loc;
     5611        loc--;
     5612        if (quotes) {
     5613            if (--esc < 0) {
     5614                esc = esclen(startp, loc);
     5615            }
     5616            if (esc % 2) {
     5617                esc--;
     5618                loc--;
     5619            }
     5620        }
     5621    }
     5622    return 0;
     5623}
     5624
     5625static void varunset(const char *, const char *, const char *, int) ATTRIBUTE_NORETURN;
     5626static void
     5627varunset(const char *end, const char *var, const char *umsg, int varflags)
     5628{
     5629    const char *msg;
     5630    const char *tail;
     5631
     5632    tail = nullstr;
     5633    msg = "parameter not set";
     5634    if (umsg) {
     5635        if (*end == CTLENDVAR) {
     5636            if (varflags & VSNUL)
     5637                tail = " or null";
     5638        } else
     5639            msg = umsg;
     5640    }
     5641    ash_msg_and_raise_error("%.*s: %s%s", end - var - 1, var, msg, tail);
     5642}
     5643
     5644static const char *
     5645subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
     5646{
     5647    char *startp;
     5648    char *loc;
     5649    int saveherefd = herefd;
     5650    struct nodelist *saveargbackq = argbackq;
     5651    int amount;
     5652    char *rmesc, *rmescend;
     5653    int zero;
     5654    char *(*scan)(char *, char *, char *, char *, int , int);
     5655
     5656    herefd = -1;
     5657    argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
     5658    STPUTC('\0', expdest);
     5659    herefd = saveherefd;
     5660    argbackq = saveargbackq;
     5661    startp = stackblock() + startloc;
     5662
     5663    switch (subtype) {
     5664    case VSASSIGN:
     5665        setvar(str, startp, 0);
     5666        amount = startp - expdest;
     5667        STADJUST(amount, expdest);
     5668        return startp;
     5669
     5670    case VSQUESTION:
     5671        varunset(p, str, startp, varflags);
     5672        /* NOTREACHED */
     5673    }
     5674
     5675    subtype -= VSTRIMRIGHT;
     5676#if DEBUG
     5677    if (subtype < 0 || subtype > 3)
     5678        abort();
     5679#endif
     5680
     5681    rmesc = startp;
     5682    rmescend = stackblock() + strloc;
     5683    if (quotes) {
     5684        rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
     5685        if (rmesc != startp) {
     5686            rmescend = expdest;
     5687            startp = stackblock() + startloc;
     5688        }
     5689    }
     5690    rmescend--;
     5691    str = stackblock() + strloc;
     5692    preglob(str, varflags & VSQUOTE, 0);
     5693
     5694    /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
     5695    zero = subtype >> 1;
     5696    /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
     5697    scan = (subtype & 1) ^ zero ? scanleft : scanright;
     5698
     5699    loc = scan(startp, rmesc, rmescend, str, quotes, zero);
     5700    if (loc) {
     5701        if (zero) {
     5702            memmove(startp, loc, str - loc);
     5703            loc = startp + (str - loc) - 1;
     5704        }
     5705        *loc = '\0';
     5706        amount = loc - expdest;
     5707        STADJUST(amount, expdest);
     5708    }
     5709    return loc;
     5710}
     5711
     5712/*
     5713 * Add the value of a specialized variable to the stack string.
     5714 */
     5715static ssize_t
     5716varvalue(char *name, int varflags, int flags)
     5717{
     5718    int num;
     5719    char *p;
     5720    int i;
     5721    int sep = 0;
     5722    int sepq = 0;
     5723    ssize_t len = 0;
     5724    char **ap;
     5725    int syntax;
     5726    int quoted = varflags & VSQUOTE;
     5727    int subtype = varflags & VSTYPE;
     5728    int quotes = flags & (EXP_FULL | EXP_CASE);
     5729
     5730    if (quoted && (flags & EXP_FULL))
     5731        sep = 1 << CHAR_BIT;
     5732
     5733    syntax = quoted ? DQSYNTAX : BASESYNTAX;
     5734    switch (*name) {
     5735    case '$':
     5736        num = rootpid;
     5737        goto numvar;
     5738    case '?':
     5739        num = exitstatus;
     5740        goto numvar;
     5741    case '#':
     5742        num = shellparam.nparam;
     5743        goto numvar;
     5744    case '!':
     5745        num = backgndpid;
     5746        if (num == 0)
     5747            return -1;
     5748 numvar:
     5749        len = cvtnum(num);
     5750        break;
     5751    case '-':
     5752        p = makestrspace(NOPTS, expdest);
     5753        for (i = NOPTS - 1; i >= 0; i--) {
     5754            if (optlist[i]) {
     5755                USTPUTC(optletters(i), p);
     5756                len++;
     5757            }
     5758        }
     5759        expdest = p;
     5760        break;
     5761    case '@':
     5762        if (sep)
     5763            goto param;
     5764        /* fall through */
     5765    case '*':
     5766        sep = ifsset() ? signed_char2int(ifsval()[0]) : ' ';
     5767        if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))
     5768            sepq = 1;
     5769 param:
     5770        ap = shellparam.p;
     5771        if (!ap)
     5772            return -1;
     5773        while ((p = *ap++)) {
     5774            size_t partlen;
     5775
     5776            partlen = strlen(p);
     5777            len += partlen;
     5778
     5779            if (!(subtype == VSPLUS || subtype == VSLENGTH))
     5780                memtodest(p, partlen, syntax, quotes);
     5781
     5782            if (*ap && sep) {
     5783                char *q;
     5784
     5785                len++;
     5786                if (subtype == VSPLUS || subtype == VSLENGTH) {
     5787                    continue;
     5788                }
     5789                q = expdest;
     5790                if (sepq)
     5791                    STPUTC(CTLESC, q);
     5792                STPUTC(sep, q);
     5793                expdest = q;
     5794            }
     5795        }
     5796        return len;
     5797    case '0':
     5798    case '1':
     5799    case '2':
     5800    case '3':
     5801    case '4':
     5802    case '5':
     5803    case '6':
     5804    case '7':
     5805    case '8':
     5806    case '9':
     5807        num = atoi(name);
     5808        if (num < 0 || num > shellparam.nparam)
     5809            return -1;
     5810        p = num ? shellparam.p[num - 1] : arg0;
     5811        goto value;
     5812    default:
     5813        p = lookupvar(name);
     5814 value:
     5815        if (!p)
     5816            return -1;
     5817
     5818        len = strlen(p);
     5819        if (!(subtype == VSPLUS || subtype == VSLENGTH))
     5820            memtodest(p, len, syntax, quotes);
     5821        return len;
     5822    }
     5823
     5824    if (subtype == VSPLUS || subtype == VSLENGTH)
     5825        STADJUST(-len, expdest);
     5826    return len;
     5827}
     5828
     5829/*
     5830 * Expand a variable, and return a pointer to the next character in the
     5831 * input string.
     5832 */
     5833static char *
     5834evalvar(char *p, int flag)
     5835{
     5836    int subtype;
     5837    int varflags;
     5838    char *var;
     5839    int patloc;
     5840    int c;
     5841    int startloc;
     5842    ssize_t varlen;
     5843    int easy;
     5844    int quotes;
     5845    int quoted;
     5846
     5847    quotes = flag & (EXP_FULL | EXP_CASE);
     5848    varflags = *p++;
     5849    subtype = varflags & VSTYPE;
     5850    quoted = varflags & VSQUOTE;
     5851    var = p;
     5852    easy = (!quoted || (*var == '@' && shellparam.nparam));
     5853    startloc = expdest - (char *)stackblock();
     5854    p = strchr(p, '=') + 1;
     5855
     5856 again:
     5857    varlen = varvalue(var, varflags, flag);
     5858    if (varflags & VSNUL)
     5859        varlen--;
     5860
     5861    if (subtype == VSPLUS) {
     5862        varlen = -1 - varlen;
     5863        goto vsplus;
     5864    }
     5865
     5866    if (subtype == VSMINUS) {
     5867 vsplus:
     5868        if (varlen < 0) {
     5869            argstr(
     5870                p, flag | EXP_TILDE |
     5871                    (quoted ?  EXP_QWORD : EXP_WORD)
     5872            );
     5873            goto end;
     5874        }
     5875        if (easy)
     5876            goto record;
     5877        goto end;
     5878    }
     5879
     5880    if (subtype == VSASSIGN || subtype == VSQUESTION) {
     5881        if (varlen < 0) {
     5882            if (subevalvar(p, var, 0, subtype, startloc, varflags, 0)) {
     5883                varflags &= ~VSNUL;
     5884                /*
     5885                 * Remove any recorded regions beyond
     5886                 * start of variable
     5887                 */
     5888                removerecordregions(startloc);
     5889                goto again;
     5890            }
     5891            goto end;
     5892        }
     5893        if (easy)
     5894            goto record;
     5895        goto end;
     5896    }
     5897
     5898    if (varlen < 0 && uflag)
     5899        varunset(p, var, 0, 0);
     5900
     5901    if (subtype == VSLENGTH) {
     5902        cvtnum(varlen > 0 ? varlen : 0);
     5903        goto record;
     5904    }
     5905
     5906    if (subtype == VSNORMAL) {
     5907        if (!easy)
     5908            goto end;
     5909 record:
     5910        recordregion(startloc, expdest - (char *)stackblock(), quoted);
     5911        goto end;
     5912    }
     5913
     5914#if DEBUG
     5915    switch (subtype) {
     5916    case VSTRIMLEFT:
     5917    case VSTRIMLEFTMAX:
     5918    case VSTRIMRIGHT:
     5919    case VSTRIMRIGHTMAX:
     5920        break;
     5921    default:
     5922        abort();
     5923    }
     5924#endif
     5925
     5926    if (varlen >= 0) {
     5927        /*
     5928         * Terminate the string and start recording the pattern
     5929         * right after it
     5930         */
     5931        STPUTC('\0', expdest);
     5932        patloc = expdest - (char *)stackblock();
     5933        if (subevalvar(p, NULL, patloc, subtype,
     5934                startloc, varflags, quotes) == 0) {
     5935            int amount = expdest - (
     5936                (char *)stackblock() + patloc - 1
     5937            );
     5938            STADJUST(-amount, expdest);
     5939        }
     5940        /* Remove any recorded regions beyond start of variable */
     5941        removerecordregions(startloc);
     5942        goto record;
     5943    }
     5944
     5945 end:
     5946    if (subtype != VSNORMAL) {      /* skip to end of alternative */
     5947        int nesting = 1;
     5948        for (;;) {
     5949            c = *p++;
     5950            if (c == CTLESC)
     5951                p++;
     5952            else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
     5953                if (varlen >= 0)
     5954                    argbackq = argbackq->next;
     5955            } else if (c == CTLVAR) {
     5956                if ((*p++ & VSTYPE) != VSNORMAL)
     5957                    nesting++;
     5958            } else if (c == CTLENDVAR) {
     5959                if (--nesting == 0)
     5960                    break;
     5961            }
     5962        }
     5963    }
     5964    return p;
     5965}
     5966
     5967/*
     5968 * Break the argument string into pieces based upon IFS and add the
     5969 * strings to the argument list.  The regions of the string to be
     5970 * searched for IFS characters have been stored by recordregion.
     5971 */
     5972static void
     5973ifsbreakup(char *string, struct arglist *arglist)
     5974{
     5975    struct ifsregion *ifsp;
     5976    struct strlist *sp;
     5977    char *start;
     5978    char *p;
     5979    char *q;
     5980    const char *ifs, *realifs;
     5981    int ifsspc;
     5982    int nulonly;
     5983
     5984    start = string;
     5985    if (ifslastp != NULL) {
     5986        ifsspc = 0;
     5987        nulonly = 0;
     5988        realifs = ifsset() ? ifsval() : defifs;
     5989        ifsp = &ifsfirst;
     5990        do {
     5991            p = string + ifsp->begoff;
     5992            nulonly = ifsp->nulonly;
     5993            ifs = nulonly ? nullstr : realifs;
     5994            ifsspc = 0;
     5995            while (p < string + ifsp->endoff) {
     5996                q = p;
     5997                if (*p == CTLESC)
     5998                    p++;
     5999                if (!strchr(ifs, *p)) {
     6000                    p++;
     6001                    continue;
     6002                }
     6003                if (!nulonly)
     6004                    ifsspc = (strchr(defifs, *p) != NULL);
     6005                /* Ignore IFS whitespace at start */
     6006                if (q == start && ifsspc) {
     6007                    p++;
     6008                    start = p;
     6009                    continue;
     6010                }
     6011                *q = '\0';
     6012                sp = stalloc(sizeof(*sp));
     6013                sp->text = start;
     6014                *arglist->lastp = sp;
     6015                arglist->lastp = &sp->next;
     6016                p++;
     6017                if (!nulonly) {
     6018                    for (;;) {
     6019                        if (p >= string + ifsp->endoff) {
     6020                            break;
     6021                        }
     6022                        q = p;
     6023                        if (*p == CTLESC)
     6024                            p++;
     6025                        if (strchr(ifs, *p) == NULL ) {
     6026                            p = q;
     6027                            break;
     6028                        } else if (strchr(defifs, *p) == NULL) {
     6029                            if (ifsspc) {
     6030                                p++;
     6031                                ifsspc = 0;
     6032                            } else {
     6033                                p = q;
     6034                                break;
     6035                            }
     6036                        } else
     6037                            p++;
     6038                    }
     6039                }
     6040                start = p;
     6041            } /* while */
     6042            ifsp = ifsp->next;
     6043        } while (ifsp != NULL);
     6044        if (nulonly)
     6045            goto add;
     6046    }
     6047
     6048    if (!*start)
     6049        return;
     6050
     6051 add:
     6052    sp = stalloc(sizeof(*sp));
     6053    sp->text = start;
     6054    *arglist->lastp = sp;
     6055    arglist->lastp = &sp->next;
     6056}
     6057
     6058static void
     6059ifsfree(void)
     6060{
     6061    struct ifsregion *p;
     6062
     6063    INT_OFF;
     6064    p = ifsfirst.next;
     6065    do {
     6066        struct ifsregion *ifsp;
     6067        ifsp = p->next;
     6068        free(p);
     6069        p = ifsp;
     6070    } while (p);
     6071    ifslastp = NULL;
     6072    ifsfirst.next = NULL;
     6073    INT_ON;
     6074}
     6075
     6076/*
     6077 * Add a file name to the list.
     6078 */
     6079static void
     6080addfname(const char *name)
     6081{
     6082    struct strlist *sp;
     6083
     6084    sp = stalloc(sizeof(*sp));
     6085    sp->text = ststrdup(name);
     6086    *exparg.lastp = sp;
     6087    exparg.lastp = &sp->next;
     6088}
     6089
     6090static char *expdir;
     6091
     6092/*
     6093 * Do metacharacter (i.e. *, ?, [...]) expansion.
     6094 */
     6095static void
     6096expmeta(char *enddir, char *name)
     6097{
     6098    char *p;
     6099    const char *cp;
     6100    char *start;
     6101    char *endname;
     6102    int metaflag;
     6103    struct stat statb;
     6104    DIR *dirp;
     6105    struct dirent *dp;
     6106    int atend;
     6107    int matchdot;
     6108
     6109    metaflag = 0;
     6110    start = name;
     6111    for (p = name; *p; p++) {
     6112        if (*p == '*' || *p == '?')
     6113            metaflag = 1;
     6114        else if (*p == '[') {
     6115            char *q = p + 1;
     6116            if (*q == '!')
     6117                q++;
     6118            for (;;) {
     6119                if (*q == '\\')
     6120                    q++;
     6121                if (*q == '/' || *q == '\0')
     6122                    break;
     6123                if (*++q == ']') {
     6124                    metaflag = 1;
     6125                    break;
     6126                }
     6127            }
     6128        } else if (*p == '\\')
     6129            p++;
     6130        else if (*p == '/') {
     6131            if (metaflag)
     6132                goto out;
     6133            start = p + 1;
     6134        }
     6135    }
     6136 out:
     6137    if (metaflag == 0) {    /* we've reached the end of the file name */
     6138        if (enddir != expdir)
     6139            metaflag++;
     6140        p = name;
     6141        do {
     6142            if (*p == '\\')
     6143                p++;
     6144            *enddir++ = *p;
     6145        } while (*p++);
     6146        if (metaflag == 0 || lstat(expdir, &statb) >= 0)
     6147            addfname(expdir);
     6148        return;
     6149    }
     6150    endname = p;
     6151    if (name < start) {
     6152        p = name;
     6153        do {
     6154            if (*p == '\\')
     6155                p++;
     6156            *enddir++ = *p++;
     6157        } while (p < start);
     6158    }
     6159    if (enddir == expdir) {
     6160        cp = ".";
     6161    } else if (enddir == expdir + 1 && *expdir == '/') {
     6162        cp = "/";
     6163    } else {
     6164        cp = expdir;
     6165        enddir[-1] = '\0';
     6166    }
     6167    dirp = opendir(cp);
     6168    if (dirp == NULL)
     6169        return;
     6170    if (enddir != expdir)
     6171        enddir[-1] = '/';
     6172    if (*endname == 0) {
     6173        atend = 1;
     6174    } else {
     6175        atend = 0;
     6176        *endname++ = '\0';
     6177    }
     6178    matchdot = 0;
     6179    p = start;
     6180    if (*p == '\\')
     6181        p++;
     6182    if (*p == '.')
     6183        matchdot++;
     6184    while (! intpending && (dp = readdir(dirp)) != NULL) {
     6185        if (dp->d_name[0] == '.' && ! matchdot)
     6186            continue;
     6187        if (pmatch(start, dp->d_name)) {
     6188            if (atend) {
     6189                strcpy(enddir, dp->d_name);
     6190                addfname(expdir);
     6191            } else {
     6192                for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
     6193                    continue;
     6194                p[-1] = '/';
     6195                expmeta(p, endname);
     6196            }
     6197        }
     6198    }
     6199    closedir(dirp);
     6200    if (! atend)
     6201        endname[-1] = '/';
     6202}
     6203
     6204static struct strlist *
     6205msort(struct strlist *list, int len)
     6206{
     6207    struct strlist *p, *q = NULL;
     6208    struct strlist **lpp;
     6209    int half;
     6210    int n;
     6211
     6212    if (len <= 1)
     6213        return list;
     6214    half = len >> 1;
     6215    p = list;
     6216    for (n = half; --n >= 0; ) {
     6217        q = p;
     6218        p = p->next;
     6219    }
     6220    q->next = NULL;                 /* terminate first half of list */
     6221    q = msort(list, half);          /* sort first half of list */
     6222    p = msort(p, len - half);               /* sort second half */
     6223    lpp = &list;
     6224    for (;;) {
     6225#if ENABLE_LOCALE_SUPPORT
     6226        if (strcoll(p->text, q->text) < 0)
     6227#else
     6228        if (strcmp(p->text, q->text) < 0)
     6229#endif
     6230                        {
     6231            *lpp = p;
     6232            lpp = &p->next;
     6233            p = *lpp;
     6234            if (p == NULL) {
     6235                *lpp = q;
     6236                break;
     6237            }
     6238        } else {
     6239            *lpp = q;
     6240            lpp = &q->next;
     6241            q = *lpp;
     6242            if (q == NULL) {
     6243                *lpp = p;
     6244                break;
     6245            }
     6246        }
     6247    }
     6248    return list;
     6249}
     6250
     6251/*
     6252 * Sort the results of file name expansion.  It calculates the number of
     6253 * strings to sort and then calls msort (short for merge sort) to do the
     6254 * work.
     6255 */
     6256static struct strlist *
     6257expsort(struct strlist *str)
     6258{
     6259    int len;
     6260    struct strlist *sp;
     6261
     6262    len = 0;
     6263    for (sp = str; sp; sp = sp->next)
     6264        len++;
     6265    return msort(str, len);
     6266}
     6267
     6268static void
     6269expandmeta(struct strlist *str, int flag)
     6270{
     6271    static const char metachars[] ALIGN1 = {
     6272        '*', '?', '[', 0
     6273    };
     6274    /* TODO - EXP_REDIR */
     6275
     6276    while (str) {
     6277        struct strlist **savelastp;
     6278        struct strlist *sp;
     6279        char *p;
     6280
     6281        if (fflag)
     6282            goto nometa;
     6283        if (!strpbrk(str->text, metachars))
     6284            goto nometa;
     6285        savelastp = exparg.lastp;
     6286
     6287        INT_OFF;
     6288        p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
     6289        {
     6290            int i = strlen(str->text);
     6291            expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
     6292        }
     6293
     6294        expmeta(expdir, p);
     6295        free(expdir);
     6296        if (p != str->text)
     6297            free(p);
     6298        INT_ON;
     6299        if (exparg.lastp == savelastp) {
     6300            /*
     6301             * no matches
     6302             */
     6303 nometa:
     6304            *exparg.lastp = str;
     6305            rmescapes(str->text);
     6306            exparg.lastp = &str->next;
     6307        } else {
     6308            *exparg.lastp = NULL;
     6309            *savelastp = sp = expsort(*savelastp);
     6310            while (sp->next != NULL)
     6311                sp = sp->next;
     6312            exparg.lastp = &sp->next;
     6313        }
     6314        str = str->next;
     6315    }
     6316}
     6317
     6318/*
     6319 * Perform variable substitution and command substitution on an argument,
     6320 * placing the resulting list of arguments in arglist.  If EXP_FULL is true,
     6321 * perform splitting and file name expansion.  When arglist is NULL, perform
     6322 * here document expansion.
     6323 */
     6324static void
     6325expandarg(union node *arg, struct arglist *arglist, int flag)
     6326{
     6327    struct strlist *sp;
     6328    char *p;
     6329
     6330    argbackq = arg->narg.backquote;
     6331    STARTSTACKSTR(expdest);
     6332    ifsfirst.next = NULL;
     6333    ifslastp = NULL;
     6334    argstr(arg->narg.text, flag);
     6335    p = _STPUTC('\0', expdest);
     6336    expdest = p - 1;
     6337    if (arglist == NULL) {
     6338        return;                 /* here document expanded */
     6339    }
     6340    p = grabstackstr(p);
     6341    exparg.lastp = &exparg.list;
     6342    /*
     6343     * TODO - EXP_REDIR
     6344     */
     6345    if (flag & EXP_FULL) {
     6346        ifsbreakup(p, &exparg);
     6347        *exparg.lastp = NULL;
     6348        exparg.lastp = &exparg.list;
     6349        expandmeta(exparg.list, flag);
     6350    } else {
     6351        if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
     6352            rmescapes(p);
     6353        sp = stalloc(sizeof(*sp));
     6354        sp->text = p;
     6355        *exparg.lastp = sp;
     6356        exparg.lastp = &sp->next;
     6357    }
     6358    if (ifsfirst.next)
     6359        ifsfree();
     6360    *exparg.lastp = NULL;
     6361    if (exparg.list) {
     6362        *arglist->lastp = exparg.list;
     6363        arglist->lastp = exparg.lastp;
     6364    }
     6365}
     6366
     6367/*
     6368 * Expand shell variables and backquotes inside a here document.
     6369 */
     6370static void
     6371expandhere(union node *arg, int fd)
     6372{
     6373    herefd = fd;
     6374    expandarg(arg, (struct arglist *)NULL, 0);
     6375    full_write(fd, stackblock(), expdest - (char *)stackblock());
     6376}
     6377
     6378/*
     6379 * Returns true if the pattern matches the string.
     6380 */
     6381static int
     6382patmatch(char *pattern, const char *string)
     6383{
     6384    return pmatch(preglob(pattern, 0, 0), string);
     6385}
     6386
     6387/*
     6388 * See if a pattern matches in a case statement.
     6389 */
     6390static int
     6391casematch(union node *pattern, char *val)
     6392{
     6393    struct stackmark smark;
     6394    int result;
     6395
     6396    setstackmark(&smark);
     6397    argbackq = pattern->narg.backquote;
     6398    STARTSTACKSTR(expdest);
     6399    ifslastp = NULL;
     6400    argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
     6401    STACKSTRNUL(expdest);
     6402    result = patmatch(stackblock(), val);
     6403    popstackmark(&smark);
     6404    return result;
     6405}
     6406
     6407
     6408/* ============ find_command */
     6409
     6410struct builtincmd {
     6411    const char *name;
     6412    int (*builtin)(int, char **);
     6413    /* unsigned flags; */
     6414};
     6415#define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
     6416#define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
     6417#define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
     6418
     6419struct cmdentry {
     6420    int cmdtype;
     6421    union param {
     6422        int index;
     6423        const struct builtincmd *cmd;
     6424        struct funcnode *func;
     6425    } u;
     6426};
     6427/* values of cmdtype */
     6428#define CMDUNKNOWN      -1      /* no entry in table for command */
     6429#define CMDNORMAL       0       /* command is an executable program */
     6430#define CMDFUNCTION     1       /* command is a shell function */
     6431#define CMDBUILTIN      2       /* command is a shell builtin */
     6432
     6433/* action to find_command() */
     6434#define DO_ERR          0x01    /* prints errors */
     6435#define DO_ABS          0x02    /* checks absolute paths */
     6436#define DO_NOFUNC       0x04    /* don't return shell functions, for command */
     6437#define DO_ALTPATH      0x08    /* using alternate path */
     6438#define DO_ALTBLTIN     0x20    /* %builtin in alt. path */
     6439
     6440static void find_command(char *, struct cmdentry *, int, const char *);
     6441
     6442
     6443/* ============ Hashing commands */
     6444
     6445/*
     6446 * When commands are first encountered, they are entered in a hash table.
     6447 * This ensures that a full path search will not have to be done for them
     6448 * on each invocation.
     6449 *
     6450 * We should investigate converting to a linear search, even though that
     6451 * would make the command name "hash" a misnomer.
     6452 */
     6453
     6454#define CMDTABLESIZE 31         /* should be prime */
     6455#define ARB 1                   /* actual size determined at run time */
     6456
     6457struct tblentry {
     6458    struct tblentry *next;  /* next entry in hash chain */
     6459    union param param;      /* definition of builtin function */
     6460    short cmdtype;          /* index identifying command */
     6461    char rehash;            /* if set, cd done since entry created */
     6462    char cmdname[ARB];      /* name of command */
     6463};
     6464
     6465static struct tblentry *cmdtable[CMDTABLESIZE];
     6466static int builtinloc = -1;             /* index in path of %builtin, or -1 */
     6467
     6468static void
     6469tryexec(char *cmd, char **argv, char **envp)
     6470{
     6471    int repeated = 0;
     6472
     6473#if ENABLE_FEATURE_SH_STANDALONE
     6474    if (strchr(cmd, '/') == NULL) {
     6475        const struct bb_applet *a;
     6476
     6477        a = find_applet_by_name(cmd);
     6478        if (a) {
     6479            if (a->noexec) {
     6480                current_applet = a;
     6481                run_current_applet_and_exit(argv);
     6482            }
     6483            /* re-exec ourselves with the new arguments */
     6484            execve(bb_busybox_exec_path, argv, envp);
     6485            /* If they called chroot or otherwise made the binary no longer
     6486             * executable, fall through */
     6487        }
     6488    }
     6489#endif
     6490
     6491 repeat:
     6492#ifdef SYSV
     6493    do {
     6494        execve(cmd, argv, envp);
     6495    } while (errno == EINTR);
     6496#else
     6497    execve(cmd, argv, envp);
     6498#endif
     6499    if (repeated++) {
     6500        free(argv);
     6501    } else if (errno == ENOEXEC) {
     6502        char **ap;
     6503        char **new;
     6504
     6505        for (ap = argv; *ap; ap++)
     6506            ;
     6507        ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
     6508        ap[1] = cmd;
     6509        ap[0] = cmd = (char *)DEFAULT_SHELL;
     6510        ap += 2;
     6511        argv++;
     6512        while ((*ap++ = *argv++))
     6513            ;
     6514        argv = new;
     6515        goto repeat;
     6516    }
     6517}
     6518
     6519/*
     6520 * Exec a program.  Never returns.  If you change this routine, you may
     6521 * have to change the find_command routine as well.
     6522 */
     6523#define environment() listvars(VEXPORT, VUNSET, 0)
     6524static void shellexec(char **, const char *, int) ATTRIBUTE_NORETURN;
     6525static void
     6526shellexec(char **argv, const char *path, int idx)
     6527{
     6528    char *cmdname;
     6529    int e;
     6530    char **envp;
     6531    int exerrno;
     6532
     6533    clearredir(1);
     6534    envp = environment();
     6535    if (strchr(argv[0], '/')
     6536#if ENABLE_FEATURE_SH_STANDALONE
     6537     || find_applet_by_name(argv[0])
     6538#endif
     6539    ) {
     6540        tryexec(argv[0], argv, envp);
     6541        e = errno;
     6542    } else {
     6543        e = ENOENT;
     6544        while ((cmdname = padvance(&path, argv[0])) != NULL) {
     6545            if (--idx < 0 && pathopt == NULL) {
     6546                tryexec(cmdname, argv, envp);
     6547                if (errno != ENOENT && errno != ENOTDIR)
     6548                    e = errno;
     6549            }
     6550            stunalloc(cmdname);
     6551        }
     6552    }
     6553
     6554    /* Map to POSIX errors */
     6555    switch (e) {
     6556    case EACCES:
     6557        exerrno = 126;
     6558        break;
     6559    case ENOENT:
     6560        exerrno = 127;
     6561        break;
     6562    default:
     6563        exerrno = 2;
     6564        break;
     6565    }
     6566    exitstatus = exerrno;
     6567    TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
     6568        argv[0], e, suppressint ));
     6569    ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found"));
     6570    /* NOTREACHED */
     6571}
     6572
     6573static void
     6574printentry(struct tblentry *cmdp)
     6575{
     6576    int idx;
     6577    const char *path;
     6578    char *name;
     6579
     6580    idx = cmdp->param.index;
     6581    path = pathval();
     6582    do {
     6583        name = padvance(&path, cmdp->cmdname);
     6584        stunalloc(name);
     6585    } while (--idx >= 0);
     6586    out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
     6587}
     6588
     6589/*
     6590 * Clear out command entries.  The argument specifies the first entry in
     6591 * PATH which has changed.
     6592 */
     6593static void
     6594clearcmdentry(int firstchange)
     6595{
     6596    struct tblentry **tblp;
     6597    struct tblentry **pp;
     6598    struct tblentry *cmdp;
     6599
     6600    INT_OFF;
     6601    for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
     6602        pp = tblp;
     6603        while ((cmdp = *pp) != NULL) {
     6604            if ((cmdp->cmdtype == CMDNORMAL &&
     6605                 cmdp->param.index >= firstchange)
     6606             || (cmdp->cmdtype == CMDBUILTIN &&
     6607                 builtinloc >= firstchange)
     6608            ) {
     6609                *pp = cmdp->next;
     6610                free(cmdp);
     6611            } else {
     6612                pp = &cmdp->next;
     6613            }
     6614        }
     6615    }
     6616    INT_ON;
     6617}
     6618
     6619/*
     6620 * Locate a command in the command hash table.  If "add" is nonzero,
     6621 * add the command to the table if it is not already present.  The
     6622 * variable "lastcmdentry" is set to point to the address of the link
     6623 * pointing to the entry, so that delete_cmd_entry can delete the
     6624 * entry.
     6625 *
     6626 * Interrupts must be off if called with add != 0.
     6627 */
     6628static struct tblentry **lastcmdentry;
     6629
     6630static struct tblentry *
     6631cmdlookup(const char *name, int add)
     6632{
     6633    unsigned int hashval;
     6634    const char *p;
     6635    struct tblentry *cmdp;
     6636    struct tblentry **pp;
     6637
     6638    p = name;
     6639    hashval = (unsigned char)*p << 4;
     6640    while (*p)
     6641        hashval += (unsigned char)*p++;
     6642    hashval &= 0x7FFF;
     6643    pp = &cmdtable[hashval % CMDTABLESIZE];
     6644    for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
     6645        if (strcmp(cmdp->cmdname, name) == 0)
     6646            break;
     6647        pp = &cmdp->next;
     6648    }
     6649    if (add && cmdp == NULL) {
     6650        cmdp = *pp = ckmalloc(sizeof(struct tblentry) - ARB
     6651                    + strlen(name) + 1);
     6652        cmdp->next = NULL;
     6653        cmdp->cmdtype = CMDUNKNOWN;
     6654        strcpy(cmdp->cmdname, name);
     6655    }
     6656    lastcmdentry = pp;
     6657    return cmdp;
     6658}
     6659
     6660/*
     6661 * Delete the command entry returned on the last lookup.
     6662 */
     6663static void
     6664delete_cmd_entry(void)
     6665{
     6666    struct tblentry *cmdp;
     6667
     6668    INT_OFF;
     6669    cmdp = *lastcmdentry;
     6670    *lastcmdentry = cmdp->next;
     6671    if (cmdp->cmdtype == CMDFUNCTION)
     6672        freefunc(cmdp->param.func);
     6673    free(cmdp);
     6674    INT_ON;
     6675}
     6676
     6677/*
     6678 * Add a new command entry, replacing any existing command entry for
     6679 * the same name - except special builtins.
     6680 */
     6681static void
     6682addcmdentry(char *name, struct cmdentry *entry)
     6683{
     6684    struct tblentry *cmdp;
     6685
     6686    cmdp = cmdlookup(name, 1);
     6687    if (cmdp->cmdtype == CMDFUNCTION) {
     6688        freefunc(cmdp->param.func);
     6689    }
     6690    cmdp->cmdtype = entry->cmdtype;
     6691    cmdp->param = entry->u;
     6692    cmdp->rehash = 0;
     6693}
     6694
     6695static int
     6696hashcmd(int argc, char **argv)
     6697{
     6698    struct tblentry **pp;
     6699    struct tblentry *cmdp;
     6700    int c;
     6701    struct cmdentry entry;
     6702    char *name;
     6703
     6704    while ((c = nextopt("r")) != '\0') {
     6705        clearcmdentry(0);
     6706        return 0;
     6707    }
     6708    if (*argptr == NULL) {
     6709        for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
     6710            for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
     6711                if (cmdp->cmdtype == CMDNORMAL)
     6712                    printentry(cmdp);
     6713            }
     6714        }
     6715        return 0;
     6716    }
     6717    c = 0;
     6718    while ((name = *argptr) != NULL) {
     6719        cmdp = cmdlookup(name, 0);
     6720        if (cmdp != NULL
     6721         && (cmdp->cmdtype == CMDNORMAL
     6722             || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
     6723            delete_cmd_entry();
     6724        find_command(name, &entry, DO_ERR, pathval());
     6725        if (entry.cmdtype == CMDUNKNOWN)
     6726            c = 1;
     6727        argptr++;
     6728    }
     6729    return c;
     6730}
     6731
     6732/*
     6733 * Called when a cd is done.  Marks all commands so the next time they
     6734 * are executed they will be rehashed.
     6735 */
     6736static void
     6737hashcd(void)
     6738{
     6739    struct tblentry **pp;
     6740    struct tblentry *cmdp;
     6741
     6742    for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
     6743        for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
     6744            if (cmdp->cmdtype == CMDNORMAL || (
     6745                cmdp->cmdtype == CMDBUILTIN &&
     6746                !(IS_BUILTIN_REGULAR(cmdp->param.cmd)) &&
     6747                builtinloc > 0
     6748            ))
     6749                cmdp->rehash = 1;
     6750        }
     6751    }
     6752}
     6753
     6754/*
     6755 * Fix command hash table when PATH changed.
     6756 * Called before PATH is changed.  The argument is the new value of PATH;
     6757 * pathval() still returns the old value at this point.
     6758 * Called with interrupts off.
     6759 */
     6760static void
     6761changepath(const char *newval)
     6762{
     6763    const char *old, *new;
     6764    int idx;
     6765    int firstchange;
     6766    int idx_bltin;
     6767
     6768    old = pathval();
     6769    new = newval;
     6770    firstchange = 9999;     /* assume no change */
     6771    idx = 0;
     6772    idx_bltin = -1;
     6773    for (;;) {
     6774        if (*old != *new) {
     6775            firstchange = idx;
     6776            if ((*old == '\0' && *new == ':')
     6777             || (*old == ':' && *new == '\0'))
     6778                firstchange++;
     6779            old = new;      /* ignore subsequent differences */
     6780        }
     6781        if (*new == '\0')
     6782            break;
     6783        if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
     6784            idx_bltin = idx;
     6785        if (*new == ':') {
     6786            idx++;
     6787        }
     6788        new++, old++;
     6789    }
     6790    if (builtinloc < 0 && idx_bltin >= 0)
     6791        builtinloc = idx_bltin;             /* zap builtins */
     6792    if (builtinloc >= 0 && idx_bltin < 0)
     6793        firstchange = 0;
     6794    clearcmdentry(firstchange);
     6795    builtinloc = idx_bltin;
     6796}
     6797
     6798#define TEOF 0
     6799#define TNL 1
     6800#define TREDIR 2
     6801#define TWORD 3
     6802#define TSEMI 4
     6803#define TBACKGND 5
     6804#define TAND 6
     6805#define TOR 7
     6806#define TPIPE 8
     6807#define TLP 9
     6808#define TRP 10
     6809#define TENDCASE 11
     6810#define TENDBQUOTE 12
     6811#define TNOT 13
     6812#define TCASE 14
     6813#define TDO 15
     6814#define TDONE 16
     6815#define TELIF 17
     6816#define TELSE 18
     6817#define TESAC 19
     6818#define TFI 20
     6819#define TFOR 21
     6820#define TIF 22
     6821#define TIN 23
     6822#define TTHEN 24
     6823#define TUNTIL 25
     6824#define TWHILE 26
     6825#define TBEGIN 27
     6826#define TEND 28
     6827
     6828/* first char is indicating which tokens mark the end of a list */
     6829static const char *const tokname_array[] = {
     6830    "\1end of file",
     6831    "\0newline",
     6832    "\0redirection",
     6833    "\0word",
     6834    "\0;",
     6835    "\0&",
     6836    "\0&&",
     6837    "\0||",
     6838    "\0|",
     6839    "\0(",
     6840    "\1)",
     6841    "\1;;",
     6842    "\1`",
     6843#define KWDOFFSET 13
     6844    /* the following are keywords */
     6845    "\0!",
     6846    "\0case",
     6847    "\1do",
     6848    "\1done",
     6849    "\1elif",
     6850    "\1else",
     6851    "\1esac",
     6852    "\1fi",
     6853    "\0for",
     6854    "\0if",
     6855    "\0in",
     6856    "\1then",
     6857    "\0until",
     6858    "\0while",
     6859    "\0{",
     6860    "\1}",
     6861};
     6862
     6863static const char *
     6864tokname(int tok)
     6865{
     6866    static char buf[16];
     6867
     6868//try this:
     6869//if (tok < TSEMI) return tokname_array[tok] + 1;
     6870//sprintf(buf, "\"%s\"", tokname_array[tok] + 1);
     6871//return buf;
     6872
     6873    if (tok >= TSEMI)
     6874        buf[0] = '"';
     6875    sprintf(buf + (tok >= TSEMI), "%s%c",
     6876            tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0));
     6877    return buf;
     6878}
     6879
     6880/* Wrapper around strcmp for qsort/bsearch/... */
     6881static int
     6882pstrcmp(const void *a, const void *b)
     6883{
     6884    return strcmp((char*) a, (*(char**) b) + 1);
     6885}
     6886
     6887static const char *const *
     6888findkwd(const char *s)
     6889{
     6890    return bsearch(s, tokname_array + KWDOFFSET,
     6891            ARRAY_SIZE(tokname_array) - KWDOFFSET,
     6892            sizeof(tokname_array[0]), pstrcmp);
     6893}
     6894
     6895/*
     6896 * Locate and print what a word is...
     6897 */
     6898static int
     6899describe_command(char *command, int describe_command_verbose)
     6900{
     6901    struct cmdentry entry;
     6902    struct tblentry *cmdp;
     6903#if ENABLE_ASH_ALIAS
     6904    const struct alias *ap;
     6905#endif
     6906    const char *path = pathval();
     6907
     6908    if (describe_command_verbose) {
     6909        out1str(command);
     6910    }
     6911
     6912    /* First look at the keywords */
     6913    if (findkwd(command)) {
     6914        out1str(describe_command_verbose ? " is a shell keyword" : command);
     6915        goto out;
     6916    }
     6917
     6918#if ENABLE_ASH_ALIAS
     6919    /* Then look at the aliases */
     6920    ap = lookupalias(command, 0);
     6921    if (ap != NULL) {
     6922        if (!describe_command_verbose) {
     6923            out1str("alias ");
     6924            printalias(ap);
     6925            return 0;
     6926        }
     6927        out1fmt(" is an alias for %s", ap->val);
     6928        goto out;
     6929    }
     6930#endif
     6931    /* Then check if it is a tracked alias */
     6932    cmdp = cmdlookup(command, 0);
     6933    if (cmdp != NULL) {
     6934        entry.cmdtype = cmdp->cmdtype;
     6935        entry.u = cmdp->param;
     6936    } else {
     6937        /* Finally use brute force */
     6938        find_command(command, &entry, DO_ABS, path);
     6939    }
     6940
     6941    switch (entry.cmdtype) {
     6942    case CMDNORMAL: {
     6943        int j = entry.u.index;
     6944        char *p;
     6945        if (j == -1) {
     6946            p = command;
     6947        } else {
     6948            do {
     6949                p = padvance(&path, command);
     6950                stunalloc(p);
     6951            } while (--j >= 0);
     6952        }
     6953        if (describe_command_verbose) {
     6954            out1fmt(" is%s %s",
     6955                (cmdp ? " a tracked alias for" : nullstr), p
     6956            );
     6957        } else {
     6958            out1str(p);
     6959        }
     6960        break;
     6961    }
     6962
     6963    case CMDFUNCTION:
     6964        if (describe_command_verbose) {
     6965            out1str(" is a shell function");
     6966        } else {
     6967            out1str(command);
     6968        }
     6969        break;
     6970
     6971    case CMDBUILTIN:
     6972        if (describe_command_verbose) {
     6973            out1fmt(" is a %sshell builtin",
     6974                IS_BUILTIN_SPECIAL(entry.u.cmd) ?
     6975                    "special " : nullstr
     6976            );
     6977        } else {
     6978            out1str(command);
     6979        }
     6980        break;
     6981
     6982    default:
     6983        if (describe_command_verbose) {
     6984            out1str(": not found\n");
     6985        }
     6986        return 127;
     6987    }
     6988 out:
     6989    outstr("\n", stdout);
     6990    return 0;
     6991}
     6992
     6993static int
     6994typecmd(int argc, char **argv)
     6995{
     6996    int i = 1;
     6997    int err = 0;
     6998    int verbose = 1;
     6999
     7000    /* type -p ... ? (we don't bother checking for 'p') */
     7001    if (argv[1] && argv[1][0] == '-') {
     7002        i++;
     7003        verbose = 0;
     7004    }
     7005    while (i < argc) {
     7006        err |= describe_command(argv[i++], verbose);
     7007    }
     7008    return err;
     7009}
     7010
     7011#if ENABLE_ASH_CMDCMD
     7012static int
     7013commandcmd(int argc, char **argv)
     7014{
     7015    int c;
     7016    enum {
     7017        VERIFY_BRIEF = 1,
     7018        VERIFY_VERBOSE = 2,
     7019    } verify = 0;
     7020
     7021    while ((c = nextopt("pvV")) != '\0')
     7022        if (c == 'V')
     7023            verify |= VERIFY_VERBOSE;
     7024        else if (c == 'v')
     7025            verify |= VERIFY_BRIEF;
     7026#if DEBUG
     7027        else if (c != 'p')
     7028            abort();
     7029#endif
     7030    if (verify)
     7031        return describe_command(*argptr, verify - VERIFY_BRIEF);
     7032
     7033    return 0;
     7034}
     7035#endif
     7036
     7037
     7038/* ============ eval.c */
     7039
     7040static int funcblocksize;          /* size of structures in function */
     7041static int funcstringsize;         /* size of strings in node */
     7042static void *funcblock;            /* block to allocate function from */
     7043static char *funcstring;           /* block to allocate strings from */
     7044
     7045/* flags in argument to evaltree */
     7046#define EV_EXIT 01              /* exit after evaluating tree */
     7047#define EV_TESTED 02            /* exit status is checked; ignore -e flag */
     7048#define EV_BACKCMD 04           /* command executing within back quotes */
     7049
     7050static const short nodesize[26] = {
     7051    SHELL_ALIGN(sizeof(struct ncmd)),
     7052    SHELL_ALIGN(sizeof(struct npipe)),
     7053    SHELL_ALIGN(sizeof(struct nredir)),
     7054    SHELL_ALIGN(sizeof(struct nredir)),
     7055    SHELL_ALIGN(sizeof(struct nredir)),
     7056    SHELL_ALIGN(sizeof(struct nbinary)),
     7057    SHELL_ALIGN(sizeof(struct nbinary)),
     7058    SHELL_ALIGN(sizeof(struct nbinary)),
     7059    SHELL_ALIGN(sizeof(struct nif)),
     7060    SHELL_ALIGN(sizeof(struct nbinary)),
     7061    SHELL_ALIGN(sizeof(struct nbinary)),
     7062    SHELL_ALIGN(sizeof(struct nfor)),
     7063    SHELL_ALIGN(sizeof(struct ncase)),
     7064    SHELL_ALIGN(sizeof(struct nclist)),
     7065    SHELL_ALIGN(sizeof(struct narg)),
     7066    SHELL_ALIGN(sizeof(struct narg)),
     7067    SHELL_ALIGN(sizeof(struct nfile)),
     7068    SHELL_ALIGN(sizeof(struct nfile)),
     7069    SHELL_ALIGN(sizeof(struct nfile)),
     7070    SHELL_ALIGN(sizeof(struct nfile)),
     7071    SHELL_ALIGN(sizeof(struct nfile)),
     7072    SHELL_ALIGN(sizeof(struct ndup)),
     7073    SHELL_ALIGN(sizeof(struct ndup)),
     7074    SHELL_ALIGN(sizeof(struct nhere)),
     7075    SHELL_ALIGN(sizeof(struct nhere)),
     7076    SHELL_ALIGN(sizeof(struct nnot)),
     7077};
     7078
     7079static void calcsize(union node *n);
     7080
     7081static void
     7082sizenodelist(struct nodelist *lp)
     7083{
     7084    while (lp) {
     7085        funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
     7086        calcsize(lp->n);
     7087        lp = lp->next;
     7088    }
     7089}
     7090
     7091static void
     7092calcsize(union node *n)
     7093{
     7094    if (n == NULL)
     7095        return;
     7096    funcblocksize += nodesize[n->type];
     7097    switch (n->type) {
     7098    case NCMD:
     7099        calcsize(n->ncmd.redirect);
     7100        calcsize(n->ncmd.args);
     7101        calcsize(n->ncmd.assign);
     7102        break;
     7103    case NPIPE:
     7104        sizenodelist(n->npipe.cmdlist);
     7105        break;
     7106    case NREDIR:
     7107    case NBACKGND:
     7108    case NSUBSHELL:
     7109        calcsize(n->nredir.redirect);
     7110        calcsize(n->nredir.n);
     7111        break;
     7112    case NAND:
     7113    case NOR:
     7114    case NSEMI:
     7115    case NWHILE:
     7116    case NUNTIL:
     7117        calcsize(n->nbinary.ch2);
     7118        calcsize(n->nbinary.ch1);
     7119        break;
     7120    case NIF:
     7121        calcsize(n->nif.elsepart);
     7122        calcsize(n->nif.ifpart);
     7123        calcsize(n->nif.test);
     7124        break;
     7125    case NFOR:
     7126        funcstringsize += strlen(n->nfor.var) + 1;
     7127        calcsize(n->nfor.body);
     7128        calcsize(n->nfor.args);
     7129        break;
     7130    case NCASE:
     7131        calcsize(n->ncase.cases);
     7132        calcsize(n->ncase.expr);
     7133        break;
     7134    case NCLIST:
     7135        calcsize(n->nclist.body);
     7136        calcsize(n->nclist.pattern);
     7137        calcsize(n->nclist.next);
     7138        break;
     7139    case NDEFUN:
     7140    case NARG:
     7141        sizenodelist(n->narg.backquote);
     7142        funcstringsize += strlen(n->narg.text) + 1;
     7143        calcsize(n->narg.next);
     7144        break;
     7145    case NTO:
     7146    case NCLOBBER:
     7147    case NFROM:
     7148    case NFROMTO:
     7149    case NAPPEND:
     7150        calcsize(n->nfile.fname);
     7151        calcsize(n->nfile.next);
     7152        break;
     7153    case NTOFD:
     7154    case NFROMFD:
     7155        calcsize(n->ndup.vname);
     7156        calcsize(n->ndup.next);
     7157    break;
     7158    case NHERE:
     7159    case NXHERE:
     7160        calcsize(n->nhere.doc);
     7161        calcsize(n->nhere.next);
     7162        break;
     7163    case NNOT:
     7164        calcsize(n->nnot.com);
     7165        break;
     7166    };
     7167}
     7168
     7169static char *
     7170nodeckstrdup(char *s)
     7171{
     7172    char *rtn = funcstring;
     7173
     7174    strcpy(funcstring, s);
     7175    funcstring += strlen(s) + 1;
     7176    return rtn;
     7177}
     7178
     7179static union node *copynode(union node *);
     7180
     7181static struct nodelist *
     7182copynodelist(struct nodelist *lp)
     7183{
     7184    struct nodelist *start;
     7185    struct nodelist **lpp;
     7186
     7187    lpp = &start;
     7188    while (lp) {
     7189        *lpp = funcblock;
     7190        funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
     7191        (*lpp)->n = copynode(lp->n);
     7192        lp = lp->next;
     7193        lpp = &(*lpp)->next;
     7194    }
     7195    *lpp = NULL;
     7196    return start;
     7197}
     7198
     7199static union node *
     7200copynode(union node *n)
     7201{
     7202    union node *new;
     7203
     7204    if (n == NULL)
     7205        return NULL;
     7206    new = funcblock;
     7207    funcblock = (char *) funcblock + nodesize[n->type];
     7208
     7209    switch (n->type) {
     7210    case NCMD:
     7211        new->ncmd.redirect = copynode(n->ncmd.redirect);
     7212        new->ncmd.args = copynode(n->ncmd.args);
     7213        new->ncmd.assign = copynode(n->ncmd.assign);
     7214        break;
     7215    case NPIPE:
     7216        new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
     7217        new->npipe.backgnd = n->npipe.backgnd;
     7218        break;
     7219    case NREDIR:
     7220    case NBACKGND:
     7221    case NSUBSHELL:
     7222        new->nredir.redirect = copynode(n->nredir.redirect);
     7223        new->nredir.n = copynode(n->nredir.n);
     7224        break;
     7225    case NAND:
     7226    case NOR:
     7227    case NSEMI:
     7228    case NWHILE:
     7229    case NUNTIL:
     7230        new->nbinary.ch2 = copynode(n->nbinary.ch2);
     7231        new->nbinary.ch1 = copynode(n->nbinary.ch1);
     7232        break;
     7233    case NIF:
     7234        new->nif.elsepart = copynode(n->nif.elsepart);
     7235        new->nif.ifpart = copynode(n->nif.ifpart);
     7236        new->nif.test = copynode(n->nif.test);
     7237        break;
     7238    case NFOR:
     7239        new->nfor.var = nodeckstrdup(n->nfor.var);
     7240        new->nfor.body = copynode(n->nfor.body);
     7241        new->nfor.args = copynode(n->nfor.args);
     7242        break;
     7243    case NCASE:
     7244        new->ncase.cases = copynode(n->ncase.cases);
     7245        new->ncase.expr = copynode(n->ncase.expr);
     7246        break;
     7247    case NCLIST:
     7248        new->nclist.body = copynode(n->nclist.body);
     7249        new->nclist.pattern = copynode(n->nclist.pattern);
     7250        new->nclist.next = copynode(n->nclist.next);
     7251        break;
     7252    case NDEFUN:
     7253    case NARG:
     7254        new->narg.backquote = copynodelist(n->narg.backquote);
     7255        new->narg.text = nodeckstrdup(n->narg.text);
     7256        new->narg.next = copynode(n->narg.next);
     7257        break;
     7258    case NTO:
     7259    case NCLOBBER:
     7260    case NFROM:
     7261    case NFROMTO:
     7262    case NAPPEND:
     7263        new->nfile.fname = copynode(n->nfile.fname);
     7264        new->nfile.fd = n->nfile.fd;
     7265        new->nfile.next = copynode(n->nfile.next);
     7266        break;
     7267    case NTOFD:
     7268    case NFROMFD:
     7269        new->ndup.vname = copynode(n->ndup.vname);
     7270        new->ndup.dupfd = n->ndup.dupfd;
     7271        new->ndup.fd = n->ndup.fd;
     7272        new->ndup.next = copynode(n->ndup.next);
     7273        break;
     7274    case NHERE:
     7275    case NXHERE:
     7276        new->nhere.doc = copynode(n->nhere.doc);
     7277        new->nhere.fd = n->nhere.fd;
     7278        new->nhere.next = copynode(n->nhere.next);
     7279        break;
     7280    case NNOT:
     7281        new->nnot.com = copynode(n->nnot.com);
     7282        break;
     7283    };
     7284    new->type = n->type;
     7285    return new;
     7286}
     7287
     7288/*
     7289 * Make a copy of a parse tree.
     7290 */
     7291static struct funcnode *
     7292copyfunc(union node *n)
     7293{
     7294    struct funcnode *f;
     7295    size_t blocksize;
     7296
     7297    funcblocksize = offsetof(struct funcnode, n);
     7298    funcstringsize = 0;
     7299    calcsize(n);
     7300    blocksize = funcblocksize;
     7301    f = ckmalloc(blocksize + funcstringsize);
     7302    funcblock = (char *) f + offsetof(struct funcnode, n);
     7303    funcstring = (char *) f + blocksize;
     7304    copynode(n);
     7305    f->count = 0;
     7306    return f;
     7307}
     7308
     7309/*
     7310 * Define a shell function.
     7311 */
     7312static void
     7313defun(char *name, union node *func)
     7314{
     7315    struct cmdentry entry;
     7316
     7317    INT_OFF;
     7318    entry.cmdtype = CMDFUNCTION;
     7319    entry.u.func = copyfunc(func);
     7320    addcmdentry(name, &entry);
     7321    INT_ON;
     7322}
     7323
     7324static int evalskip;            /* set if we are skipping commands */
     7325/* reasons for skipping commands (see comment on breakcmd routine) */
     7326#define SKIPBREAK      (1 << 0)
     7327#define SKIPCONT       (1 << 1)
     7328#define SKIPFUNC       (1 << 2)
     7329#define SKIPFILE       (1 << 3)
     7330#define SKIPEVAL       (1 << 4)
     7331static int skipcount;           /* number of levels to skip */
     7332static int funcnest;            /* depth of function calls */
     7333
     7334/* forward decl way out to parsing code - dotrap needs it */
     7335static int evalstring(char *s, int mask);
     7336
     7337/*
     7338 * Called to execute a trap.  Perhaps we should avoid entering new trap
     7339 * handlers while we are executing a trap handler.
     7340 */
     7341static int
     7342dotrap(void)
     7343{
     7344    char *p;
     7345    char *q;
     7346    int i;
     7347    int savestatus;
     7348    int skip = 0;
     7349
     7350    savestatus = exitstatus;
     7351    pendingsig = 0;
     7352    xbarrier();
     7353
     7354    for (i = 0, q = gotsig; i < NSIG - 1; i++, q++) {
     7355        if (!*q)
     7356            continue;
     7357        *q = '\0';
     7358
     7359        p = trap[i + 1];
     7360        if (!p)
     7361            continue;
     7362        skip = evalstring(p, SKIPEVAL);
     7363        exitstatus = savestatus;
     7364        if (skip)
     7365            break;
     7366    }
     7367
     7368    return skip;
     7369}
     7370
     7371/* forward declarations - evaluation is fairly recursive business... */
     7372static void evalloop(union node *, int);
     7373static void evalfor(union node *, int);
     7374static void evalcase(union node *, int);
     7375static void evalsubshell(union node *, int);
     7376static void expredir(union node *);
     7377static void evalpipe(union node *, int);
     7378static void evalcommand(union node *, int);
     7379static int evalbltin(const struct builtincmd *, int, char **);
     7380static void prehash(union node *);
     7381
     7382/*
     7383 * Evaluate a parse tree.  The value is left in the global variable
     7384 * exitstatus.
     7385 */
     7386static void
     7387evaltree(union node *n, int flags)
     7388{
     7389    int checkexit = 0;
     7390    void (*evalfn)(union node *, int);
     7391    unsigned isor;
    77457392    int status;
    7746     int retval;
    7747 
    7748     status = job->ps[job->nprocs - 1].status;
    7749     retval = WEXITSTATUS(status);
    7750     if (!WIFEXITED(status)) {
     7393    if (n == NULL) {
     7394        TRACE(("evaltree(NULL) called\n"));
     7395        goto out;
     7396    }
     7397    TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
     7398            getpid(), n, n->type, flags));
     7399    switch (n->type) {
     7400    default:
     7401#if DEBUG
     7402        out1fmt("Node type = %d\n", n->type);
     7403        fflush(stdout);
     7404        break;
     7405#endif
     7406    case NNOT:
     7407        evaltree(n->nnot.com, EV_TESTED);
     7408        status = !exitstatus;
     7409        goto setstatus;
     7410    case NREDIR:
     7411        expredir(n->nredir.redirect);
     7412        status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
     7413        if (!status) {
     7414            evaltree(n->nredir.n, flags & EV_TESTED);
     7415            status = exitstatus;
     7416        }
     7417        popredir(0);
     7418        goto setstatus;
     7419    case NCMD:
     7420        evalfn = evalcommand;
     7421 checkexit:
     7422        if (eflag && !(flags & EV_TESTED))
     7423            checkexit = ~0;
     7424        goto calleval;
     7425    case NFOR:
     7426        evalfn = evalfor;
     7427        goto calleval;
     7428    case NWHILE:
     7429    case NUNTIL:
     7430        evalfn = evalloop;
     7431        goto calleval;
     7432    case NSUBSHELL:
     7433    case NBACKGND:
     7434        evalfn = evalsubshell;
     7435        goto calleval;
     7436    case NPIPE:
     7437        evalfn = evalpipe;
     7438        goto checkexit;
     7439    case NCASE:
     7440        evalfn = evalcase;
     7441        goto calleval;
     7442    case NAND:
     7443    case NOR:
     7444    case NSEMI:
     7445#if NAND + 1 != NOR
     7446#error NAND + 1 != NOR
     7447#endif
     7448#if NOR + 1 != NSEMI
     7449#error NOR + 1 != NSEMI
     7450#endif
     7451        isor = n->type - NAND;
     7452        evaltree(
     7453            n->nbinary.ch1,
     7454            (flags | ((isor >> 1) - 1)) & EV_TESTED
     7455        );
     7456        if (!exitstatus == isor)
     7457            break;
     7458        if (!evalskip) {
     7459            n = n->nbinary.ch2;
     7460 evaln:
     7461            evalfn = evaltree;
     7462 calleval:
     7463            evalfn(n, flags);
     7464            break;
     7465        }
     7466        break;
     7467    case NIF:
     7468        evaltree(n->nif.test, EV_TESTED);
     7469        if (evalskip)
     7470            break;
     7471        if (exitstatus == 0) {
     7472            n = n->nif.ifpart;
     7473            goto evaln;
     7474        } else if (n->nif.elsepart) {
     7475            n = n->nif.elsepart;
     7476            goto evaln;
     7477        }
     7478        goto success;
     7479    case NDEFUN:
     7480        defun(n->narg.text, n->narg.next);
     7481 success:
     7482        status = 0;
     7483 setstatus:
     7484        exitstatus = status;
     7485        break;
     7486    }
     7487 out:
     7488    if ((checkexit & exitstatus))
     7489        evalskip |= SKIPEVAL;
     7490    else if (pendingsig && dotrap())
     7491        goto exexit;
     7492
     7493    if (flags & EV_EXIT) {
     7494 exexit:
     7495        raise_exception(EXEXIT);
     7496    }
     7497}
     7498
     7499#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
     7500static
     7501#endif
     7502void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
     7503
     7504static int loopnest;            /* current loop nesting level */
     7505
     7506static void
     7507evalloop(union node *n, int flags)
     7508{
     7509    int status;
     7510
     7511    loopnest++;
     7512    status = 0;
     7513    flags &= EV_TESTED;
     7514    for (;;) {
     7515        int i;
     7516
     7517        evaltree(n->nbinary.ch1, EV_TESTED);
     7518        if (evalskip) {
     7519 skipping:
     7520            if (evalskip == SKIPCONT && --skipcount <= 0) {
     7521                evalskip = 0;
     7522                continue;
     7523            }
     7524            if (evalskip == SKIPBREAK && --skipcount <= 0)
     7525                evalskip = 0;
     7526            break;
     7527        }
     7528        i = exitstatus;
     7529        if (n->type != NWHILE)
     7530            i = !i;
     7531        if (i != 0)
     7532            break;
     7533        evaltree(n->nbinary.ch2, flags);
     7534        status = exitstatus;
     7535        if (evalskip)
     7536            goto skipping;
     7537    }
     7538    loopnest--;
     7539    exitstatus = status;
     7540}
     7541
     7542static void
     7543evalfor(union node *n, int flags)
     7544{
     7545    struct arglist arglist;
     7546    union node *argp;
     7547    struct strlist *sp;
     7548    struct stackmark smark;
     7549
     7550    setstackmark(&smark);
     7551    arglist.lastp = &arglist.list;
     7552    for (argp = n->nfor.args; argp; argp = argp->narg.next) {
     7553        expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
     7554        /* XXX */
     7555        if (evalskip)
     7556            goto out;
     7557    }
     7558    *arglist.lastp = NULL;
     7559
     7560    exitstatus = 0;
     7561    loopnest++;
     7562    flags &= EV_TESTED;
     7563    for (sp = arglist.list; sp; sp = sp->next) {
     7564        setvar(n->nfor.var, sp->text, 0);
     7565        evaltree(n->nfor.body, flags);
     7566        if (evalskip) {
     7567            if (evalskip == SKIPCONT && --skipcount <= 0) {
     7568                evalskip = 0;
     7569                continue;
     7570            }
     7571            if (evalskip == SKIPBREAK && --skipcount <= 0)
     7572                evalskip = 0;
     7573            break;
     7574        }
     7575    }
     7576    loopnest--;
     7577 out:
     7578    popstackmark(&smark);
     7579}
     7580
     7581static void
     7582evalcase(union node *n, int flags)
     7583{
     7584    union node *cp;
     7585    union node *patp;
     7586    struct arglist arglist;
     7587    struct stackmark smark;
     7588
     7589    setstackmark(&smark);
     7590    arglist.lastp = &arglist.list;
     7591    expandarg(n->ncase.expr, &arglist, EXP_TILDE);
     7592    exitstatus = 0;
     7593    for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
     7594        for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
     7595            if (casematch(patp, arglist.list->text)) {
     7596                if (evalskip == 0) {
     7597                    evaltree(cp->nclist.body, flags);
     7598                }
     7599                goto out;
     7600            }
     7601        }
     7602    }
     7603 out:
     7604    popstackmark(&smark);
     7605}
     7606
     7607/*
     7608 * Kick off a subshell to evaluate a tree.
     7609 */
     7610static void
     7611evalsubshell(union node *n, int flags)
     7612{
     7613    struct job *jp;
     7614    int backgnd = (n->type == NBACKGND);
     7615    int status;
     7616
     7617    expredir(n->nredir.redirect);
     7618    if (!backgnd && flags & EV_EXIT && !trap[0])
     7619        goto nofork;
     7620    INT_OFF;
     7621    jp = makejob(n, 1);
     7622    if (forkshell(jp, n, backgnd) == 0) {
     7623        INT_ON;
     7624        flags |= EV_EXIT;
     7625        if (backgnd)
     7626            flags &=~ EV_TESTED;
     7627 nofork:
     7628        redirect(n->nredir.redirect, 0);
     7629        evaltreenr(n->nredir.n, flags);
     7630        /* never returns */
     7631    }
     7632    status = 0;
     7633    if (! backgnd)
     7634        status = waitforjob(jp);
     7635    exitstatus = status;
     7636    INT_ON;
     7637}
     7638
     7639/*
     7640 * Compute the names of the files in a redirection list.
     7641 */
     7642static void fixredir(union node *, const char *, int);
     7643static void
     7644expredir(union node *n)
     7645{
     7646    union node *redir;
     7647
     7648    for (redir = n; redir; redir = redir->nfile.next) {
     7649        struct arglist fn;
     7650
     7651        memset(&fn, 0, sizeof(fn));
     7652        fn.lastp = &fn.list;
     7653        switch (redir->type) {
     7654        case NFROMTO:
     7655        case NFROM:
     7656        case NTO:
     7657        case NCLOBBER:
     7658        case NAPPEND:
     7659            expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
     7660            redir->nfile.expfname = fn.list->text;
     7661            break;
     7662        case NFROMFD:
     7663        case NTOFD:
     7664            if (redir->ndup.vname) {
     7665                expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
     7666                if (fn.list == NULL)
     7667                    ash_msg_and_raise_error("redir error");
     7668                fixredir(redir, fn.list->text, 1);
     7669            }
     7670            break;
     7671        }
     7672    }
     7673}
     7674
     7675/*
     7676 * Evaluate a pipeline.  All the processes in the pipeline are children
     7677 * of the process creating the pipeline.  (This differs from some versions
     7678 * of the shell, which make the last process in a pipeline the parent
     7679 * of all the rest.)
     7680 */
     7681static void
     7682evalpipe(union node *n, int flags)
     7683{
     7684    struct job *jp;
     7685    struct nodelist *lp;
     7686    int pipelen;
     7687    int prevfd;
     7688    int pip[2];
     7689
     7690    TRACE(("evalpipe(0x%lx) called\n", (long)n));
     7691    pipelen = 0;
     7692    for (lp = n->npipe.cmdlist; lp; lp = lp->next)
     7693        pipelen++;
     7694    flags |= EV_EXIT;
     7695    INT_OFF;
     7696    jp = makejob(n, pipelen);
     7697    prevfd = -1;
     7698    for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
     7699        prehash(lp->n);
     7700        pip[1] = -1;
     7701        if (lp->next) {
     7702            if (pipe(pip) < 0) {
     7703                close(prevfd);
     7704                ash_msg_and_raise_error("pipe call failed");
     7705            }
     7706        }
     7707        if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
     7708            INT_ON;
     7709            if (pip[1] >= 0) {
     7710                close(pip[0]);
     7711            }
     7712            if (prevfd > 0) {
     7713                dup2(prevfd, 0);
     7714                close(prevfd);
     7715            }
     7716            if (pip[1] > 1) {
     7717                dup2(pip[1], 1);
     7718                close(pip[1]);
     7719            }
     7720            evaltreenr(lp->n, flags);
     7721            /* never returns */
     7722        }
     7723        if (prevfd >= 0)
     7724            close(prevfd);
     7725        prevfd = pip[0];
     7726        close(pip[1]);
     7727    }
     7728    if (n->npipe.backgnd == 0) {
     7729        exitstatus = waitforjob(jp);
     7730        TRACE(("evalpipe:  job done exit status %d\n", exitstatus));
     7731    }
     7732    INT_ON;
     7733}
     7734
     7735/*
     7736 * Controls whether the shell is interactive or not.
     7737 */
     7738static void
     7739setinteractive(int on)
     7740{
     7741    static int is_interactive;
     7742
     7743    if (++on == is_interactive)
     7744        return;
     7745    is_interactive = on;
     7746    setsignal(SIGINT);
     7747    setsignal(SIGQUIT);
     7748    setsignal(SIGTERM);
     7749#if !ENABLE_FEATURE_SH_EXTRA_QUIET
     7750    if (is_interactive > 1) {
     7751        /* Looks like they want an interactive shell */
     7752        static smallint did_banner;
     7753
     7754        if (!did_banner) {
     7755            out1fmt(
     7756                "\n\n"
     7757                "%s built-in shell (ash)\n"
     7758                "Enter 'help' for a list of built-in commands."
     7759                "\n\n",
     7760                bb_banner);
     7761            did_banner = 1;
     7762        }
     7763    }
     7764#endif
     7765}
     7766
     7767#if ENABLE_FEATURE_EDITING_VI
     7768#define setvimode(on) do { \
     7769    if (on) line_input_state->flags |= VI_MODE; \
     7770    else line_input_state->flags &= ~VI_MODE; \
     7771} while (0)
     7772#else
     7773#define setvimode(on) viflag = 0   /* forcibly keep the option off */
     7774#endif
     7775
     7776static void
     7777optschanged(void)
     7778{
     7779#if DEBUG
     7780    opentrace();
     7781#endif
     7782    setinteractive(iflag);
     7783    setjobctl(mflag);
     7784    setvimode(viflag);
     7785}
     7786
     7787static struct localvar *localvars;
     7788
     7789/*
     7790 * Called after a function returns.
     7791 * Interrupts must be off.
     7792 */
     7793static void
     7794poplocalvars(void)
     7795{
     7796    struct localvar *lvp;
     7797    struct var *vp;
     7798
     7799    while ((lvp = localvars) != NULL) {
     7800        localvars = lvp->next;
     7801        vp = lvp->vp;
     7802        TRACE(("poplocalvar %s", vp ? vp->text : "-"));
     7803        if (vp == NULL) {       /* $- saved */
     7804            memcpy(optlist, lvp->text, sizeof(optlist));
     7805            free((char*)lvp->text);
     7806            optschanged();
     7807        } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
     7808            unsetvar(vp->text);
     7809        } else {
     7810            if (vp->func)
     7811                (*vp->func)(strchrnul(lvp->text, '=') + 1);
     7812            if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
     7813                free((char*)vp->text);
     7814            vp->flags = lvp->flags;
     7815            vp->text = lvp->text;
     7816        }
     7817        free(lvp);
     7818    }
     7819}
     7820
     7821static int
     7822evalfun(struct funcnode *func, int argc, char **argv, int flags)
     7823{
     7824    volatile struct shparam saveparam;
     7825    struct localvar *volatile savelocalvars;
     7826    struct jmploc *volatile savehandler;
     7827    struct jmploc jmploc;
     7828    int e;
     7829
     7830    saveparam = shellparam;
     7831    savelocalvars = localvars;
     7832    e = setjmp(jmploc.loc);
     7833    if (e) {
     7834        goto funcdone;
     7835    }
     7836    INT_OFF;
     7837    savehandler = exception_handler;
     7838    exception_handler = &jmploc;
     7839    localvars = NULL;
     7840    shellparam.malloc = 0;
     7841    func->count++;
     7842    funcnest++;
     7843    INT_ON;
     7844    shellparam.nparam = argc - 1;
     7845    shellparam.p = argv + 1;
     7846#if ENABLE_ASH_GETOPTS
     7847    shellparam.optind = 1;
     7848    shellparam.optoff = -1;
     7849#endif
     7850    evaltree(&func->n, flags & EV_TESTED);
     7851funcdone:
     7852    INT_OFF;
     7853    funcnest--;
     7854    freefunc(func);
     7855    poplocalvars();
     7856    localvars = savelocalvars;
     7857    freeparam(&shellparam);
     7858    shellparam = saveparam;
     7859    exception_handler = savehandler;
     7860    INT_ON;
     7861    evalskip &= ~SKIPFUNC;
     7862    return e;
     7863}
     7864
     7865#if ENABLE_ASH_CMDCMD
     7866static char **
     7867parse_command_args(char **argv, const char **path)
     7868{
     7869    char *cp, c;
     7870
     7871    for (;;) {
     7872        cp = *++argv;
     7873        if (!cp)
     7874            return 0;
     7875        if (*cp++ != '-')
     7876            break;
     7877        c = *cp++;
     7878        if (!c)
     7879            break;
     7880        if (c == '-' && !*cp) {
     7881            argv++;
     7882            break;
     7883        }
     7884        do {
     7885            switch (c) {
     7886            case 'p':
     7887                *path = bb_default_path;
     7888                break;
     7889            default:
     7890                /* run 'typecmd' for other options */
     7891                return 0;
     7892            }
     7893            c = *cp++;
     7894        } while (c);
     7895    }
     7896    return argv;
     7897}
     7898#endif
     7899
     7900/*
     7901 * Make a variable a local variable.  When a variable is made local, it's
     7902 * value and flags are saved in a localvar structure.  The saved values
     7903 * will be restored when the shell function returns.  We handle the name
     7904 * "-" as a special case.
     7905 */
     7906static void
     7907mklocal(char *name)
     7908{
     7909    struct localvar *lvp;
     7910    struct var **vpp;
     7911    struct var *vp;
     7912
     7913    INT_OFF;
     7914    lvp = ckmalloc(sizeof(struct localvar));
     7915    if (LONE_DASH(name)) {
     7916        char *p;
     7917        p = ckmalloc(sizeof(optlist));
     7918        lvp->text = memcpy(p, optlist, sizeof(optlist));
     7919        vp = NULL;
     7920    } else {
     7921        char *eq;
     7922
     7923        vpp = hashvar(name);
     7924        vp = *findvar(vpp, name);
     7925        eq = strchr(name, '=');
     7926        if (vp == NULL) {
     7927            if (eq)
     7928                setvareq(name, VSTRFIXED);
     7929            else
     7930                setvar(name, NULL, VSTRFIXED);
     7931            vp = *vpp;      /* the new variable */
     7932            lvp->flags = VUNSET;
     7933        } else {
     7934            lvp->text = vp->text;
     7935            lvp->flags = vp->flags;
     7936            vp->flags |= VSTRFIXED|VTEXTFIXED;
     7937            if (eq)
     7938                setvareq(name, 0);
     7939        }
     7940    }
     7941    lvp->vp = vp;
     7942    lvp->next = localvars;
     7943    localvars = lvp;
     7944    INT_ON;
     7945}
     7946
     7947/*
     7948 * The "local" command.
     7949 */
     7950static int
     7951localcmd(int argc, char **argv)
     7952{
     7953    char *name;
     7954
     7955    argv = argptr;
     7956    while ((name = *argv++) != NULL) {
     7957        mklocal(name);
     7958    }
     7959    return 0;
     7960}
     7961
     7962static int
     7963falsecmd(int argc, char **argv)
     7964{
     7965    return 1;
     7966}
     7967
     7968static int
     7969truecmd(int argc, char **argv)
     7970{
     7971    return 0;
     7972}
     7973
     7974static int
     7975execcmd(int argc, char **argv)
     7976{
     7977    if (argc > 1) {
     7978        iflag = 0;              /* exit on error */
     7979        mflag = 0;
     7980        optschanged();
     7981        shellexec(argv + 1, pathval(), 0);
     7982    }
     7983    return 0;
     7984}
     7985
     7986/*
     7987 * The return command.
     7988 */
     7989static int
     7990returncmd(int argc, char **argv)
     7991{
     7992    /*
     7993     * If called outside a function, do what ksh does;
     7994     * skip the rest of the file.
     7995     */
     7996    evalskip = funcnest ? SKIPFUNC : SKIPFILE;
     7997    return argv[1] ? number(argv[1]) : exitstatus;
     7998}
     7999
     8000/* Forward declarations for builtintab[] */
     8001static int breakcmd(int, char **);
     8002static int dotcmd(int, char **);
     8003static int evalcmd(int, char **);
     8004#if ENABLE_ASH_BUILTIN_ECHO
     8005static int echocmd(int, char **);
     8006#endif
     8007#if ENABLE_ASH_BUILTIN_TEST
     8008static int testcmd(int, char **);
     8009#endif
     8010static int exitcmd(int, char **);
     8011static int exportcmd(int, char **);
     8012#if ENABLE_ASH_GETOPTS
     8013static int getoptscmd(int, char **);
     8014#endif
     8015#if !ENABLE_FEATURE_SH_EXTRA_QUIET
     8016static int helpcmd(int argc, char **argv);
     8017#endif
     8018#if ENABLE_ASH_MATH_SUPPORT
     8019static int letcmd(int, char **);
     8020#endif
     8021static int readcmd(int, char **);
     8022static int setcmd(int, char **);
     8023static int shiftcmd(int, char **);
     8024static int timescmd(int, char **);
     8025static int trapcmd(int, char **);
     8026static int umaskcmd(int, char **);
     8027static int unsetcmd(int, char **);
     8028static int ulimitcmd(int, char **);
     8029
     8030#define BUILTIN_NOSPEC          "0"
     8031#define BUILTIN_SPECIAL         "1"
     8032#define BUILTIN_REGULAR         "2"
     8033#define BUILTIN_SPEC_REG        "3"
     8034#define BUILTIN_ASSIGN          "4"
     8035#define BUILTIN_SPEC_ASSG       "5"
     8036#define BUILTIN_REG_ASSG        "6"
     8037#define BUILTIN_SPEC_REG_ASSG   "7"
     8038
     8039/* make sure to keep these in proper order since it is searched via bsearch() */
     8040static const struct builtincmd builtintab[] = {
     8041    { BUILTIN_SPEC_REG      ".", dotcmd },
     8042    { BUILTIN_SPEC_REG      ":", truecmd },
     8043#if ENABLE_ASH_BUILTIN_TEST
     8044    { BUILTIN_REGULAR   "[", testcmd },
     8045    { BUILTIN_REGULAR   "[[", testcmd },
     8046#endif
     8047#if ENABLE_ASH_ALIAS
     8048    { BUILTIN_REG_ASSG      "alias", aliascmd },
     8049#endif
    77518050#if JOBS
    7752         retval = WSTOPSIG(status);
    7753         if (!WIFSTOPPED(status))
    7754 #endif
    7755         {
    7756             /* XXX: limits number of signals */
    7757             retval = WTERMSIG(status);
     8051    { BUILTIN_REGULAR       "bg", fg_bgcmd },
     8052#endif
     8053    { BUILTIN_SPEC_REG      "break", breakcmd },
     8054    { BUILTIN_REGULAR       "cd", cdcmd },
     8055    { BUILTIN_NOSPEC        "chdir", cdcmd },
     8056#if ENABLE_ASH_CMDCMD
     8057    { BUILTIN_REGULAR       "command", commandcmd },
     8058#endif
     8059    { BUILTIN_SPEC_REG      "continue", breakcmd },
     8060#if ENABLE_ASH_BUILTIN_ECHO
     8061    { BUILTIN_REGULAR       "echo", echocmd },
     8062#endif
     8063    { BUILTIN_SPEC_REG      "eval", evalcmd },
     8064    { BUILTIN_SPEC_REG      "exec", execcmd },
     8065    { BUILTIN_SPEC_REG      "exit", exitcmd },
     8066    { BUILTIN_SPEC_REG_ASSG "export", exportcmd },
     8067    { BUILTIN_REGULAR       "false", falsecmd },
    77588068#if JOBS
    7759             if (retval == SIGINT)
    7760                 job->sigint = 1;
    7761 #endif
    7762         }
    7763         retval += 128;
    7764     }
    7765     TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
    7766         jobno(job), job->nprocs, status, retval));
    7767     return retval;
    7768 }
    7769 
    7770 #ifdef CONFIG_ASH_MAIL
    7771 /*      mail.c       */
    7772 
    7773 /*
    7774  * Routines to check for mail.  (Perhaps make part of main.c?)
    7775  */
     8069    { BUILTIN_REGULAR       "fg", fg_bgcmd },
     8070#endif
     8071#if ENABLE_ASH_GETOPTS
     8072    { BUILTIN_REGULAR       "getopts", getoptscmd },
     8073#endif
     8074    { BUILTIN_NOSPEC        "hash", hashcmd },
     8075#if !ENABLE_FEATURE_SH_EXTRA_QUIET
     8076    { BUILTIN_NOSPEC        "help", helpcmd },
     8077#endif
     8078#if JOBS
     8079    { BUILTIN_REGULAR       "jobs", jobscmd },
     8080    { BUILTIN_REGULAR       "kill", killcmd },
     8081#endif
     8082#if ENABLE_ASH_MATH_SUPPORT
     8083    { BUILTIN_NOSPEC        "let", letcmd },
     8084#endif
     8085    { BUILTIN_ASSIGN        "local", localcmd },
     8086    { BUILTIN_NOSPEC        "pwd", pwdcmd },
     8087    { BUILTIN_REGULAR       "read", readcmd },
     8088    { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
     8089    { BUILTIN_SPEC_REG      "return", returncmd },
     8090    { BUILTIN_SPEC_REG      "set", setcmd },
     8091    { BUILTIN_SPEC_REG      "shift", shiftcmd },
     8092    { BUILTIN_SPEC_REG      "source", dotcmd },
     8093#if ENABLE_ASH_BUILTIN_TEST
     8094    { BUILTIN_REGULAR   "test", testcmd },
     8095#endif
     8096    { BUILTIN_SPEC_REG      "times", timescmd },
     8097    { BUILTIN_SPEC_REG      "trap", trapcmd },
     8098    { BUILTIN_REGULAR       "true", truecmd },
     8099    { BUILTIN_NOSPEC        "type", typecmd },
     8100    { BUILTIN_NOSPEC        "ulimit", ulimitcmd },
     8101    { BUILTIN_REGULAR       "umask", umaskcmd },
     8102#if ENABLE_ASH_ALIAS
     8103    { BUILTIN_REGULAR       "unalias", unaliascmd },
     8104#endif
     8105    { BUILTIN_SPEC_REG      "unset", unsetcmd },
     8106    { BUILTIN_REGULAR       "wait", waitcmd },
     8107};
     8108
     8109
     8110#define COMMANDCMD (builtintab + 5 + \
     8111    2 * ENABLE_ASH_BUILTIN_TEST + \
     8112    ENABLE_ASH_ALIAS + \
     8113    ENABLE_ASH_JOB_CONTROL)
     8114#define EXECCMD (builtintab + 7 + \
     8115    2 * ENABLE_ASH_BUILTIN_TEST + \
     8116    ENABLE_ASH_ALIAS + \
     8117    ENABLE_ASH_JOB_CONTROL + \
     8118    ENABLE_ASH_CMDCMD + \
     8119    ENABLE_ASH_BUILTIN_ECHO)
     8120
     8121/*
     8122 * Search the table of builtin commands.
     8123 */
     8124static struct builtincmd *
     8125find_builtin(const char *name)
     8126{
     8127    struct builtincmd *bp;
     8128
     8129    bp = bsearch(
     8130        name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
     8131        pstrcmp
     8132    );
     8133    return bp;
     8134}
     8135
     8136/*
     8137 * Execute a simple command.
     8138 */
     8139static int back_exitstatus; /* exit status of backquoted command */
     8140static int
     8141isassignment(const char *p)
     8142{
     8143    const char *q = endofname(p);
     8144    if (p == q)
     8145        return 0;
     8146    return *q == '=';
     8147}
     8148static int
     8149bltincmd(int argc, char **argv)
     8150{
     8151    /* Preserve exitstatus of a previous possible redirection
     8152     * as POSIX mandates */
     8153    return back_exitstatus;
     8154}
     8155static void
     8156evalcommand(union node *cmd, int flags)
     8157{
     8158    static const struct builtincmd bltin = {
     8159        "\0\0", bltincmd
     8160    };
     8161    struct stackmark smark;
     8162    union node *argp;
     8163    struct arglist arglist;
     8164    struct arglist varlist;
     8165    char **argv;
     8166    int argc;
     8167    const struct strlist *sp;
     8168    struct cmdentry cmdentry;
     8169    struct job *jp;
     8170    char *lastarg;
     8171    const char *path;
     8172    int spclbltin;
     8173    int cmd_is_exec;
     8174    int status;
     8175    char **nargv;
     8176    struct builtincmd *bcmd;
     8177    int pseudovarflag = 0;
     8178
     8179    /* First expand the arguments. */
     8180    TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
     8181    setstackmark(&smark);
     8182    back_exitstatus = 0;
     8183
     8184    cmdentry.cmdtype = CMDBUILTIN;
     8185    cmdentry.u.cmd = &bltin;
     8186    varlist.lastp = &varlist.list;
     8187    *varlist.lastp = NULL;
     8188    arglist.lastp = &arglist.list;
     8189    *arglist.lastp = NULL;
     8190
     8191    argc = 0;
     8192    if (cmd->ncmd.args) {
     8193        bcmd = find_builtin(cmd->ncmd.args->narg.text);
     8194        pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
     8195    }
     8196
     8197    for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
     8198        struct strlist **spp;
     8199
     8200        spp = arglist.lastp;
     8201        if (pseudovarflag && isassignment(argp->narg.text))
     8202            expandarg(argp, &arglist, EXP_VARTILDE);
     8203        else
     8204            expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
     8205
     8206        for (sp = *spp; sp; sp = sp->next)
     8207            argc++;
     8208    }
     8209
     8210    argv = nargv = stalloc(sizeof(char *) * (argc + 1));
     8211    for (sp = arglist.list; sp; sp = sp->next) {
     8212        TRACE(("evalcommand arg: %s\n", sp->text));
     8213        *nargv++ = sp->text;
     8214    }
     8215    *nargv = NULL;
     8216
     8217    lastarg = NULL;
     8218    if (iflag && funcnest == 0 && argc > 0)
     8219        lastarg = nargv[-1];
     8220
     8221    preverrout_fd = 2;
     8222    expredir(cmd->ncmd.redirect);
     8223    status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
     8224
     8225    path = vpath.text;
     8226    for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
     8227        struct strlist **spp;
     8228        char *p;
     8229
     8230        spp = varlist.lastp;
     8231        expandarg(argp, &varlist, EXP_VARTILDE);
     8232
     8233        /*
     8234         * Modify the command lookup path, if a PATH= assignment
     8235         * is present
     8236         */
     8237        p = (*spp)->text;
     8238        if (varequal(p, path))
     8239            path = p;
     8240    }
     8241
     8242    /* Print the command if xflag is set. */
     8243    if (xflag) {
     8244        int n;
     8245        const char *p = " %s";
     8246
     8247        p++;
     8248        dprintf(preverrout_fd, p, expandstr(ps4val()));
     8249
     8250        sp = varlist.list;
     8251        for (n = 0; n < 2; n++) {
     8252            while (sp) {
     8253                dprintf(preverrout_fd, p, sp->text);
     8254                sp = sp->next;
     8255                if (*p == '%') {
     8256                    p--;
     8257                }
     8258            }
     8259            sp = arglist.list;
     8260        }
     8261        full_write(preverrout_fd, "\n", 1);
     8262    }
     8263
     8264    cmd_is_exec = 0;
     8265    spclbltin = -1;
     8266
     8267    /* Now locate the command. */
     8268    if (argc) {
     8269        const char *oldpath;
     8270        int cmd_flag = DO_ERR;
     8271
     8272        path += 5;
     8273        oldpath = path;
     8274        for (;;) {
     8275            find_command(argv[0], &cmdentry, cmd_flag, path);
     8276            if (cmdentry.cmdtype == CMDUNKNOWN) {
     8277                status = 127;
     8278                flush_stderr();
     8279                goto bail;
     8280            }
     8281
     8282            /* implement bltin and command here */
     8283            if (cmdentry.cmdtype != CMDBUILTIN)
     8284                break;
     8285            if (spclbltin < 0)
     8286                spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
     8287            if (cmdentry.u.cmd == EXECCMD)
     8288                cmd_is_exec++;
     8289#if ENABLE_ASH_CMDCMD
     8290            if (cmdentry.u.cmd == COMMANDCMD) {
     8291                path = oldpath;
     8292                nargv = parse_command_args(argv, &path);
     8293                if (!nargv)
     8294                    break;
     8295                argc -= nargv - argv;
     8296                argv = nargv;
     8297                cmd_flag |= DO_NOFUNC;
     8298            } else
     8299#endif
     8300                break;
     8301        }
     8302    }
     8303
     8304    if (status) {
     8305        /* We have a redirection error. */
     8306        if (spclbltin > 0)
     8307            raise_exception(EXERROR);
     8308 bail:
     8309        exitstatus = status;
     8310        goto out;
     8311    }
     8312
     8313    /* Execute the command. */
     8314    switch (cmdentry.cmdtype) {
     8315    default:
     8316        /* Fork off a child process if necessary. */
     8317        if (!(flags & EV_EXIT) || trap[0]) {
     8318            INT_OFF;
     8319            jp = makejob(cmd, 1);
     8320            if (forkshell(jp, cmd, FORK_FG) != 0) {
     8321                exitstatus = waitforjob(jp);
     8322                INT_ON;
     8323                break;
     8324            }
     8325            FORCE_INT_ON;
     8326        }
     8327        listsetvar(varlist.list, VEXPORT|VSTACK);
     8328        shellexec(argv, path, cmdentry.u.index);
     8329        /* NOTREACHED */
     8330
     8331    case CMDBUILTIN:
     8332        cmdenviron = varlist.list;
     8333        if (cmdenviron) {
     8334            struct strlist *list = cmdenviron;
     8335            int i = VNOSET;
     8336            if (spclbltin > 0 || argc == 0) {
     8337                i = 0;
     8338                if (cmd_is_exec && argc > 1)
     8339                    i = VEXPORT;
     8340            }
     8341            listsetvar(list, i);
     8342        }
     8343        if (evalbltin(cmdentry.u.cmd, argc, argv)) {
     8344            int exit_status;
     8345            int i, j;
     8346
     8347            i = exception;
     8348            if (i == EXEXIT)
     8349                goto raise;
     8350
     8351            exit_status = 2;
     8352            j = 0;
     8353            if (i == EXINT)
     8354                j = SIGINT;
     8355            if (i == EXSIG)
     8356                j = pendingsig;
     8357            if (j)
     8358                exit_status = j + 128;
     8359            exitstatus = exit_status;
     8360
     8361            if (i == EXINT || spclbltin > 0) {
     8362 raise:
     8363                longjmp(exception_handler->loc, 1);
     8364            }
     8365            FORCE_INT_ON;
     8366        }
     8367        break;
     8368
     8369    case CMDFUNCTION:
     8370        listsetvar(varlist.list, 0);
     8371        if (evalfun(cmdentry.u.func, argc, argv, flags))
     8372            goto raise;
     8373        break;
     8374    }
     8375
     8376 out:
     8377    popredir(cmd_is_exec);
     8378    if (lastarg)
     8379        /* dsl: I think this is intended to be used to support
     8380         * '_' in 'vi' command mode during line editing...
     8381         * However I implemented that within libedit itself.
     8382         */
     8383        setvar("_", lastarg, 0);
     8384    popstackmark(&smark);
     8385}
     8386
     8387static int
     8388evalbltin(const struct builtincmd *cmd, int argc, char **argv)
     8389{
     8390    char *volatile savecmdname;
     8391    struct jmploc *volatile savehandler;
     8392    struct jmploc jmploc;
     8393    int i;
     8394
     8395    savecmdname = commandname;
     8396    i = setjmp(jmploc.loc);
     8397    if (i)
     8398        goto cmddone;
     8399    savehandler = exception_handler;
     8400    exception_handler = &jmploc;
     8401    commandname = argv[0];
     8402    argptr = argv + 1;
     8403    optptr = NULL;                  /* initialize nextopt */
     8404    exitstatus = (*cmd->builtin)(argc, argv);
     8405    flush_stdout_stderr();
     8406 cmddone:
     8407    exitstatus |= ferror(stdout);
     8408    clearerr(stdout);
     8409    commandname = savecmdname;
     8410    exsig = 0;
     8411    exception_handler = savehandler;
     8412
     8413    return i;
     8414}
     8415
     8416static int
     8417goodname(const char *p)
     8418{
     8419    return !*endofname(p);
     8420}
     8421
     8422
     8423/*
     8424 * Search for a command.  This is called before we fork so that the
     8425 * location of the command will be available in the parent as well as
     8426 * the child.  The check for "goodname" is an overly conservative
     8427 * check that the name will not be subject to expansion.
     8428 */
     8429static void
     8430prehash(union node *n)
     8431{
     8432    struct cmdentry entry;
     8433
     8434    if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
     8435        find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
     8436}
     8437
     8438
     8439/* ============ Builtin commands
     8440 *
     8441 * Builtin commands whose functions are closely tied to evaluation
     8442 * are implemented here.
     8443 */
     8444
     8445/*
     8446 * Handle break and continue commands.  Break, continue, and return are
     8447 * all handled by setting the evalskip flag.  The evaluation routines
     8448 * above all check this flag, and if it is set they start skipping
     8449 * commands rather than executing them.  The variable skipcount is
     8450 * the number of loops to break/continue, or the number of function
     8451 * levels to return.  (The latter is always 1.)  It should probably
     8452 * be an error to break out of more loops than exist, but it isn't
     8453 * in the standard shell so we don't make it one here.
     8454 */
     8455static int
     8456breakcmd(int argc, char **argv)
     8457{
     8458    int n = argc > 1 ? number(argv[1]) : 1;
     8459
     8460    if (n <= 0)
     8461        ash_msg_and_raise_error(illnum, argv[1]);
     8462    if (n > loopnest)
     8463        n = loopnest;
     8464    if (n > 0) {
     8465        evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
     8466        skipcount = n;
     8467    }
     8468    return 0;
     8469}
     8470
     8471
     8472/* ============ input.c
     8473 *
     8474 * This implements the input routines used by the parser.
     8475 */
     8476
     8477#define EOF_NLEFT -99           /* value of parsenleft when EOF pushed back */
     8478
     8479enum {
     8480    INPUT_PUSH_FILE = 1,
     8481    INPUT_NOFILE_OK = 2,
     8482};
     8483
     8484/*
     8485 * NEOF is returned by parsecmd when it encounters an end of file.  It
     8486 * must be distinct from NULL, so we use the address of a variable that
     8487 * happens to be handy.
     8488 */
     8489static int plinno = 1;                  /* input line number */
     8490/* number of characters left in input buffer */
     8491static int parsenleft;                  /* copy of parsefile->nleft */
     8492static int parselleft;                  /* copy of parsefile->lleft */
     8493/* next character in input buffer */
     8494static char *parsenextc;                /* copy of parsefile->nextc */
     8495
     8496static int checkkwd;
     8497/* values of checkkwd variable */
     8498#define CHKALIAS        0x1
     8499#define CHKKWD          0x2
     8500#define CHKNL           0x4
     8501
     8502static void
     8503popstring(void)
     8504{
     8505    struct strpush *sp = parsefile->strpush;
     8506
     8507    INT_OFF;
     8508#if ENABLE_ASH_ALIAS
     8509    if (sp->ap) {
     8510        if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
     8511            checkkwd |= CHKALIAS;
     8512        }
     8513        if (sp->string != sp->ap->val) {
     8514            free(sp->string);
     8515        }
     8516        sp->ap->flag &= ~ALIASINUSE;
     8517        if (sp->ap->flag & ALIASDEAD) {
     8518            unalias(sp->ap->name);
     8519        }
     8520    }
     8521#endif
     8522    parsenextc = sp->prevstring;
     8523    parsenleft = sp->prevnleft;
     8524/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
     8525    parsefile->strpush = sp->prev;
     8526    if (sp != &(parsefile->basestrpush))
     8527        free(sp);
     8528    INT_ON;
     8529}
     8530
     8531static int
     8532preadfd(void)
     8533{
     8534    int nr;
     8535    char *buf =  parsefile->buf;
     8536    parsenextc = buf;
     8537
     8538 retry:
     8539#if ENABLE_FEATURE_EDITING
     8540    if (!iflag || parsefile->fd)
     8541        nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
     8542    else {
     8543#if ENABLE_FEATURE_TAB_COMPLETION
     8544        line_input_state->path_lookup = pathval();
     8545#endif
     8546        nr = read_line_input(cmdedit_prompt, buf, BUFSIZ, line_input_state);
     8547        if (nr == 0) {
     8548            /* Ctrl+C pressed */
     8549            if (trap[SIGINT]) {
     8550                buf[0] = '\n';
     8551                buf[1] = '\0';
     8552                raise(SIGINT);
     8553                return 1;
     8554            }
     8555            goto retry;
     8556        }
     8557        if (nr < 0 && errno == 0) {
     8558            /* Ctrl+D presend */
     8559            nr = 0;
     8560        }
     8561    }
     8562#else
     8563    nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
     8564#endif
     8565
     8566    if (nr < 0) {
     8567        if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
     8568            int flags = fcntl(0, F_GETFL);
     8569            if (flags >= 0 && flags & O_NONBLOCK) {
     8570                flags &=~ O_NONBLOCK;
     8571                if (fcntl(0, F_SETFL, flags) >= 0) {
     8572                    out2str("sh: turning off NDELAY mode\n");
     8573                    goto retry;
     8574                }
     8575            }
     8576        }
     8577    }
     8578    return nr;
     8579}
     8580
     8581/*
     8582 * Refill the input buffer and return the next input character:
     8583 *
     8584 * 1) If a string was pushed back on the input, pop it;
     8585 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
     8586 *    from a string so we can't refill the buffer, return EOF.
     8587 * 3) If the is more stuff in this buffer, use it else call read to fill it.
     8588 * 4) Process input up to the next newline, deleting nul characters.
     8589 */
     8590static int
     8591preadbuffer(void)
     8592{
     8593    char *q;
     8594    int more;
     8595    char savec;
     8596
     8597    while (parsefile->strpush) {
     8598#if ENABLE_ASH_ALIAS
     8599        if (parsenleft == -1 && parsefile->strpush->ap &&
     8600            parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
     8601            return PEOA;
     8602        }
     8603#endif
     8604        popstring();
     8605        if (--parsenleft >= 0)
     8606            return signed_char2int(*parsenextc++);
     8607    }
     8608    if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
     8609        return PEOF;
     8610    flush_stdout_stderr();
     8611
     8612    more = parselleft;
     8613    if (more <= 0) {
     8614 again:
     8615        more = preadfd();
     8616        if (more <= 0) {
     8617            parselleft = parsenleft = EOF_NLEFT;
     8618            return PEOF;
     8619        }
     8620    }
     8621
     8622    q = parsenextc;
     8623
     8624    /* delete nul characters */
     8625    for (;;) {
     8626        int c;
     8627
     8628        more--;
     8629        c = *q;
     8630
     8631        if (!c)
     8632            memmove(q, q + 1, more);
     8633        else {
     8634            q++;
     8635            if (c == '\n') {
     8636                parsenleft = q - parsenextc - 1;
     8637                break;
     8638            }
     8639        }
     8640
     8641        if (more <= 0) {
     8642            parsenleft = q - parsenextc - 1;
     8643            if (parsenleft < 0)
     8644                goto again;
     8645            break;
     8646        }
     8647    }
     8648    parselleft = more;
     8649
     8650    savec = *q;
     8651    *q = '\0';
     8652
     8653    if (vflag) {
     8654        out2str(parsenextc);
     8655    }
     8656
     8657    *q = savec;
     8658
     8659    return signed_char2int(*parsenextc++);
     8660}
     8661
     8662#define pgetc_as_macro() (--parsenleft >= 0? signed_char2int(*parsenextc++) : preadbuffer())
     8663static int
     8664pgetc(void)
     8665{
     8666    return pgetc_as_macro();
     8667}
     8668
     8669#if ENABLE_ASH_OPTIMIZE_FOR_SIZE
     8670#define pgetc_macro() pgetc()
     8671#else
     8672#define pgetc_macro() pgetc_as_macro()
     8673#endif
     8674
     8675/*
     8676 * Same as pgetc(), but ignores PEOA.
     8677 */
     8678#if ENABLE_ASH_ALIAS
     8679static int
     8680pgetc2(void)
     8681{
     8682    int c;
     8683
     8684    do {
     8685        c = pgetc_macro();
     8686    } while (c == PEOA);
     8687    return c;
     8688}
     8689#else
     8690static int
     8691pgetc2(void)
     8692{
     8693    return pgetc_macro();
     8694}
     8695#endif
     8696
     8697/*
     8698 * Read a line from the script.
     8699 */
     8700static char *
     8701pfgets(char *line, int len)
     8702{
     8703    char *p = line;
     8704    int nleft = len;
     8705    int c;
     8706
     8707    while (--nleft > 0) {
     8708        c = pgetc2();
     8709        if (c == PEOF) {
     8710            if (p == line)
     8711                return NULL;
     8712            break;
     8713        }
     8714        *p++ = c;
     8715        if (c == '\n')
     8716            break;
     8717    }
     8718    *p = '\0';
     8719    return line;
     8720}
     8721
     8722/*
     8723 * Undo the last call to pgetc.  Only one character may be pushed back.
     8724 * PEOF may be pushed back.
     8725 */
     8726static void
     8727pungetc(void)
     8728{
     8729    parsenleft++;
     8730    parsenextc--;
     8731}
     8732
     8733/*
     8734 * Push a string back onto the input at this current parsefile level.
     8735 * We handle aliases this way.
     8736 */
     8737static void
     8738pushstring(char *s, void *ap)
     8739{
     8740    struct strpush *sp;
     8741    size_t len;
     8742
     8743    len = strlen(s);
     8744    INT_OFF;
     8745/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
     8746    if (parsefile->strpush) {
     8747        sp = ckmalloc(sizeof(struct strpush));
     8748        sp->prev = parsefile->strpush;
     8749        parsefile->strpush = sp;
     8750    } else
     8751        sp = parsefile->strpush = &(parsefile->basestrpush);
     8752    sp->prevstring = parsenextc;
     8753    sp->prevnleft = parsenleft;
     8754#if ENABLE_ASH_ALIAS
     8755    sp->ap = (struct alias *)ap;
     8756    if (ap) {
     8757        ((struct alias *)ap)->flag |= ALIASINUSE;
     8758        sp->string = s;
     8759    }
     8760#endif
     8761    parsenextc = s;
     8762    parsenleft = len;
     8763    INT_ON;
     8764}
     8765
     8766/*
     8767 * To handle the "." command, a stack of input files is used.  Pushfile
     8768 * adds a new entry to the stack and popfile restores the previous level.
     8769 */
     8770static void
     8771pushfile(void)
     8772{
     8773    struct parsefile *pf;
     8774
     8775    parsefile->nleft = parsenleft;
     8776    parsefile->lleft = parselleft;
     8777    parsefile->nextc = parsenextc;
     8778    parsefile->linno = plinno;
     8779    pf = ckmalloc(sizeof(*pf));
     8780    pf->prev = parsefile;
     8781    pf->fd = -1;
     8782    pf->strpush = NULL;
     8783    pf->basestrpush.prev = NULL;
     8784    parsefile = pf;
     8785}
     8786
     8787static void
     8788popfile(void)
     8789{
     8790    struct parsefile *pf = parsefile;
     8791
     8792    INT_OFF;
     8793    if (pf->fd >= 0)
     8794        close(pf->fd);
     8795    if (pf->buf)
     8796        free(pf->buf);
     8797    while (pf->strpush)
     8798        popstring();
     8799    parsefile = pf->prev;
     8800    free(pf);
     8801    parsenleft = parsefile->nleft;
     8802    parselleft = parsefile->lleft;
     8803    parsenextc = parsefile->nextc;
     8804    plinno = parsefile->linno;
     8805    INT_ON;
     8806}
     8807
     8808/*
     8809 * Return to top level.
     8810 */
     8811static void
     8812popallfiles(void)
     8813{
     8814    while (parsefile != &basepf)
     8815        popfile();
     8816}
     8817
     8818/*
     8819 * Close the file(s) that the shell is reading commands from.  Called
     8820 * after a fork is done.
     8821 */
     8822static void
     8823closescript(void)
     8824{
     8825    popallfiles();
     8826    if (parsefile->fd > 0) {
     8827        close(parsefile->fd);
     8828        parsefile->fd = 0;
     8829    }
     8830}
     8831
     8832/*
     8833 * Like setinputfile, but takes an open file descriptor.  Call this with
     8834 * interrupts off.
     8835 */
     8836static void
     8837setinputfd(int fd, int push)
     8838{
     8839    fcntl(fd, F_SETFD, FD_CLOEXEC);
     8840    if (push) {
     8841        pushfile();
     8842        parsefile->buf = 0;
     8843    }
     8844    parsefile->fd = fd;
     8845    if (parsefile->buf == NULL)
     8846        parsefile->buf = ckmalloc(IBUFSIZ);
     8847    parselleft = parsenleft = 0;
     8848    plinno = 1;
     8849}
     8850
     8851/*
     8852 * Set the input to take input from a file.  If push is set, push the
     8853 * old input onto the stack first.
     8854 */
     8855static int
     8856setinputfile(const char *fname, int flags)
     8857{
     8858    int fd;
     8859    int fd2;
     8860
     8861    INT_OFF;
     8862    fd = open(fname, O_RDONLY);
     8863    if (fd < 0) {
     8864        if (flags & INPUT_NOFILE_OK)
     8865            goto out;
     8866        ash_msg_and_raise_error("can't open %s", fname);
     8867    }
     8868    if (fd < 10) {
     8869        fd2 = copyfd(fd, 10);
     8870        close(fd);
     8871        if (fd2 < 0)
     8872            ash_msg_and_raise_error("out of file descriptors");
     8873        fd = fd2;
     8874    }
     8875    setinputfd(fd, flags & INPUT_PUSH_FILE);
     8876 out:
     8877    INT_ON;
     8878    return fd;
     8879}
     8880
     8881/*
     8882 * Like setinputfile, but takes input from a string.
     8883 */
     8884static void
     8885setinputstring(char *string)
     8886{
     8887    INT_OFF;
     8888    pushfile();
     8889    parsenextc = string;
     8890    parsenleft = strlen(string);
     8891    parsefile->buf = NULL;
     8892    plinno = 1;
     8893    INT_ON;
     8894}
     8895
     8896
     8897/* ============ mail.c
     8898 *
     8899 * Routines to check for mail.
     8900 */
     8901
     8902#if ENABLE_ASH_MAIL
    77768903
    77778904#define MAXMBOXES 10
     
    77828909static int mail_var_path_changed;
    77838910
    7784 
    7785 
    77868911/*
    77878912 * Print appropriate message(s) if mail has arrived.
     
    77908915 * so we just update the values.
    77918916 */
    7792 
    77938917static void
    77948918chkmail(void)
     
    78098933        if (*p == '\0')
    78108934            continue;
    7811         for (q = p ; *q ; q++);
    7812 #ifdef DEBUG
     8935        for (q = p; *q; q++);
     8936#if DEBUG
    78138937        if (q[-1] != '/')
    78148938            abort();
     
    78318955}
    78328956
    7833 
    78348957static void
    78358958changemail(const char *val)
     
    78388961}
    78398962
    7840 #endif /* CONFIG_ASH_MAIL */
    7841 
    7842 /*      main.c       */
    7843 
    7844 
    7845 #if PROFILE
    7846 static short profile_buf[16384];
    7847 extern int etext();
    7848 #endif
    7849 
    7850 static int isloginsh;
    7851 
    7852 static void read_profile(const char *);
    7853 
    7854 /*
    7855  * Main routine.  We initialize things, parse the arguments, execute
    7856  * profiles if we're a login shell, and then call cmdloop to execute
    7857  * commands.  The setjmp call sets up the location to jump to when an
    7858  * exception occurs.  When an exception occurs the variable "state"
    7859  * is used to figure out how far we had gotten.
    7860  */
    7861 
    7862 int
    7863 ash_main(int argc, char **argv)
    7864 {
    7865     char *shinit;
    7866     volatile int state;
    7867     struct jmploc jmploc;
    7868     struct stackmark smark;
    7869 
    7870 #ifdef __GLIBC__
    7871     dash_errno = __errno_location();
    7872 #endif
    7873 
    7874 #if PROFILE
    7875     monitor(4, etext, profile_buf, sizeof profile_buf, 50);
    7876 #endif
    7877     state = 0;
    7878     if (setjmp(jmploc.loc)) {
    7879         int e;
    7880         int s;
    7881 
    7882         reset();
    7883 
    7884         e = exception;
    7885         if (e == EXERROR)
    7886             exitstatus = 2;
    7887         s = state;
    7888         if (e == EXEXIT || s == 0 || iflag == 0 || shlvl)
    7889             exitshell();
    7890 
    7891         if (e == EXINT) {
    7892             outcslow('\n', stderr);
    7893         }
    7894         popstackmark(&smark);
    7895         FORCEINTON;                             /* enable interrupts */
    7896         if (s == 1)
    7897             goto state1;
    7898         else if (s == 2)
    7899             goto state2;
    7900         else if (s == 3)
    7901             goto state3;
    7902         else
    7903             goto state4;
    7904     }
    7905     handler = &jmploc;
    7906 #ifdef DEBUG
    7907     opentrace();
    7908     trputs("Shell args:  ");  trargs(argv);
    7909 #endif
    7910     rootpid = getpid();
    7911 
    7912 #ifdef CONFIG_ASH_RANDOM_SUPPORT
    7913     rseed = rootpid + ((time_t)time((time_t *)0));
    7914 #endif
    7915     init();
    7916     setstackmark(&smark);
    7917     procargs(argc, argv);
    7918 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
    7919     if ( iflag ) {
    7920         const char *hp = lookupvar("HISTFILE");
    7921 
    7922         if(hp == NULL ) {
    7923             hp = lookupvar("HOME");
    7924             if(hp != NULL) {
    7925                 char *defhp = concat_path_file(hp, ".ash_history");
    7926                 setvar("HISTFILE", defhp, 0);
    7927                 free(defhp);
    7928             }
    7929         }
    7930     }
    7931 #endif
    7932     if (argv[0] && argv[0][0] == '-')
    7933         isloginsh = 1;
    7934     if (isloginsh) {
    7935         state = 1;
    7936         read_profile("/etc/profile");
    7937 state1:
    7938         state = 2;
    7939         read_profile(".profile");
    7940     }
    7941 state2:
    7942     state = 3;
    7943     if (
    7944 #ifndef linux
    7945         getuid() == geteuid() && getgid() == getegid() &&
    7946 #endif
    7947         iflag
    7948     ) {
    7949         if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
    7950             read_profile(shinit);
    7951         }
    7952     }
    7953 state3:
    7954     state = 4;
    7955     if (minusc)
    7956         evalstring(minusc, 0);
    7957 
    7958     if (sflag || minusc == NULL) {
    7959 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
    7960         if ( iflag ) {
    7961         const char *hp = lookupvar("HISTFILE");
    7962 
    7963         if(hp != NULL )
    7964             load_history ( hp );
    7965         }
    7966 #endif
    7967 state4: /* XXX ??? - why isn't this before the "if" statement */
    7968         cmdloop(1);
    7969     }
    7970 #if PROFILE
    7971     monitor(0);
    7972 #endif
    7973 #if GPROF
    7974     {
    7975         extern void _mcleanup(void);
    7976         _mcleanup();
    7977     }
    7978 #endif
    7979     exitshell();
    7980     /* NOTREACHED */
    7981 }
    7982 
    7983 
    7984 /*
    7985  * Read and execute commands.  "Top" is nonzero for the top level command
    7986  * loop; it turns on prompting if the shell is interactive.
    7987  */
    7988 
    7989 static int
    7990 cmdloop(int top)
    7991 {
    7992     union node *n;
    7993     struct stackmark smark;
    7994     int inter;
    7995     int numeof = 0;
    7996 
    7997     TRACE(("cmdloop(%d) called\n", top));
    7998     for (;;) {
    7999         int skip;
    8000 
    8001         setstackmark(&smark);
    8002 #if JOBS
    8003         if (jobctl)
    8004             showjobs(stderr, SHOW_CHANGED);
    8005 #endif
    8006         inter = 0;
    8007         if (iflag && top) {
    8008             inter++;
    8009 #ifdef CONFIG_ASH_MAIL
    8010             chkmail();
    8011 #endif
    8012         }
    8013         n = parsecmd(inter);
    8014         /* showtree(n); DEBUG */
    8015         if (n == NEOF) {
    8016             if (!top || numeof >= 50)
    8017                 break;
    8018             if (!stoppedjobs()) {
    8019                 if (!Iflag)
    8020                     break;
    8021                 out2str("\nUse \"exit\" to leave shell.\n");
    8022             }
    8023             numeof++;
    8024         } else if (nflag == 0) {
    8025             job_warning = (job_warning == 2) ? 1 : 0;
    8026             numeof = 0;
    8027             evaltree(n, 0);
    8028         }
    8029         popstackmark(&smark);
    8030         skip = evalskip;
    8031 
    8032         if (skip) {
    8033             evalskip = 0;
    8034             return skip & SKIPEVAL;
    8035         }
    8036     }
    8037 
    8038     return 0;
    8039 }
    8040 
    8041 
    8042 /*
    8043  * Read /etc/profile or .profile.  Return on error.
    8044  */
    8045 
    8046 static void
    8047 read_profile(const char *name)
    8048 {
    8049     int skip;
    8050 
    8051     if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
    8052         return;
    8053 
    8054     skip = cmdloop(0);
    8055     popfile();
    8056 
    8057     if (skip)
    8058         exitshell();
    8059 }
    8060 
    8061 
    8062 /*
    8063  * Read a file containing shell functions.
    8064  */
    8065 
    8066 static void
    8067 readcmdfile(char *name)
    8068 {
    8069     setinputfile(name, INPUT_PUSH_FILE);
    8070     cmdloop(0);
    8071     popfile();
    8072 }
    8073 
    8074 
    8075 /*
    8076  * Take commands from a file.  To be compatible we should do a path
    8077  * search for the file, which is necessary to find sub-commands.
    8078  */
    8079 
    8080 static inline char *
    8081 find_dot_file(char *name)
    8082 {
    8083     char *fullname;
    8084     const char *path = pathval();
    8085     struct stat statb;
    8086 
    8087     /* don't try this for absolute or relative paths */
    8088     if (strchr(name, '/'))
    8089         return name;
    8090 
    8091     while ((fullname = padvance(&path, name)) != NULL) {
    8092         if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
    8093             /*
    8094              * Don't bother freeing here, since it will
    8095              * be freed by the caller.
    8096              */
    8097             return fullname;
    8098         }
    8099         stunalloc(fullname);
    8100     }
    8101 
    8102     /* not found in the PATH */
    8103     sh_error(not_found_msg, name);
    8104     /* NOTREACHED */
    8105 }
    8106 
    8107 static int dotcmd(int argc, char **argv)
    8108 {
    8109     struct strlist *sp;
    8110     volatile struct shparam saveparam;
    8111     int status = 0;
    8112 
    8113     for (sp = cmdenviron; sp; sp = sp->next)
    8114         setvareq(bb_xstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
    8115 
    8116     if (argc >= 2) {        /* That's what SVR2 does */
    8117         char *fullname;
    8118 
    8119         fullname = find_dot_file(argv[1]);
    8120 
    8121         if (argc > 2) {
    8122             saveparam = shellparam;
    8123             shellparam.malloc = 0;
    8124             shellparam.nparam = argc - 2;
    8125             shellparam.p = argv + 2;
    8126         };
    8127 
    8128         setinputfile(fullname, INPUT_PUSH_FILE);
    8129         commandname = fullname;
    8130         cmdloop(0);
    8131         popfile();
    8132 
    8133         if (argc > 2) {
    8134             freeparam(&shellparam);
    8135             shellparam = saveparam;
    8136         };
    8137         status = exitstatus;
    8138     }
    8139     return status;
    8140 }
    8141 
    8142 
    8143 static int
    8144 exitcmd(int argc, char **argv)
    8145 {
    8146     if (stoppedjobs())
    8147         return 0;
    8148     if (argc > 1)
    8149         exitstatus = number(argv[1]);
    8150     exraise(EXEXIT);
    8151     /* NOTREACHED */
    8152 }
    8153 
    8154 #ifdef CONFIG_ASH_BUILTIN_ECHO
    8155 static int
    8156 echocmd(int argc, char **argv)
    8157 {
    8158     return bb_echo(argc, argv);
    8159 }
    8160 #endif
    8161 
    8162 #ifdef CONFIG_ASH_BUILTIN_TEST
    8163 static int
    8164 testcmd(int argc, char **argv)
    8165 {
    8166     return bb_test(argc, argv);
    8167 }
    8168 #endif
    8169 
    8170 /*      memalloc.c        */
    8171 
    8172 /*
    8173  * Same for malloc, realloc, but returns an error when out of space.
    8174  */
    8175 
    8176 static pointer
    8177 ckrealloc(pointer p, size_t nbytes)
    8178 {
    8179     p = realloc(p, nbytes);
    8180     if (p == NULL)
    8181         sh_error(bb_msg_memory_exhausted);
    8182     return p;
    8183 }
    8184 
    8185 static pointer
    8186 ckmalloc(size_t nbytes)
    8187 {
    8188     return ckrealloc(NULL, nbytes);
    8189 }
    8190 
    8191 /*
    8192  * Make a copy of a string in safe storage.
    8193  */
    8194 
    8195 static char *
    8196 savestr(const char *s)
    8197 {
    8198     char *p = strdup(s);
    8199     if (!p)
    8200         sh_error(bb_msg_memory_exhausted);
    8201     return p;
    8202 }
    8203 
    8204 
    8205 /*
    8206  * Parse trees for commands are allocated in lifo order, so we use a stack
    8207  * to make this more efficient, and also to avoid all sorts of exception
    8208  * handling code to handle interrupts in the middle of a parse.
    8209  *
    8210  * The size 504 was chosen because the Ultrix malloc handles that size
    8211  * well.
    8212  */
    8213 
    8214 
    8215 static pointer
    8216 stalloc(size_t nbytes)
    8217 {
    8218     char *p;
    8219     size_t aligned;
    8220 
    8221     aligned = SHELL_ALIGN(nbytes);
    8222     if (aligned > stacknleft) {
    8223         size_t len;
    8224         size_t blocksize;
    8225         struct stack_block *sp;
    8226 
    8227         blocksize = aligned;
    8228         if (blocksize < MINSIZE)
    8229             blocksize = MINSIZE;
    8230         len = sizeof(struct stack_block) - MINSIZE + blocksize;
    8231         if (len < blocksize)
    8232             sh_error(bb_msg_memory_exhausted);
    8233         INTOFF;
    8234         sp = ckmalloc(len);
    8235         sp->prev = stackp;
    8236         stacknxt = sp->space;
    8237         stacknleft = blocksize;
    8238         sstrend = stacknxt + blocksize;
    8239         stackp = sp;
    8240         INTON;
    8241     }
    8242     p = stacknxt;
    8243     stacknxt += aligned;
    8244     stacknleft -= aligned;
    8245     return p;
    8246 }
    8247 
    8248 
    8249 void
    8250 stunalloc(pointer p)
    8251 {
    8252 #ifdef DEBUG
    8253     if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
    8254         write(2, "stunalloc\n", 10);
    8255         abort();
    8256     }
    8257 #endif
    8258     stacknleft += stacknxt - (char *)p;
    8259     stacknxt = p;
    8260 }
    8261 
    8262 
    8263 void
    8264 setstackmark(struct stackmark *mark)
    8265 {
    8266     mark->stackp = stackp;
    8267     mark->stacknxt = stacknxt;
    8268     mark->stacknleft = stacknleft;
    8269     mark->marknext = markp;
    8270     markp = mark;
    8271 }
    8272 
    8273 
    8274 void
    8275 popstackmark(struct stackmark *mark)
    8276 {
    8277     struct stack_block *sp;
    8278 
    8279     INTOFF;
    8280     markp = mark->marknext;
    8281     while (stackp != mark->stackp) {
    8282         sp = stackp;
    8283         stackp = sp->prev;
    8284         ckfree(sp);
    8285     }
    8286     stacknxt = mark->stacknxt;
    8287     stacknleft = mark->stacknleft;
    8288     sstrend = mark->stacknxt + mark->stacknleft;
    8289     INTON;
    8290 }
    8291 
    8292 
    8293 /*
    8294  * When the parser reads in a string, it wants to stick the string on the
    8295  * stack and only adjust the stack pointer when it knows how big the
    8296  * string is.  Stackblock (defined in stack.h) returns a pointer to a block
    8297  * of space on top of the stack and stackblocklen returns the length of
    8298  * this block.  Growstackblock will grow this space by at least one byte,
    8299  * possibly moving it (like realloc).  Grabstackblock actually allocates the
    8300  * part of the block that has been used.
    8301  */
    8302 
    8303 void
    8304 growstackblock(void)
    8305 {
    8306     size_t newlen;
    8307 
    8308     newlen = stacknleft * 2;
    8309     if (newlen < stacknleft)
    8310         sh_error(bb_msg_memory_exhausted);
    8311     if (newlen < 128)
    8312         newlen += 128;
    8313 
    8314     if (stacknxt == stackp->space && stackp != &stackbase) {
    8315         struct stack_block *oldstackp;
    8316         struct stackmark *xmark;
    8317         struct stack_block *sp;
    8318         struct stack_block *prevstackp;
    8319         size_t grosslen;
    8320 
    8321         INTOFF;
    8322         oldstackp = stackp;
    8323         sp = stackp;
    8324         prevstackp = sp->prev;
    8325         grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
    8326         sp = ckrealloc((pointer)sp, grosslen);
    8327         sp->prev = prevstackp;
    8328         stackp = sp;
    8329         stacknxt = sp->space;
    8330         stacknleft = newlen;
    8331         sstrend = sp->space + newlen;
    8332 
    8333         /*
    8334          * Stack marks pointing to the start of the old block
    8335          * must be relocated to point to the new block
    8336          */
    8337         xmark = markp;
    8338         while (xmark != NULL && xmark->stackp == oldstackp) {
    8339             xmark->stackp = stackp;
    8340             xmark->stacknxt = stacknxt;
    8341             xmark->stacknleft = stacknleft;
    8342             xmark = xmark->marknext;
    8343         }
    8344         INTON;
    8345     } else {
    8346         char *oldspace = stacknxt;
    8347         int oldlen = stacknleft;
    8348         char *p = stalloc(newlen);
    8349 
    8350         /* free the space we just allocated */
    8351         stacknxt = memcpy(p, oldspace, oldlen);
    8352         stacknleft += newlen;
    8353     }
    8354 }
    8355 
    8356 static inline void
    8357 grabstackblock(size_t len)
    8358 {
    8359     len = SHELL_ALIGN(len);
    8360     stacknxt += len;
    8361     stacknleft -= len;
    8362 }
    8363 
    8364 /*
    8365  * The following routines are somewhat easier to use than the above.
    8366  * The user declares a variable of type STACKSTR, which may be declared
    8367  * to be a register.  The macro STARTSTACKSTR initializes things.  Then
    8368  * the user uses the macro STPUTC to add characters to the string.  In
    8369  * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
    8370  * grown as necessary.  When the user is done, she can just leave the
    8371  * string there and refer to it using stackblock().  Or she can allocate
    8372  * the space for it using grabstackstr().  If it is necessary to allow
    8373  * someone else to use the stack temporarily and then continue to grow
    8374  * the string, the user should use grabstack to allocate the space, and
    8375  * then call ungrabstr(p) to return to the previous mode of operation.
    8376  *
    8377  * USTPUTC is like STPUTC except that it doesn't check for overflow.
    8378  * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
    8379  * is space for at least one character.
    8380  */
    8381 
    8382 void *
    8383 growstackstr(void)
    8384 {
    8385     size_t len = stackblocksize();
    8386     if (herefd >= 0 && len >= 1024) {
    8387         bb_full_write(herefd, stackblock(), len);
    8388         return stackblock();
    8389     }
    8390     growstackblock();
    8391     return stackblock() + len;
    8392 }
    8393 
    8394 /*
    8395  * Called from CHECKSTRSPACE.
    8396  */
    8397 
    8398 char *
    8399 makestrspace(size_t newlen, char *p)
    8400 {
    8401     size_t len = p - stacknxt;
    8402     size_t size = stackblocksize();
    8403 
    8404     for (;;) {
    8405         size_t nleft;
    8406 
    8407         size = stackblocksize();
    8408         nleft = size - len;
    8409         if (nleft >= newlen)
    8410             break;
    8411         growstackblock();
    8412     }
    8413     return stackblock() + len;
    8414 }
    8415 
    8416 char *
    8417 stnputs(const char *s, size_t n, char *p)
    8418 {
    8419     p = makestrspace(n, p);
    8420     p = mempcpy(p, s, n);
    8421     return p;
    8422 }
    8423 
    8424 char *
    8425 stputs(const char *s, char *p)
    8426 {
    8427     return stnputs(s, strlen(s), p);
    8428 }
    8429 
    8430 /*      mystring.c   */
    8431 
    8432 /*
    8433  * String functions.
    8434  *
    8435  *      number(s)               Convert a string of digits to an integer.
    8436  *      is_number(s)            Return true if s is a string of digits.
    8437  */
    8438 
    8439 /*
    8440  * prefix -- see if pfx is a prefix of string.
    8441  */
    8442 
    8443 char *
    8444 prefix(const char *string, const char *pfx)
    8445 {
    8446     while (*pfx) {
    8447         if (*pfx++ != *string++)
    8448             return 0;
    8449     }
    8450     return (char *) string;
    8451 }
    8452 
    8453 
    8454 /*
    8455  * Convert a string of digits to an integer, printing an error message on
    8456  * failure.
    8457  */
    8458 
    8459 int
    8460 number(const char *s)
    8461 {
    8462 
    8463     if (! is_number(s))
    8464         sh_error(illnum, s);
    8465     return atoi(s);
    8466 }
    8467 
    8468 
    8469 /*
    8470  * Check for a valid number.  This should be elsewhere.
    8471  */
    8472 
    8473 int
    8474 is_number(const char *p)
    8475 {
    8476     do {
    8477         if (! is_digit(*p))
    8478             return 0;
    8479     } while (*++p != '\0');
    8480     return 1;
    8481 }
    8482 
    8483 
    8484 /*
    8485  * Produce a possibly single quoted string suitable as input to the shell.
    8486  * The return string is allocated on the stack.
    8487  */
    8488 
    8489 char *
    8490 single_quote(const char *s) {
    8491     char *p;
    8492 
    8493     STARTSTACKSTR(p);
    8494 
    8495     do {
    8496         char *q;
    8497         size_t len;
    8498 
    8499         len = strchrnul(s, '\'') - s;
    8500 
    8501         q = p = makestrspace(len + 3, p);
    8502 
    8503         *q++ = '\'';
    8504         q = mempcpy(q, s, len);
    8505         *q++ = '\'';
    8506         s += len;
    8507 
    8508         STADJUST(q - p, p);
    8509 
    8510         len = strspn(s, "'");
    8511         if (!len)
    8512             break;
    8513 
    8514         q = p = makestrspace(len + 3, p);
    8515 
    8516         *q++ = '"';
    8517         q = mempcpy(q, s, len);
    8518         *q++ = '"';
    8519         s += len;
    8520 
    8521         STADJUST(q - p, p);
    8522     } while (*s);
    8523 
    8524     USTPUTC(0, p);
    8525 
    8526     return stackblock();
    8527 }
    8528 
    8529 /*
    8530  * Like strdup but works with the ash stack.
    8531  */
    8532 
    8533 char *
    8534 sstrdup(const char *p)
    8535 {
    8536     size_t len = strlen(p) + 1;
    8537     return memcpy(stalloc(len), p, len);
    8538 }
    8539 
    8540 
    8541 static void
    8542 calcsize(union node *n)
    8543 {
    8544       if (n == NULL)
    8545         return;
    8546       funcblocksize += nodesize[n->type];
    8547       switch (n->type) {
    8548       case NCMD:
    8549         calcsize(n->ncmd.redirect);
    8550         calcsize(n->ncmd.args);
    8551         calcsize(n->ncmd.assign);
    8552         break;
    8553       case NPIPE:
    8554         sizenodelist(n->npipe.cmdlist);
    8555         break;
    8556       case NREDIR:
    8557       case NBACKGND:
    8558       case NSUBSHELL:
    8559         calcsize(n->nredir.redirect);
    8560         calcsize(n->nredir.n);
    8561         break;
    8562       case NAND:
    8563       case NOR:
    8564       case NSEMI:
    8565       case NWHILE:
    8566       case NUNTIL:
    8567         calcsize(n->nbinary.ch2);
    8568         calcsize(n->nbinary.ch1);
    8569         break;
    8570       case NIF:
    8571         calcsize(n->nif.elsepart);
    8572         calcsize(n->nif.ifpart);
    8573         calcsize(n->nif.test);
    8574         break;
    8575       case NFOR:
    8576         funcstringsize += strlen(n->nfor.var) + 1;
    8577         calcsize(n->nfor.body);
    8578         calcsize(n->nfor.args);
    8579         break;
    8580       case NCASE:
    8581         calcsize(n->ncase.cases);
    8582         calcsize(n->ncase.expr);
    8583         break;
    8584       case NCLIST:
    8585         calcsize(n->nclist.body);
    8586         calcsize(n->nclist.pattern);
    8587         calcsize(n->nclist.next);
    8588         break;
    8589       case NDEFUN:
    8590       case NARG:
    8591         sizenodelist(n->narg.backquote);
    8592         funcstringsize += strlen(n->narg.text) + 1;
    8593         calcsize(n->narg.next);
    8594         break;
    8595       case NTO:
    8596       case NCLOBBER:
    8597       case NFROM:
    8598       case NFROMTO:
    8599       case NAPPEND:
    8600         calcsize(n->nfile.fname);
    8601         calcsize(n->nfile.next);
    8602         break;
    8603       case NTOFD:
    8604       case NFROMFD:
    8605         calcsize(n->ndup.vname);
    8606         calcsize(n->ndup.next);
    8607         break;
    8608       case NHERE:
    8609       case NXHERE:
    8610         calcsize(n->nhere.doc);
    8611         calcsize(n->nhere.next);
    8612         break;
    8613       case NNOT:
    8614         calcsize(n->nnot.com);
    8615         break;
    8616       };
    8617 }
    8618 
    8619 
    8620 static void
    8621 sizenodelist(struct nodelist *lp)
    8622 {
    8623     while (lp) {
    8624         funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
    8625         calcsize(lp->n);
    8626         lp = lp->next;
    8627     }
    8628 }
    8629 
    8630 
    8631 static union node *
    8632 copynode(union node *n)
    8633 {
    8634       union node *new;
    8635 
    8636       if (n == NULL)
    8637         return NULL;
    8638       new = funcblock;
    8639       funcblock = (char *) funcblock + nodesize[n->type];
    8640       switch (n->type) {
    8641       case NCMD:
    8642         new->ncmd.redirect = copynode(n->ncmd.redirect);
    8643         new->ncmd.args = copynode(n->ncmd.args);
    8644         new->ncmd.assign = copynode(n->ncmd.assign);
    8645         break;
    8646       case NPIPE:
    8647         new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
    8648         new->npipe.backgnd = n->npipe.backgnd;
    8649         break;
    8650       case NREDIR:
    8651       case NBACKGND:
    8652       case NSUBSHELL:
    8653         new->nredir.redirect = copynode(n->nredir.redirect);
    8654         new->nredir.n = copynode(n->nredir.n);
    8655         break;
    8656       case NAND:
    8657       case NOR:
    8658       case NSEMI:
    8659       case NWHILE:
    8660       case NUNTIL:
    8661         new->nbinary.ch2 = copynode(n->nbinary.ch2);
    8662         new->nbinary.ch1 = copynode(n->nbinary.ch1);
    8663         break;
    8664       case NIF:
    8665         new->nif.elsepart = copynode(n->nif.elsepart);
    8666         new->nif.ifpart = copynode(n->nif.ifpart);
    8667         new->nif.test = copynode(n->nif.test);
    8668         break;
    8669       case NFOR:
    8670         new->nfor.var = nodesavestr(n->nfor.var);
    8671         new->nfor.body = copynode(n->nfor.body);
    8672         new->nfor.args = copynode(n->nfor.args);
    8673         break;
    8674       case NCASE:
    8675         new->ncase.cases = copynode(n->ncase.cases);
    8676         new->ncase.expr = copynode(n->ncase.expr);
    8677         break;
    8678       case NCLIST:
    8679         new->nclist.body = copynode(n->nclist.body);
    8680         new->nclist.pattern = copynode(n->nclist.pattern);
    8681         new->nclist.next = copynode(n->nclist.next);
    8682         break;
    8683       case NDEFUN:
    8684       case NARG:
    8685         new->narg.backquote = copynodelist(n->narg.backquote);
    8686         new->narg.text = nodesavestr(n->narg.text);
    8687         new->narg.next = copynode(n->narg.next);
    8688         break;
    8689       case NTO:
    8690       case NCLOBBER:
    8691       case NFROM:
    8692       case NFROMTO:
    8693       case NAPPEND:
    8694         new->nfile.fname = copynode(n->nfile.fname);
    8695         new->nfile.fd = n->nfile.fd;
    8696         new->nfile.next = copynode(n->nfile.next);
    8697         break;
    8698       case NTOFD:
    8699       case NFROMFD:
    8700         new->ndup.vname = copynode(n->ndup.vname);
    8701         new->ndup.dupfd = n->ndup.dupfd;
    8702         new->ndup.fd = n->ndup.fd;
    8703         new->ndup.next = copynode(n->ndup.next);
    8704         break;
    8705       case NHERE:
    8706       case NXHERE:
    8707         new->nhere.doc = copynode(n->nhere.doc);
    8708         new->nhere.fd = n->nhere.fd;
    8709         new->nhere.next = copynode(n->nhere.next);
    8710         break;
    8711       case NNOT:
    8712         new->nnot.com = copynode(n->nnot.com);
    8713         break;
    8714       };
    8715       new->type = n->type;
    8716     return new;
    8717 }
    8718 
    8719 
    8720 static struct nodelist *
    8721 copynodelist(struct nodelist *lp)
    8722 {
    8723     struct nodelist *start;
    8724     struct nodelist **lpp;
    8725 
    8726     lpp = &start;
    8727     while (lp) {
    8728         *lpp = funcblock;
    8729         funcblock = (char *) funcblock +
    8730             SHELL_ALIGN(sizeof(struct nodelist));
    8731         (*lpp)->n = copynode(lp->n);
    8732         lp = lp->next;
    8733         lpp = &(*lpp)->next;
    8734     }
    8735     *lpp = NULL;
    8736     return start;
    8737 }
    8738 
    8739 
    8740 static char *
    8741 nodesavestr(char   *s)
    8742 {
    8743     char   *rtn = funcstring;
    8744 
    8745     funcstring = stpcpy(funcstring, s) + 1;
    8746     return rtn;
    8747 }
    8748 
    8749 
    8750 /*
    8751  * Free a parse tree.
    8752  */
    8753 
    8754 static void
    8755 freefunc(struct funcnode *f)
    8756 {
    8757     if (f && --f->count < 0)
    8758         ckfree(f);
    8759 }
    8760 
    8761 
    8762 static void options(int);
    8763 static void setoption(int, int);
    8764 
    8765 
    8766 /*
    8767  * Process the shell command line arguments.
    8768  */
    8769 
    8770 void
    8771 procargs(int argc, char **argv)
    8772 {
    8773     int i;
    8774     const char *xminusc;
    8775     char **xargv;
    8776 
    8777     xargv = argv;
    8778     arg0 = xargv[0];
    8779     if (argc > 0)
    8780         xargv++;
    8781     for (i = 0; i < NOPTS; i++)
    8782         optlist[i] = 2;
    8783     argptr = xargv;
    8784     options(1);
    8785     xargv = argptr;
    8786     xminusc = minusc;
    8787     if (*xargv == NULL) {
    8788         if (xminusc)
    8789             sh_error(bb_msg_requires_arg, "-c");
    8790         sflag = 1;
    8791     }
    8792     if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
    8793         iflag = 1;
    8794     if (mflag == 2)
    8795         mflag = iflag;
    8796     for (i = 0; i < NOPTS; i++)
    8797         if (optlist[i] == 2)
    8798             optlist[i] = 0;
    8799 #if DEBUG == 2
    8800     debug = 1;
    8801 #endif
    8802     /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
    8803     if (xminusc) {
    8804         minusc = *xargv++;
    8805         if (*xargv)
    8806             goto setarg0;
    8807     } else if (!sflag) {
    8808         setinputfile(*xargv, 0);
    8809 setarg0:
    8810         arg0 = *xargv++;
    8811         commandname = arg0;
    8812     }
    8813 
    8814     shellparam.p = xargv;
    8815 #ifdef CONFIG_ASH_GETOPTS
     8963#endif /* ASH_MAIL */
     8964
     8965
     8966/* ============ ??? */
     8967
     8968/*
     8969 * Set the shell parameters.
     8970 */
     8971static void
     8972setparam(char **argv)
     8973{
     8974    char **newparam;
     8975    char **ap;
     8976    int nparam;
     8977
     8978    for (nparam = 0; argv[nparam]; nparam++);
     8979    ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
     8980    while (*argv) {
     8981        *ap++ = ckstrdup(*argv++);
     8982    }
     8983    *ap = NULL;
     8984    freeparam(&shellparam);
     8985    shellparam.malloc = 1;
     8986    shellparam.nparam = nparam;
     8987    shellparam.p = newparam;
     8988#if ENABLE_ASH_GETOPTS
    88168989    shellparam.optind = 1;
    88178990    shellparam.optoff = -1;
    88188991#endif
    8819     /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
    8820     while (*xargv) {
    8821         shellparam.nparam++;
    8822         xargv++;
    8823     }
    8824     optschanged();
    8825 }
    8826 
    8827 
    8828 void
    8829 optschanged(void)
    8830 {
    8831 #ifdef DEBUG
    8832     opentrace();
    8833 #endif
    8834     setinteractive(iflag);
    8835     setjobctl(mflag);
    8836     setvimode(viflag);
    8837 }
    8838 
    8839 static inline void
     8992}
     8993
     8994/*
     8995 * Process shell options.  The global variable argptr contains a pointer
     8996 * to the argument list; we advance it past the options.
     8997 */
     8998static void
    88408999minus_o(char *name, int val)
    88419000{
    88429001    int i;
    88439002
    8844     if (name == NULL) {
    8845         out1str("Current option settings\n");
    8846         for (i = 0; i < NOPTS; i++)
    8847             out1fmt("%-16s%s\n", optnames(i),
    8848                 optlist[i] ? "on" : "off");
    8849     } else {
    8850         for (i = 0; i < NOPTS; i++)
    8851             if (equal(name, optnames(i))) {
     9003    if (name) {
     9004        for (i = 0; i < NOPTS; i++) {
     9005            if (strcmp(name, optnames(i)) == 0) {
    88529006                optlist[i] = val;
    88539007                return;
    88549008            }
    8855         sh_error("Illegal option -o %s", name);
    8856     }
    8857 }
    8858 
    8859 /*
    8860  * Process shell options.  The global variable argptr contains a pointer
    8861  * to the argument list; we advance it past the options.
    8862  */
    8863 
     9009        }
     9010        ash_msg_and_raise_error("illegal option -o %s", name);
     9011    }
     9012    out1str("Current option settings\n");
     9013    for (i = 0; i < NOPTS; i++)
     9014        out1fmt("%-16s%s\n", optnames(i),
     9015                optlist[i] ? "on" : "off");
     9016}
     9017static void
     9018setoption(int flag, int val)
     9019{
     9020    int i;
     9021
     9022    for (i = 0; i < NOPTS; i++) {
     9023        if (optletters(i) == flag) {
     9024            optlist[i] = val;
     9025            return;
     9026        }
     9027    }
     9028    ash_msg_and_raise_error("illegal option -%c", flag);
     9029    /* NOTREACHED */
     9030}
    88649031static void
    88659032options(int cmdline)
     
    88729039        minusc = NULL;
    88739040    while ((p = *argptr) != NULL) {
     9041        c = *p++;
     9042        if (c != '-' && c != '+')
     9043            break;
    88749044        argptr++;
    8875         if ((c = *p++) == '-') {
     9045        val = 0; /* val = 0 if c == '+' */
     9046        if (c == '-') {
    88769047            val = 1;
    8877             if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
     9048            if (p[0] == '\0' || LONE_DASH(p)) {
    88789049                if (!cmdline) {
    88799050                    /* "-" means turn off -x and -v */
     
    88869057                break;    /* "-" or  "--" terminates options */
    88879058            }
    8888         } else if (c == '+') {
    8889             val = 0;
    8890         } else {
    8891             argptr--;
    8892             break;
    8893         }
     9059        }
     9060        /* first char was + or - */
    88949061        while ((c = *p++) != '\0') {
     9062            /* bash 3.2 indeed handles -c CMD and +c CMD the same */
    88959063            if (c == 'c' && cmdline) {
    8896                 minusc = p;     /* command is after shell args*/
     9064                minusc = p;     /* command is after shell args */
    88979065            } else if (c == 'o') {
    88989066                minus_o(*argptr, val);
    88999067                if (*argptr)
    89009068                    argptr++;
    8901             } else if (cmdline && (c == '-')) {     // long options
     9069            } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
     9070                isloginsh = 1;
     9071            /* bash does not accept +-login, we also won't */
     9072            } else if (cmdline && val && (c == '-')) { /* long options */
    89029073                if (strcmp(p, "login") == 0)
    89039074                    isloginsh = 1;
     
    89109081}
    89119082
    8912 
    8913 static void
    8914 setoption(int flag, int val)
    8915 {
    8916     int i;
    8917 
    8918     for (i = 0; i < NOPTS; i++)
    8919         if (optletters(i) == flag) {
    8920             optlist[i] = val;
    8921             return;
    8922         }
    8923     sh_error("Illegal option -%c", flag);
    8924     /* NOTREACHED */
    8925 }
    8926 
    8927 
    8928 
    8929 /*
    8930  * Set the shell parameters.
    8931  */
    8932 
    8933 void
    8934 setparam(char **argv)
    8935 {
    8936     char **newparam;
    8937     char **ap;
    8938     int nparam;
    8939 
    8940     for (nparam = 0 ; argv[nparam] ; nparam++);
    8941     ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
    8942     while (*argv) {
    8943         *ap++ = savestr(*argv++);
    8944     }
    8945     *ap = NULL;
    8946     freeparam(&shellparam);
    8947     shellparam.malloc = 1;
    8948     shellparam.nparam = nparam;
    8949     shellparam.p = newparam;
    8950 #ifdef CONFIG_ASH_GETOPTS
    8951     shellparam.optind = 1;
    8952     shellparam.optoff = -1;
    8953 #endif
    8954 }
    8955 
    8956 
    8957 /*
    8958  * Free the list of positional parameters.
    8959  */
    8960 
    8961 void
    8962 freeparam(volatile struct shparam *param)
    8963 {
    8964     char **ap;
    8965 
    8966     if (param->malloc) {
    8967         for (ap = param->p ; *ap ; ap++)
    8968             ckfree(*ap);
    8969         ckfree(param->p);
    8970     }
    8971 }
    8972 
    8973 
    8974 
    89759083/*
    89769084 * The shift builtin command.
    89779085 */
    8978 
    8979 int
     9086static int
    89809087shiftcmd(int argc, char **argv)
    89819088{
     
    89879094        n = number(argv[1]);
    89889095    if (n > shellparam.nparam)
    8989         sh_error("can't shift that many");
    8990     INTOFF;
     9096        ash_msg_and_raise_error("can't shift that many");
     9097    INT_OFF;
    89919098    shellparam.nparam -= n;
    8992     for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
     9099    for (ap1 = shellparam.p; --n >= 0; ap1++) {
    89939100        if (shellparam.malloc)
    8994             ckfree(*ap1);
     9101            free(*ap1);
    89959102    }
    89969103    ap2 = shellparam.p;
    89979104    while ((*ap2++ = *ap1++) != NULL);
    8998 #ifdef CONFIG_ASH_GETOPTS
     9105#if ENABLE_ASH_GETOPTS
    89999106    shellparam.optind = 1;
    90009107    shellparam.optoff = -1;
    90019108#endif
    9002     INTON;
     9109    INT_ON;
    90039110    return 0;
    90049111}
    90059112
    9006 
     9113/*
     9114 * POSIX requires that 'set' (but not export or readonly) output the
     9115 * variables in lexicographic order - by the locale's collating order (sigh).
     9116 * Maybe we could keep them in an ordered balanced binary tree
     9117 * instead of hashed lists.
     9118 * For now just roll 'em through qsort for printing...
     9119 */
     9120static int
     9121showvars(const char *sep_prefix, int on, int off)
     9122{
     9123    const char *sep;
     9124    char **ep, **epend;
     9125
     9126    ep = listvars(on, off, &epend);
     9127    qsort(ep, epend - ep, sizeof(char *), vpcmp);
     9128
     9129    sep = *sep_prefix ? " " : sep_prefix;
     9130
     9131    for (; ep < epend; ep++) {
     9132        const char *p;
     9133        const char *q;
     9134
     9135        p = strchrnul(*ep, '=');
     9136        q = nullstr;
     9137        if (*p)
     9138            q = single_quote(++p);
     9139        out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
     9140    }
     9141    return 0;
     9142}
    90079143
    90089144/*
    90099145 * The set command builtin.
    90109146 */
    9011 
    9012 int
     9147static int
    90139148setcmd(int argc, char **argv)
    90149149{
    90159150    if (argc == 1)
    90169151        return showvars(nullstr, 0, VUNSET);
    9017     INTOFF;
     9152    INT_OFF;
    90189153    options(0);
    90199154    optschanged();
     
    90219156        setparam(argptr);
    90229157    }
    9023     INTON;
     9158    INT_ON;
    90249159    return 0;
    90259160}
    90269161
    9027 
    9028 #ifdef CONFIG_ASH_GETOPTS
    9029 static void
    9030 getoptsreset(const char *value)
    9031 {
    9032     shellparam.optind = number(value);
    9033     shellparam.optoff = -1;
    9034 }
    9035 #endif
    9036 
    9037 #ifdef CONFIG_LOCALE_SUPPORT
    9038 static void change_lc_all(const char *value)
    9039 {
    9040     if (value != 0 && *value != 0)
    9041         setlocale(LC_ALL, value);
    9042 }
    9043 
    9044 static void change_lc_ctype(const char *value)
    9045 {
    9046     if (value != 0 && *value != 0)
    9047         setlocale(LC_CTYPE, value);
    9048 }
    9049 
    9050 #endif
    9051 
    9052 #ifdef CONFIG_ASH_RANDOM_SUPPORT
     9162#if ENABLE_ASH_RANDOM_SUPPORT
    90539163/* Roughly copied from bash.. */
    9054 static void change_random(const char *value)
    9055 {
    9056     if(value == NULL) {
     9164static void
     9165change_random(const char *value)
     9166{
     9167    if (value == NULL) {
    90579168        /* "get", generate */
    90589169        char buf[16];
     
    90709181#endif
    90719182
    9072 
    9073 #ifdef CONFIG_ASH_GETOPTS
     9183#if ENABLE_ASH_GETOPTS
    90749184static int
    90759185getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
     
    90829192    char **optnext;
    90839193
    9084     if(*param_optind < 1)
     9194    if (*param_optind < 1)
    90859195        return 1;
    90869196    optnext = optfirst + *param_optind - 1;
     
    90949204        p = *optnext;
    90959205        if (p == NULL || *p != '-' || *++p == '\0') {
    9096 atend:
     9206 atend:
    90979207            p = NULL;
    90989208            done = 1;
     
    91009210        }
    91019211        optnext++;
    9102         if (p[0] == '-' && p[1] == '\0')        /* check for "--" */
     9212        if (LONE_DASH(p))        /* check for "--" */
    91039213            goto atend;
    91049214    }
     
    91139223            } else {
    91149224                fprintf(stderr, "Illegal option -%c\n", c);
    9115                 (void) unsetvar("OPTARG");
     9225                unsetvar("OPTARG");
    91169226            }
    91179227            c = '?';
     
    91319241            } else {
    91329242                fprintf(stderr, "No arg for -%c option\n", c);
    9133                 (void) unsetvar("OPTARG");
     9243                unsetvar("OPTARG");
    91349244                c = '?';
    91359245            }
     
    91439253    } else
    91449254        err |= setvarsafe("OPTARG", nullstr, 0);
    9145 
    9146 out:
     9255 out:
    91479256    *optoff = p ? p - *(optnext - 1) : -1;
    91489257    *param_optind = optnext - optfirst + 1;
     
    91559264        *param_optind = 1;
    91569265        *optoff = -1;
    9157         flushall();
    9158         exraise(EXERROR);
     9266        flush_stdout_stderr();
     9267        raise_exception(EXERROR);
    91599268    }
    91609269    return done;
     
    91679276 * then it's the first time getopts has been called.
    91689277 */
    9169 
    9170 int
     9278static int
    91719279getoptscmd(int argc, char **argv)
    91729280{
     
    91749282
    91759283    if (argc < 3)
    9176         sh_error("Usage: getopts optstring var [arg]");
    9177     else if (argc == 3) {
     9284        ash_msg_and_raise_error("usage: getopts optstring var [arg]");
     9285    if (argc == 3) {
    91789286        optbase = shellparam.p;
    91799287        if (shellparam.optind > shellparam.nparam + 1) {
     
    91819289            shellparam.optoff = -1;
    91829290        }
    9183     }
    9184     else {
     9291    } else {
    91859292        optbase = &argv[3];
    91869293        if (shellparam.optind > argc - 2) {
     
    91919298
    91929299    return getopts(argv[1], argv[2], optbase, &shellparam.optind,
    9193                &shellparam.optoff);
    9194 }
    9195 #endif /* CONFIG_ASH_GETOPTS */
    9196 
    9197 /*
    9198  * XXX - should get rid of.  have all builtins use getopt(3).  the
    9199  * library getopt must have the BSD extension static variable "optreset"
    9200  * otherwise it can't be used within the shell safely.
    9201  *
    9202  * Standard option processing (a la getopt) for builtin routines.  The
    9203  * only argument that is passed to nextopt is the option string; the
    9204  * other arguments are unnecessary.  It return the character, or '\0' on
    9205  * end of input.
    9206  */
    9207 
    9208 static int
    9209 nextopt(const char *optstring)
    9210 {
    9211     char *p;
    9212     const char *q;
    9213     char c;
    9214 
    9215     if ((p = optptr) == NULL || *p == '\0') {
    9216         p = *argptr;
    9217         if (p == NULL || *p != '-' || *++p == '\0')
    9218             return '\0';
    9219         argptr++;
    9220         if (p[0] == '-' && p[1] == '\0')        /* check for "--" */
    9221             return '\0';
    9222     }
    9223     c = *p++;
    9224     for (q = optstring ; *q != c ; ) {
    9225         if (*q == '\0')
    9226             sh_error("Illegal option -%c", c);
    9227         if (*++q == ':')
    9228             q++;
    9229     }
    9230     if (*++q == ':') {
    9231         if (*p == '\0' && (p = *argptr++) == NULL)
    9232             sh_error("No arg for -%c option", c);
    9233         optionarg = p;
    9234         p = NULL;
    9235     }
    9236     optptr = p;
    9237     return c;
    9238 }
    9239 
    9240 
    9241 /*      output.c     */
    9242 
    9243 void
    9244 outstr(const char *p, FILE *file)
    9245 {
    9246     INTOFF;
    9247     fputs(p, file);
    9248     INTON;
    9249 }
    9250 
    9251 void
    9252 flushall(void)
    9253 {
    9254     INTOFF;
    9255     fflush(stdout);
    9256     fflush(stderr);
    9257     INTON;
    9258 }
    9259 
    9260 void
    9261 flusherr(void)
    9262 {
    9263     INTOFF;
    9264     fflush(stderr);
    9265     INTON;
    9266 }
    9267 
    9268 static void
    9269 outcslow(int c, FILE *dest)
    9270 {
    9271     INTOFF;
    9272     putc(c, dest);
    9273     fflush(dest);
    9274     INTON;
    9275 }
    9276 
    9277 
    9278 static int
    9279 out1fmt(const char *fmt, ...)
    9280 {
    9281     va_list ap;
    9282     int r;
    9283 
    9284     INTOFF;
    9285     va_start(ap, fmt);
    9286     r = vprintf(fmt, ap);
    9287     va_end(ap);
    9288     INTON;
    9289     return r;
    9290 }
    9291 
    9292 
    9293 int
    9294 fmtstr(char *outbuf, size_t length, const char *fmt, ...)
    9295 {
    9296     va_list ap;
    9297     int ret;
    9298 
    9299     va_start(ap, fmt);
    9300     INTOFF;
    9301     ret = vsnprintf(outbuf, length, fmt, ap);
    9302     va_end(ap);
    9303     INTON;
    9304     return ret;
    9305 }
    9306 
    9307 
    9308 
    9309 /*      parser.c     */
    9310 
    9311 
    9312 /*
    9313  * Shell command parser.
    9314  */
     9300            &shellparam.optoff);
     9301}
     9302#endif /* ASH_GETOPTS */
     9303
     9304
     9305/* ============ Shell parser */
     9306
     9307static int tokpushback;                /* last token pushed back */
     9308#define NEOF ((union node *)&tokpushback)
     9309static int parsebackquote;             /* nonzero if we are inside backquotes */
     9310static int lasttoken;                  /* last token read */
     9311static char *wordtext;                 /* text of last word returned by readtoken */
     9312static struct nodelist *backquotelist;
     9313static union node *redirnode;
     9314static struct heredoc *heredoc;
     9315static int quoteflag;                  /* set if (part of) last token was quoted */
     9316
     9317static void raise_error_syntax(const char *) ATTRIBUTE_NORETURN;
     9318static void
     9319raise_error_syntax(const char *msg)
     9320{
     9321    ash_msg_and_raise_error("syntax error: %s", msg);
     9322    /* NOTREACHED */
     9323}
     9324
     9325/*
     9326 * Called when an unexpected token is read during the parse.  The argument
     9327 * is the token that is expected, or -1 if more than one type of token can
     9328 * occur at this point.
     9329 */
     9330static void raise_error_unexpected_syntax(int) ATTRIBUTE_NORETURN;
     9331static void
     9332raise_error_unexpected_syntax(int token)
     9333{
     9334    char msg[64];
     9335    int l;
     9336
     9337    l = sprintf(msg, "%s unexpected", tokname(lasttoken));
     9338    if (token >= 0)
     9339        sprintf(msg + l, " (expecting %s)", tokname(token));
     9340    raise_error_syntax(msg);
     9341    /* NOTREACHED */
     9342}
    93159343
    93169344#define EOFMARKLEN 79
    9317 
    93189345
    93199346struct heredoc {
     
    93249351};
    93259352
    9326 
    9327 
    93289353static struct heredoc *heredoclist;    /* list of here documents to read */
    93299354
    9330 
    9331 static union node *list(int);
     9355/* parsing is heavily cross-recursive, need these forward decls */
    93329356static union node *andor(void);
    93339357static union node *pipeline(void);
    9334 static union node *command(void);
    9335 static union node *simplecmd(void);
    9336 static union node *makename(void);
    9337 static void parsefname(void);
     9358static union node *parse_command(void);
    93389359static void parseheredoc(void);
    93399360static char peektoken(void);
    93409361static int readtoken(void);
    9341 static int xxreadtoken(void);
    9342 static int readtoken1(int firstc, int syntax, char *eofmark, int striptabs);
    9343 static int noexpand(char *);
    9344 static void synexpect(int) ATTRIBUTE_NORETURN;
    9345 static void synerror(const char *) ATTRIBUTE_NORETURN;
    9346 static void setprompt(int);
    9347 
    9348 
    9349 
    9350 
    9351 /*
    9352  * Read and parse a command.  Returns NEOF on end of file.  (NULL is a
    9353  * valid parse tree indicating a blank line.)
    9354  */
    9355 
    9356 union node *
    9357 parsecmd(int interact)
    9358 {
    9359     int t;
    9360 
    9361     tokpushback = 0;
    9362     doprompt = interact;
    9363     if (doprompt)
    9364         setprompt(doprompt);
    9365     needprompt = 0;
    9366     t = readtoken();
    9367     if (t == TEOF)
    9368         return NEOF;
    9369     if (t == TNL)
    9370         return NULL;
    9371     tokpushback++;
    9372     return list(1);
    9373 }
    9374 
    93759362
    93769363static union node *
     
    94029389        if (n1 == NULL) {
    94039390            n1 = n2;
    9404         }
    9405         else {
    9406             n3 = (union node *)stalloc(sizeof (struct nbinary));
     9391        } else {
     9392            n3 = stalloc(sizeof(struct nbinary));
    94079393            n3->type = NSEMI;
    94089394            n3->nbinary.ch1 = n1;
     
    94359421        default:
    94369422            if (nlflag == 1)
    9437                 synexpect(-1);
     9423                raise_error_unexpected_syntax(-1);
    94389424            tokpushback++;
    94399425            return n1;
     
    94429428}
    94439429
    9444 
    9445 
    94469430static union node *
    94479431andor(void)
     
    94529436    n1 = pipeline();
    94539437    for (;;) {
    9454         if ((t = readtoken()) == TAND) {
     9438        t = readtoken();
     9439        if (t == TAND) {
    94559440            t = NAND;
    94569441        } else if (t == TOR) {
     
    94629447        checkkwd = CHKNL | CHKKWD | CHKALIAS;
    94639448        n2 = pipeline();
    9464         n3 = (union node *)stalloc(sizeof (struct nbinary));
     9449        n3 = stalloc(sizeof(struct nbinary));
    94659450        n3->type = t;
    94669451        n3->nbinary.ch1 = n1;
     
    94699454    }
    94709455}
    9471 
    9472 
    94739456
    94749457static union node *
     
    94869469    } else
    94879470        tokpushback++;
    9488     n1 = command();
     9471    n1 = parse_command();
    94899472    if (readtoken() == TPIPE) {
    9490         pipenode = (union node *)stalloc(sizeof (struct npipe));
     9473        pipenode = stalloc(sizeof(struct npipe));
    94919474        pipenode->type = NPIPE;
    94929475        pipenode->npipe.backgnd = 0;
    9493         lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
     9476        lp = stalloc(sizeof(struct nodelist));
    94949477        pipenode->npipe.cmdlist = lp;
    94959478        lp->n = n1;
    94969479        do {
    94979480            prev = lp;
    9498             lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
     9481            lp = stalloc(sizeof(struct nodelist));
    94999482            checkkwd = CHKNL | CHKKWD | CHKALIAS;
    9500             lp->n = command();
     9483            lp->n = parse_command();
    95019484            prev->next = lp;
    95029485        } while (readtoken() == TPIPE);
     
    95069489    tokpushback++;
    95079490    if (negate) {
    9508         n2 = (union node *)stalloc(sizeof (struct nnot));
     9491        n2 = stalloc(sizeof(struct nnot));
    95099492        n2->type = NNOT;
    95109493        n2->nnot.com = n1;
    95119494        return n2;
    9512     } else
    9513         return n1;
    9514 }
    9515 
    9516 
     9495    }
     9496    return n1;
     9497}
    95179498
    95189499static union node *
    9519 command(void)
    9520 {
    9521     union node *n1, *n2;
    9522     union node *ap, **app;
    9523     union node *cp, **cpp;
    9524     union node *redir, **rpp;
    9525     union node **rpp2;
    9526     int t;
    9527 
    9528     redir = NULL;
    9529     rpp2 = &redir;
    9530 
    9531     switch (readtoken()) {
    9532     default:
    9533         synexpect(-1);
    9534         /* NOTREACHED */
    9535     case TIF:
    9536         n1 = (union node *)stalloc(sizeof (struct nif));
    9537         n1->type = NIF;
    9538         n1->nif.test = list(0);
    9539         if (readtoken() != TTHEN)
    9540             synexpect(TTHEN);
    9541         n1->nif.ifpart = list(0);
    9542         n2 = n1;
    9543         while (readtoken() == TELIF) {
    9544             n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
    9545             n2 = n2->nif.elsepart;
    9546             n2->type = NIF;
    9547             n2->nif.test = list(0);
    9548             if (readtoken() != TTHEN)
    9549                 synexpect(TTHEN);
    9550             n2->nif.ifpart = list(0);
    9551         }
    9552         if (lasttoken == TELSE)
    9553             n2->nif.elsepart = list(0);
     9500makename(void)
     9501{
     9502    union node *n;
     9503
     9504    n = stalloc(sizeof(struct narg));
     9505    n->type = NARG;
     9506    n->narg.next = NULL;
     9507    n->narg.text = wordtext;
     9508    n->narg.backquote = backquotelist;
     9509    return n;
     9510}
     9511
     9512static void
     9513fixredir(union node *n, const char *text, int err)
     9514{
     9515    TRACE(("Fix redir %s %d\n", text, err));
     9516    if (!err)
     9517        n->ndup.vname = NULL;
     9518
     9519    if (isdigit(text[0]) && text[1] == '\0')
     9520        n->ndup.dupfd = text[0] - '0';
     9521    else if (LONE_DASH(text))
     9522        n->ndup.dupfd = -1;
     9523    else {
     9524        if (err)
     9525            raise_error_syntax("Bad fd number");
     9526        n->ndup.vname = makename();
     9527    }
     9528}
     9529
     9530/*
     9531 * Returns true if the text contains nothing to expand (no dollar signs
     9532 * or backquotes).
     9533 */
     9534static int
     9535noexpand(char *text)
     9536{
     9537    char *p;
     9538    char c;
     9539
     9540    p = text;
     9541    while ((c = *p++) != '\0') {
     9542        if (c == CTLQUOTEMARK)
     9543            continue;
     9544        if (c == CTLESC)
     9545            p++;
     9546        else if (SIT(c, BASESYNTAX) == CCTL)
     9547            return 0;
     9548    }
     9549    return 1;
     9550}
     9551
     9552static void
     9553parsefname(void)
     9554{
     9555    union node *n = redirnode;
     9556
     9557    if (readtoken() != TWORD)
     9558        raise_error_unexpected_syntax(-1);
     9559    if (n->type == NHERE) {
     9560        struct heredoc *here = heredoc;
     9561        struct heredoc *p;
     9562        int i;
     9563
     9564        if (quoteflag == 0)
     9565            n->type = NXHERE;
     9566        TRACE(("Here document %d\n", n->type));
     9567        if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
     9568            raise_error_syntax("Illegal eof marker for << redirection");
     9569        rmescapes(wordtext);
     9570        here->eofmark = wordtext;
     9571        here->next = NULL;
     9572        if (heredoclist == NULL)
     9573            heredoclist = here;
    95549574        else {
    9555             n2->nif.elsepart = NULL;
    9556             tokpushback++;
    9557         }
    9558         t = TFI;
    9559         break;
    9560     case TWHILE:
    9561     case TUNTIL: {
    9562         int got;
    9563         n1 = (union node *)stalloc(sizeof (struct nbinary));
    9564         n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
    9565         n1->nbinary.ch1 = list(0);
    9566         if ((got=readtoken()) != TDO) {
    9567 TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
    9568             synexpect(TDO);
    9569         }
    9570         n1->nbinary.ch2 = list(0);
    9571         t = TDONE;
    9572         break;
    9573     }
    9574     case TFOR:
    9575         if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
    9576             synerror("Bad for loop variable");
    9577         n1 = (union node *)stalloc(sizeof (struct nfor));
    9578         n1->type = NFOR;
    9579         n1->nfor.var = wordtext;
    9580         checkkwd = CHKKWD | CHKALIAS;
    9581         if (readtoken() == TIN) {
    9582             app = &ap;
    9583             while (readtoken() == TWORD) {
    9584                 n2 = (union node *)stalloc(sizeof (struct narg));
    9585                 n2->type = NARG;
    9586                 n2->narg.text = wordtext;
    9587                 n2->narg.backquote = backquotelist;
    9588                 *app = n2;
    9589                 app = &n2->narg.next;
    9590             }
    9591             *app = NULL;
    9592             n1->nfor.args = ap;
    9593             if (lasttoken != TNL && lasttoken != TSEMI)
    9594                 synexpect(-1);
    9595         } else {
    9596             n2 = (union node *)stalloc(sizeof (struct narg));
    9597             n2->type = NARG;
    9598             n2->narg.text = (char *)dolatstr;
    9599             n2->narg.backquote = NULL;
    9600             n2->narg.next = NULL;
    9601             n1->nfor.args = n2;
    9602             /*
    9603              * Newline or semicolon here is optional (but note
    9604              * that the original Bourne shell only allowed NL).
    9605              */
    9606             if (lasttoken != TNL && lasttoken != TSEMI)
    9607                 tokpushback++;
    9608         }
    9609         checkkwd = CHKNL | CHKKWD | CHKALIAS;
    9610         if (readtoken() != TDO)
    9611             synexpect(TDO);
    9612         n1->nfor.body = list(0);
    9613         t = TDONE;
    9614         break;
    9615     case TCASE:
    9616         n1 = (union node *)stalloc(sizeof (struct ncase));
    9617         n1->type = NCASE;
    9618         if (readtoken() != TWORD)
    9619             synexpect(TWORD);
    9620         n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
    9621         n2->type = NARG;
    9622         n2->narg.text = wordtext;
    9623         n2->narg.backquote = backquotelist;
    9624         n2->narg.next = NULL;
    9625         do {
    9626             checkkwd = CHKKWD | CHKALIAS;
    9627         } while (readtoken() == TNL);
    9628         if (lasttoken != TIN)
    9629             synexpect(TIN);
    9630         cpp = &n1->ncase.cases;
    9631 next_case:
    9632         checkkwd = CHKNL | CHKKWD;
    9633         t = readtoken();
    9634         while(t != TESAC) {
    9635             if (lasttoken == TLP)
    9636                 readtoken();
    9637             *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
    9638             cp->type = NCLIST;
    9639             app = &cp->nclist.pattern;
    9640             for (;;) {
    9641                 *app = ap = (union node *)stalloc(sizeof (struct narg));
    9642                 ap->type = NARG;
    9643                 ap->narg.text = wordtext;
    9644                 ap->narg.backquote = backquotelist;
    9645                 if (readtoken() != TPIPE)
    9646                     break;
    9647                 app = &ap->narg.next;
    9648                 readtoken();
    9649             }
    9650             ap->narg.next = NULL;
    9651             if (lasttoken != TRP)
    9652                 synexpect(TRP);
    9653             cp->nclist.body = list(2);
    9654 
    9655             cpp = &cp->nclist.next;
    9656 
    9657             checkkwd = CHKNL | CHKKWD;
    9658             if ((t = readtoken()) != TESAC) {
    9659                 if (t != TENDCASE)
    9660                     synexpect(TENDCASE);
    9661                 else
    9662                     goto next_case;
    9663             }
    9664         }
    9665         *cpp = NULL;
    9666         goto redir;
    9667     case TLP:
    9668         n1 = (union node *)stalloc(sizeof (struct nredir));
    9669         n1->type = NSUBSHELL;
    9670         n1->nredir.n = list(0);
    9671         n1->nredir.redirect = NULL;
    9672         t = TRP;
    9673         break;
    9674     case TBEGIN:
    9675         n1 = list(0);
    9676         t = TEND;
    9677         break;
    9678     case TWORD:
    9679     case TREDIR:
    9680         tokpushback++;
    9681         return simplecmd();
    9682     }
    9683 
    9684     if (readtoken() != t)
    9685         synexpect(t);
    9686 
    9687 redir:
    9688     /* Now check for redirection which may follow command */
    9689     checkkwd = CHKKWD | CHKALIAS;
    9690     rpp = rpp2;
    9691     while (readtoken() == TREDIR) {
    9692         *rpp = n2 = redirnode;
    9693         rpp = &n2->nfile.next;
    9694         parsefname();
    9695     }
    9696     tokpushback++;
    9697     *rpp = NULL;
    9698     if (redir) {
    9699         if (n1->type != NSUBSHELL) {
    9700             n2 = (union node *)stalloc(sizeof (struct nredir));
    9701             n2->type = NREDIR;
    9702             n2->nredir.n = n1;
    9703             n1 = n2;
    9704         }
    9705         n1->nredir.redirect = redir;
    9706     }
    9707 
    9708     return n1;
    9709 }
    9710 
     9575            for (p = heredoclist; p->next; p = p->next);
     9576            p->next = here;
     9577        }
     9578    } else if (n->type == NTOFD || n->type == NFROMFD) {
     9579        fixredir(n, wordtext, 0);
     9580    } else {
     9581        n->nfile.fname = makename();
     9582    }
     9583}
    97119584
    97129585static union node *
    9713 simplecmd(void) {
     9586simplecmd(void)
     9587{
    97149588    union node *args, **app;
    97159589    union node *n = NULL;
     
    97309604        switch (readtoken()) {
    97319605        case TWORD:
    9732             n = (union node *)stalloc(sizeof (struct narg));
     9606            n = stalloc(sizeof(struct narg));
    97339607            n->type = NARG;
    97349608            n->narg.text = wordtext;
     
    97499623            break;
    97509624        case TLP:
    9751             if (
    9752                 args && app == &args->narg.next &&
    9753                 !vars && !redir
     9625            if (args && app == &args->narg.next
     9626             && !vars && !redir
    97549627            ) {
    97559628                struct builtincmd *bcmd;
     
    97589631                /* We have a function */
    97599632                if (readtoken() != TRP)
    9760                     synexpect(TRP);
     9633                    raise_error_unexpected_syntax(TRP);
    97619634                name = n->narg.text;
    9762                 if (
    9763                     !goodname(name) || (
    9764                         (bcmd = find_builtin(name)) &&
    9765                         IS_BUILTIN_SPECIAL(bcmd)
    9766                     )
    9767                 )
    9768                     synerror("Bad function name");
     9635                if (!goodname(name)
     9636                 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
     9637                ) {
     9638                    raise_error_syntax("Bad function name");
     9639                }
    97699640                n->type = NDEFUN;
    97709641                checkkwd = CHKNL | CHKKWD | CHKALIAS;
    9771                 n->narg.next = command();
     9642                n->narg.next = parse_command();
    97729643                return n;
    97739644            }
     
    97789649        }
    97799650    }
    9780 out:
     9651 out:
    97819652    *app = NULL;
    97829653    *vpp = NULL;
    97839654    *rpp = NULL;
    9784     n = (union node *)stalloc(sizeof (struct ncmd));
     9655    n = stalloc(sizeof(struct ncmd));
    97859656    n->type = NCMD;
    97869657    n->ncmd.args = args;
     
    97919662
    97929663static union node *
    9793 makename(void)
    9794 {
    9795     union node *n;
    9796 
    9797     n = (union node *)stalloc(sizeof (struct narg));
    9798     n->type = NARG;
    9799     n->narg.next = NULL;
    9800     n->narg.text = wordtext;
    9801     n->narg.backquote = backquotelist;
    9802     return n;
    9803 }
    9804 
    9805 void fixredir(union node *n, const char *text, int err)
    9806 {
    9807     TRACE(("Fix redir %s %d\n", text, err));
    9808     if (!err)
    9809         n->ndup.vname = NULL;
    9810 
    9811     if (is_digit(text[0]) && text[1] == '\0')
    9812         n->ndup.dupfd = digit_val(text[0]);
    9813     else if (text[0] == '-' && text[1] == '\0')
    9814         n->ndup.dupfd = -1;
    9815     else {
    9816 
    9817         if (err)
    9818             synerror("Bad fd number");
    9819         else
    9820             n->ndup.vname = makename();
    9821     }
    9822 }
    9823 
    9824 
    9825 static void
    9826 parsefname(void)
    9827 {
    9828     union node *n = redirnode;
    9829 
    9830     if (readtoken() != TWORD)
    9831         synexpect(-1);
    9832     if (n->type == NHERE) {
    9833         struct heredoc *here = heredoc;
    9834         struct heredoc *p;
    9835         int i;
    9836 
    9837         if (quoteflag == 0)
    9838             n->type = NXHERE;
    9839         TRACE(("Here document %d\n", n->type));
    9840         if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
    9841             synerror("Illegal eof marker for << redirection");
    9842         rmescapes(wordtext);
    9843         here->eofmark = wordtext;
    9844         here->next = NULL;
    9845         if (heredoclist == NULL)
    9846             heredoclist = here;
     9664parse_command(void)
     9665{
     9666    union node *n1, *n2;
     9667    union node *ap, **app;
     9668    union node *cp, **cpp;
     9669    union node *redir, **rpp;
     9670    union node **rpp2;
     9671    int t;
     9672
     9673    redir = NULL;
     9674    rpp2 = &redir;
     9675
     9676    switch (readtoken()) {
     9677    default:
     9678        raise_error_unexpected_syntax(-1);
     9679        /* NOTREACHED */
     9680    case TIF:
     9681        n1 = stalloc(sizeof(struct nif));
     9682        n1->type = NIF;
     9683        n1->nif.test = list(0);
     9684        if (readtoken() != TTHEN)
     9685            raise_error_unexpected_syntax(TTHEN);
     9686        n1->nif.ifpart = list(0);
     9687        n2 = n1;
     9688        while (readtoken() == TELIF) {
     9689            n2->nif.elsepart = stalloc(sizeof(struct nif));
     9690            n2 = n2->nif.elsepart;
     9691            n2->type = NIF;
     9692            n2->nif.test = list(0);
     9693            if (readtoken() != TTHEN)
     9694                raise_error_unexpected_syntax(TTHEN);
     9695            n2->nif.ifpart = list(0);
     9696        }
     9697        if (lasttoken == TELSE)
     9698            n2->nif.elsepart = list(0);
    98479699        else {
    9848             for (p = heredoclist ; p->next ; p = p->next);
    9849             p->next = here;
    9850         }
    9851     } else if (n->type == NTOFD || n->type == NFROMFD) {
    9852         fixredir(n, wordtext, 0);
    9853     } else {
    9854         n->nfile.fname = makename();
    9855     }
    9856 }
    9857 
    9858 
    9859 /*
    9860  * Input any here documents.
    9861  */
    9862 
    9863 static void
    9864 parseheredoc(void)
    9865 {
    9866     struct heredoc *here;
    9867     union node *n;
    9868 
    9869     here = heredoclist;
    9870     heredoclist = 0;
    9871 
    9872     while (here) {
    9873         if (needprompt) {
    9874             setprompt(2);
    9875         }
    9876         readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
    9877                 here->eofmark, here->striptabs);
    9878         n = (union node *)stalloc(sizeof (struct narg));
    9879         n->narg.type = NARG;
    9880         n->narg.next = NULL;
    9881         n->narg.text = wordtext;
    9882         n->narg.backquote = backquotelist;
    9883         here->here->nhere.doc = n;
    9884         here = here->next;
    9885     }
    9886 }
    9887 
    9888 static char peektoken(void)
    9889 {
    9890     int t;
    9891 
    9892     t = readtoken();
     9700            n2->nif.elsepart = NULL;
     9701            tokpushback++;
     9702        }
     9703        t = TFI;
     9704        break;
     9705    case TWHILE:
     9706    case TUNTIL: {
     9707        int got;
     9708        n1 = stalloc(sizeof(struct nbinary));
     9709        n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
     9710        n1->nbinary.ch1 = list(0);
     9711        got = readtoken();
     9712        if (got != TDO) {
     9713            TRACE(("expecting DO got %s %s\n", tokname(got),
     9714                    got == TWORD ? wordtext : ""));
     9715            raise_error_unexpected_syntax(TDO);
     9716        }
     9717        n1->nbinary.ch2 = list(0);
     9718        t = TDONE;
     9719        break;
     9720    }
     9721    case TFOR:
     9722        if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
     9723            raise_error_syntax("Bad for loop variable");
     9724        n1 = stalloc(sizeof(struct nfor));
     9725        n1->type = NFOR;
     9726        n1->nfor.var = wordtext;
     9727        checkkwd = CHKKWD | CHKALIAS;
     9728        if (readtoken() == TIN) {
     9729            app = &ap;
     9730            while (readtoken() == TWORD) {
     9731                n2 = stalloc(sizeof(struct narg));
     9732                n2->type = NARG;
     9733                n2->narg.text = wordtext;
     9734                n2->narg.backquote = backquotelist;
     9735                *app = n2;
     9736                app = &n2->narg.next;
     9737            }
     9738            *app = NULL;
     9739            n1->nfor.args = ap;
     9740            if (lasttoken != TNL && lasttoken != TSEMI)
     9741                raise_error_unexpected_syntax(-1);
     9742        } else {
     9743            n2 = stalloc(sizeof(struct narg));
     9744            n2->type = NARG;
     9745            n2->narg.text = (char *)dolatstr;
     9746            n2->narg.backquote = NULL;
     9747            n2->narg.next = NULL;
     9748            n1->nfor.args = n2;
     9749            /*
     9750             * Newline or semicolon here is optional (but note
     9751             * that the original Bourne shell only allowed NL).
     9752             */
     9753            if (lasttoken != TNL && lasttoken != TSEMI)
     9754                tokpushback++;
     9755        }
     9756        checkkwd = CHKNL | CHKKWD | CHKALIAS;
     9757        if (readtoken() != TDO)
     9758            raise_error_unexpected_syntax(TDO);
     9759        n1->nfor.body = list(0);
     9760        t = TDONE;
     9761        break;
     9762    case TCASE:
     9763        n1 = stalloc(sizeof(struct ncase));
     9764        n1->type = NCASE;
     9765        if (readtoken() != TWORD)
     9766            raise_error_unexpected_syntax(TWORD);
     9767        n1->ncase.expr = n2 = stalloc(sizeof(struct narg));
     9768        n2->type = NARG;
     9769        n2->narg.text = wordtext;
     9770        n2->narg.backquote = backquotelist;
     9771        n2->narg.next = NULL;
     9772        do {
     9773            checkkwd = CHKKWD | CHKALIAS;
     9774        } while (readtoken() == TNL);
     9775        if (lasttoken != TIN)
     9776            raise_error_unexpected_syntax(TIN);
     9777        cpp = &n1->ncase.cases;
     9778 next_case:
     9779        checkkwd = CHKNL | CHKKWD;
     9780        t = readtoken();
     9781        while (t != TESAC) {
     9782            if (lasttoken == TLP)
     9783                readtoken();
     9784            *cpp = cp = stalloc(sizeof(struct nclist));
     9785            cp->type = NCLIST;
     9786            app = &cp->nclist.pattern;
     9787            for (;;) {
     9788                *app = ap = stalloc(sizeof(struct narg));
     9789                ap->type = NARG;
     9790                ap->narg.text = wordtext;
     9791                ap->narg.backquote = backquotelist;
     9792                if (readtoken() != TPIPE)
     9793                    break;
     9794                app = &ap->narg.next;
     9795                readtoken();
     9796            }
     9797            ap->narg.next = NULL;
     9798            if (lasttoken != TRP)
     9799                raise_error_unexpected_syntax(TRP);
     9800            cp->nclist.body = list(2);
     9801
     9802            cpp = &cp->nclist.next;
     9803
     9804            checkkwd = CHKNL | CHKKWD;
     9805            t = readtoken();
     9806            if (t != TESAC) {
     9807                if (t != TENDCASE)
     9808                    raise_error_unexpected_syntax(TENDCASE);
     9809                goto next_case;
     9810            }
     9811        }
     9812        *cpp = NULL;
     9813        goto redir;
     9814    case TLP:
     9815        n1 = stalloc(sizeof(struct nredir));
     9816        n1->type = NSUBSHELL;
     9817        n1->nredir.n = list(0);
     9818        n1->nredir.redirect = NULL;
     9819        t = TRP;
     9820        break;
     9821    case TBEGIN:
     9822        n1 = list(0);
     9823        t = TEND;
     9824        break;
     9825    case TWORD:
     9826    case TREDIR:
     9827        tokpushback++;
     9828        return simplecmd();
     9829    }
     9830
     9831    if (readtoken() != t)
     9832        raise_error_unexpected_syntax(t);
     9833
     9834 redir:
     9835    /* Now check for redirection which may follow command */
     9836    checkkwd = CHKKWD | CHKALIAS;
     9837    rpp = rpp2;
     9838    while (readtoken() == TREDIR) {
     9839        *rpp = n2 = redirnode;
     9840        rpp = &n2->nfile.next;
     9841        parsefname();
     9842    }
    98939843    tokpushback++;
    9894     return tokname_array[t][0];
    9895 }
    9896 
    9897 static int
    9898 readtoken(void)
    9899 {
    9900     int t;
    9901 #ifdef DEBUG
    9902     int alreadyseen = tokpushback;
    9903 #endif
    9904 
    9905 #ifdef CONFIG_ASH_ALIAS
    9906 top:
    9907 #endif
    9908 
    9909     t = xxreadtoken();
    9910 
    9911     /*
    9912      * eat newlines
    9913      */
    9914     if (checkkwd & CHKNL) {
    9915         while (t == TNL) {
    9916             parseheredoc();
    9917             t = xxreadtoken();
    9918         }
    9919     }
    9920 
    9921     if (t != TWORD || quoteflag) {
    9922         goto out;
    9923     }
    9924 
    9925     /*
    9926      * check for keywords
    9927      */
    9928     if (checkkwd & CHKKWD) {
    9929         const char *const *pp;
    9930 
    9931         if ((pp = findkwd(wordtext))) {
    9932             lasttoken = t = pp - tokname_array;
    9933             TRACE(("keyword %s recognized\n", tokname(t)));
    9934             goto out;
    9935         }
    9936     }
    9937 
    9938     if (checkkwd & CHKALIAS) {
    9939 #ifdef CONFIG_ASH_ALIAS
    9940         struct alias *ap;
    9941         if ((ap = lookupalias(wordtext, 1)) != NULL) {
    9942             if (*ap->val) {
    9943                 pushstring(ap->val, ap);
    9944             }
    9945             goto top;
    9946         }
    9947 #endif
    9948     }
    9949 out:
    9950     checkkwd = 0;
    9951 #ifdef DEBUG
    9952     if (!alreadyseen)
    9953         TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
    9954     else
    9955         TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
    9956 #endif
    9957     return (t);
    9958 }
    9959 
    9960 
    9961 /*
    9962  * Read the next input token.
    9963  * If the token is a word, we set backquotelist to the list of cmds in
    9964  *      backquotes.  We set quoteflag to true if any part of the word was
    9965  *      quoted.
    9966  * If the token is TREDIR, then we set redirnode to a structure containing
    9967  *      the redirection.
    9968  * In all cases, the variable startlinno is set to the number of the line
    9969  *      on which the token starts.
    9970  *
    9971  * [Change comment:  here documents and internal procedures]
    9972  * [Readtoken shouldn't have any arguments.  Perhaps we should make the
    9973  *  word parsing code into a separate routine.  In this case, readtoken
    9974  *  doesn't need to have any internal procedures, but parseword does.
    9975  *  We could also make parseoperator in essence the main routine, and
    9976  *  have parseword (readtoken1?) handle both words and redirection.]
    9977  */
    9978 
    9979 #define NEW_xxreadtoken
    9980 #ifdef NEW_xxreadtoken
    9981 
    9982 /* singles must be first! */
    9983 static const char xxreadtoken_chars[7] = { '\n', '(', ')', '&', '|', ';', 0 };
    9984 
    9985 static const char xxreadtoken_tokens[] = {
    9986     TNL, TLP, TRP,          /* only single occurrence allowed */
    9987     TBACKGND, TPIPE, TSEMI, /* if single occurrence */
    9988     TEOF,                   /* corresponds to trailing nul */
    9989     TAND, TOR, TENDCASE,    /* if double occurrence */
    9990 };
    9991 
    9992 #define xxreadtoken_doubles \
    9993     (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
    9994 #define xxreadtoken_singles \
    9995     (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
    9996 
    9997 static int xxreadtoken(void)
    9998 {
    9999     int c;
    10000 
    10001     if (tokpushback) {
    10002         tokpushback = 0;
    10003         return lasttoken;
    10004     }
    10005     if (needprompt) {
    10006         setprompt(2);
    10007     }
    10008     startlinno = plinno;
    10009     for (;;) {                      /* until token or start of word found */
    10010         c = pgetc_macro();
    10011 
    10012         if ((c != ' ') && (c != '\t')
    10013 #ifdef CONFIG_ASH_ALIAS
    10014             && (c != PEOA)
    10015 #endif
    10016             ) {
    10017             if (c == '#') {
    10018                 while ((c = pgetc()) != '\n' && c != PEOF);
    10019                 pungetc();
    10020             } else if (c == '\\') {
    10021                 if (pgetc() != '\n') {
    10022                     pungetc();
    10023                     goto READTOKEN1;
    10024                 }
    10025                 startlinno = ++plinno;
    10026                 if (doprompt)
    10027                     setprompt(2);
    10028             } else {
    10029                 const char *p
    10030                     = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
    10031 
    10032                 if (c != PEOF) {
    10033                     if (c == '\n') {
    10034                         plinno++;
    10035                         needprompt = doprompt;
    10036                     }
    10037 
    10038                     p = strchr(xxreadtoken_chars, c);
    10039                     if (p == NULL) {
    10040                       READTOKEN1:
    10041                         return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
    10042                     }
    10043 
    10044                     if (p - xxreadtoken_chars >= xxreadtoken_singles) {
    10045                         if (pgetc() == *p) {    /* double occurrence? */
    10046                             p += xxreadtoken_doubles + 1;
    10047                         } else {
    10048                             pungetc();
    10049                         }
    10050                     }
    10051                 }
    10052 
    10053                 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
    10054             }
    10055         }
    10056     }
    10057 }
    10058 
    10059 
    10060 #else
    10061 #define RETURN(token)   return lasttoken = token
    10062 
    10063 static int
    10064 xxreadtoken(void)
    10065 {
    10066     int c;
    10067 
    10068     if (tokpushback) {
    10069         tokpushback = 0;
    10070         return lasttoken;
    10071     }
    10072     if (needprompt) {
    10073         setprompt(2);
    10074     }
    10075     startlinno = plinno;
    10076     for (;;) {      /* until token or start of word found */
    10077         c = pgetc_macro();
    10078         switch (c) {
    10079         case ' ': case '\t':
    10080 #ifdef CONFIG_ASH_ALIAS
    10081         case PEOA:
    10082 #endif
    10083             continue;
    10084         case '#':
    10085             while ((c = pgetc()) != '\n' && c != PEOF);
    10086             pungetc();
    10087             continue;
    10088         case '\\':
    10089             if (pgetc() == '\n') {
    10090                 startlinno = ++plinno;
    10091                 if (doprompt)
    10092                     setprompt(2);
    10093                 continue;
    10094             }
    10095             pungetc();
    10096             goto breakloop;
    10097         case '\n':
    10098             plinno++;
    10099             needprompt = doprompt;
    10100             RETURN(TNL);
    10101         case PEOF:
    10102             RETURN(TEOF);
    10103         case '&':
    10104             if (pgetc() == '&')
    10105                 RETURN(TAND);
    10106             pungetc();
    10107             RETURN(TBACKGND);
    10108         case '|':
    10109             if (pgetc() == '|')
    10110                 RETURN(TOR);
    10111             pungetc();
    10112             RETURN(TPIPE);
    10113         case ';':
    10114             if (pgetc() == ';')
    10115                 RETURN(TENDCASE);
    10116             pungetc();
    10117             RETURN(TSEMI);
    10118         case '(':
    10119             RETURN(TLP);
    10120         case ')':
    10121             RETURN(TRP);
    10122         default:
    10123             goto breakloop;
    10124         }
    10125     }
    10126 breakloop:
    10127     return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
    10128 #undef RETURN
    10129 }
    10130 #endif /* NEW_xxreadtoken */
    10131 
     9844    *rpp = NULL;
     9845    if (redir) {
     9846        if (n1->type != NSUBSHELL) {
     9847            n2 = stalloc(sizeof(struct nredir));
     9848            n2->type = NREDIR;
     9849            n2->nredir.n = n1;
     9850            n1 = n2;
     9851        }
     9852        n1->nredir.redirect = redir;
     9853    }
     9854    return n1;
     9855}
    101329856
    101339857/*
     
    101429866 * will run code that appears at the end of readtoken1.
    101439867 */
     9868
     9869static int parsebackquote;             /* nonzero if we are inside backquotes */
    101449870
    101459871#define CHECKEND()      {goto checkend; checkend_return:;}
     
    101969922        for (;;) {      /* until end of line or end of word */
    101979923            CHECKSTRSPACE(4, out);  /* permit 4 calls to USTPUTC */
    10198             switch(SIT(c, syntax)) {
     9924            switch (SIT(c, syntax)) {
    101999925            case CNL:       /* '\n' */
    102009926                if (syntax == BASESYNTAX)
     
    102419967            case CSQUOTE:
    102429968                syntax = SQSYNTAX;
    10243 quotemark:
     9969 quotemark:
    102449970                if (eofmark == NULL) {
    102459971                    USTPUTC(CTLQUOTEMARK, out);
     
    102519977                goto quotemark;
    102529978            case CENDQUOTE:
    10253                 if (eofmark != NULL && arinest == 0 &&
    10254                     varnest == 0) {
     9979                if (eofmark != NULL && arinest == 0
     9980                 && varnest == 0
     9981                ) {
    102559982                    USTPUTC(c, out);
    102569983                } else {
     
    1027710004                }
    1027810005                break;
    10279 #ifdef CONFIG_ASH_MATH_SUPPORT
     10006#if ENABLE_ASH_MATH_SUPPORT
    1028010007            case CLP:       /* '(' in arithmetic */
    1028110008                parenlevel++;
     
    1031810045                if (varnest == 0)
    1031910046                    goto endword;   /* exit outer loop */
    10320 #ifdef CONFIG_ASH_ALIAS
     10047#if ENABLE_ASH_ALIAS
    1032110048                if (c != PEOA)
    1032210049#endif
     
    1032710054        }
    1032810055    }
    10329 endword:
    10330 #ifdef CONFIG_ASH_MATH_SUPPORT
     10056 endword:
     10057#if ENABLE_ASH_MATH_SUPPORT
    1033110058    if (syntax == ARISYNTAX)
    10332         synerror("Missing '))'");
    10333 #endif
    10334     if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
    10335         synerror("Unterminated quoted string");
     10059        raise_error_syntax("Missing '))'");
     10060#endif
     10061    if (syntax != BASESYNTAX && !parsebackquote && eofmark == NULL)
     10062        raise_error_syntax("Unterminated quoted string");
    1033610063    if (varnest != 0) {
    1033710064        startlinno = plinno;
    1033810065        /* { */
    10339         synerror("Missing '}'");
     10066        raise_error_syntax("Missing '}'");
    1034010067    }
    1034110068    USTPUTC('\0', out);
     
    1034610073         && quotef == 0
    1034710074         && len <= 2
    10348          && (*out == '\0' || is_digit(*out))) {
     10075         && (*out == '\0' || isdigit(*out))) {
    1034910076            PARSEREDIR();
    1035010077            return lasttoken = TREDIR;
     
    1035710084    grabstackblock(len);
    1035810085    wordtext = out;
    10359     return lasttoken = TWORD;
     10086    lasttoken = TWORD;
     10087    return lasttoken;
    1036010088/* end of readtoken routine */
    10361 
    10362 
    1036310089
    1036410090/*
     
    1036710093 * we are at the end of the here document, this routine sets the c to PEOF.
    1036810094 */
    10369 
    1037010095checkend: {
    1037110096    if (eofmark) {
    10372 #ifdef CONFIG_ASH_ALIAS
     10097#if ENABLE_ASH_ALIAS
    1037310098        if (c == PEOA) {
    1037410099            c = pgetc2();
     
    1038110106        }
    1038210107        if (c == *eofmark) {
    10383             if (pfgets(line, sizeof line) != NULL) {
     10108            if (pfgets(line, sizeof(line)) != NULL) {
    1038410109                char *p, *q;
    1038510110
    1038610111                p = line;
    10387                 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
     10112                for (q = eofmark + 1; *q && *p == *q; p++, q++);
    1038810113                if (*p == '\n' && *q == '\0') {
    1038910114                    c = PEOF;
     
    1039910124}
    1040010125
    10401 
    1040210126/*
    1040310127 * Parse a redirection operator.  The variable "out" points to a string
     
    1040510129 * first character of the redirection operator.
    1040610130 */
    10407 
    1040810131parseredir: {
    1040910132    char fd = *out;
    1041010133    union node *np;
    1041110134
    10412     np = (union node *)stalloc(sizeof (struct nfile));
     10135    np = stalloc(sizeof(struct nfile));
    1041310136    if (c == '>') {
    1041410137        np->nfile.fd = 1;
     
    1042610149    } else {        /* c == '<' */
    1042710150        np->nfile.fd = 0;
    10428         switch (c = pgetc()) {
     10151        c = pgetc();
     10152        switch (c) {
    1042910153        case '<':
    10430             if (sizeof (struct nfile) != sizeof (struct nhere)) {
    10431                 np = (union node *)stalloc(sizeof (struct nhere));
     10154            if (sizeof(struct nfile) != sizeof(struct nhere)) {
     10155                np = stalloc(sizeof(struct nhere));
    1043210156                np->nfile.fd = 0;
    1043310157            }
    1043410158            np->type = NHERE;
    10435             heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
     10159            heredoc = stalloc(sizeof(struct heredoc));
    1043610160            heredoc->here = np;
    10437             if ((c = pgetc()) == '-') {
     10161            c = pgetc();
     10162            if (c == '-') {
    1043810163                heredoc->striptabs = 1;
    1043910164            } else {
     
    1045810183    }
    1045910184    if (fd != '\0')
    10460         np->nfile.fd = digit_val(fd);
     10185        np->nfile.fd = fd - '0';
    1046110186    redirnode = np;
    1046210187    goto parseredir_return;
    1046310188}
    1046410189
    10465 
    1046610190/*
    1046710191 * Parse a substitution.  At this point, we have read the dollar sign
     
    1046910193 */
    1047010194
     10195/* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
     10196 * (assuming ascii char codes, as the original implementation did) */
     10197#define is_special(c) \
     10198    ((((unsigned int)c) - 33 < 32) \
     10199            && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1))
    1047110200parsesub: {
    1047210201    int subtype;
     
    1047410203    int flags;
    1047510204    char *p;
    10476     static const char types[] = "}-+?=";
     10205    static const char types[] ALIGN1 = "}-+?=";
    1047710206
    1047810207    c = pgetc();
     
    1048510214    } else if (c == '(') {  /* $(command) or $((arith)) */
    1048610215        if (pgetc() == '(') {
    10487 #ifdef CONFIG_ASH_MATH_SUPPORT
     10216#if ENABLE_ASH_MATH_SUPPORT
    1048810217            PARSEARITH();
    1048910218#else
    10490             synerror("We unsupport $((arith))");
     10219            raise_error_syntax("We unsupport $((arith))");
    1049110220#endif
    1049210221        } else {
     
    1050210231            c = pgetc();
    1050310232            if (c == '#') {
    10504                 if ((c = pgetc()) == '}')
     10233                c = pgetc();
     10234                if (c == '}')
    1050510235                    c = '#';
    1050610236                else
    1050710237                    subtype = VSLENGTH;
    10508             }
    10509             else
     10238            } else
    1051010239                subtype = 0;
    1051110240        }
     
    1051510244                c = pgetc();
    1051610245            } while (c > PEOA_OR_PEOF && is_in_name(c));
    10517         } else if (is_digit(c)) {
     10246        } else if (isdigit(c)) {
    1051810247            do {
    1051910248                STPUTC(c, out);
    1052010249                c = pgetc();
    10521             } while (is_digit(c));
    10522         }
    10523         else if (is_special(c)) {
     10250            } while (isdigit(c));
     10251        } else if (is_special(c)) {
    1052410252            USTPUTC(c, out);
    1052510253            c = pgetc();
    10526         }
    10527         else
    10528 badsub:                 synerror("Bad substitution");
     10254        } else
     10255 badsub:        raise_error_syntax("Bad substitution");
    1052910256
    1053010257        STPUTC('=', out);
     
    1054710274                    int cc = c;
    1054810275                    subtype = c == '#' ? VSTRIMLEFT :
    10549                                  VSTRIMRIGHT;
     10276                                         VSTRIMRIGHT;
    1055010277                    c = pgetc();
    1055110278                    if (c == cc)
     
    1057210299}
    1057310300
    10574 
    1057510301/*
    1057610302 * Called to parse command substitutions.  Newstyle is set if the command
     
    1057910305 * characters on the top of the stack which must be preserved.
    1058010306 */
    10581 
    1058210307parsebackq: {
    1058310308    struct nodelist **nlpp;
     
    1059610321    if (setjmp(jmploc.loc)) {
    1059710322        if (str)
    10598             ckfree(str);
     10323            free(str);
    1059910324        parsebackquote = 0;
    10600         handler = savehandler;
    10601         longjmp(handler->loc, 1);
    10602     }
    10603     INTOFF;
     10325        exception_handler = savehandler;
     10326        longjmp(exception_handler->loc, 1);
     10327    }
     10328    INT_OFF;
    1060410329    str = NULL;
    1060510330    savelen = out - (char *)stackblock();
     
    1060810333        memcpy(str, stackblock(), savelen);
    1060910334    }
    10610     savehandler = handler;
    10611     handler = &jmploc;
    10612     INTON;
     10335    savehandler = exception_handler;
     10336    exception_handler = &jmploc;
     10337    INT_ON;
    1061310338    if (oldstyle) {
    1061410339        /* We must read until the closing backquote, giving special
     
    1062610351                setprompt(2);
    1062710352            }
    10628             switch (pc = pgetc()) {
     10353            pc = pgetc();
     10354            switch (pc) {
    1062910355            case '`':
    1063010356                goto done;
    1063110357
    1063210358            case '\\':
    10633                 if ((pc = pgetc()) == '\n') {
     10359                pc = pgetc();
     10360                if (pc == '\n') {
    1063410361                    plinno++;
    1063510362                    if (doprompt)
     
    1064410371                }
    1064510372                if (pc != '\\' && pc != '`' && pc != '$'
    10646                     && (!dblquote || pc != '"'))
     10373                 && (!dblquote || pc != '"'))
    1064710374                    STPUTC('\\', pout);
    1064810375                if (pc > PEOA_OR_PEOF) {
     
    1065210379
    1065310380            case PEOF:
    10654 #ifdef CONFIG_ASH_ALIAS
     10381#if ENABLE_ASH_ALIAS
    1065510382            case PEOA:
    1065610383#endif
    1065710384                startlinno = plinno;
    10658                 synerror("EOF in backquote substitution");
     10385                raise_error_syntax("EOF in backquote substitution");
    1065910386
    1066010387            case '\n':
     
    1066810395            STPUTC(pc, pout);
    1066910396        }
    10670 done:
     10397 done:
    1067110398        STPUTC('\0', pout);
    1067210399        psavelen = pout - (char *)stackblock();
     
    1067910406    while (*nlpp)
    1068010407        nlpp = &(*nlpp)->next;
    10681     *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
     10408    *nlpp = stalloc(sizeof(**nlpp));
    1068210409    (*nlpp)->next = NULL;
    1068310410    parsebackquote = oldstyle;
     
    1069210419    if (oldstyle)
    1069310420        doprompt = saveprompt;
    10694     else {
    10695         if (readtoken() != TRP)
    10696             synexpect(TRP);
    10697     }
     10421    else if (readtoken() != TRP)
     10422        raise_error_unexpected_syntax(TRP);
    1069810423
    1069910424    (*nlpp)->n = n;
     
    1071210437        memcpy(out, str, savelen);
    1071310438        STADJUST(savelen, out);
    10714         INTOFF;
    10715         ckfree(str);
     10439        INT_OFF;
     10440        free(str);
    1071610441        str = NULL;
    10717         INTON;
     10442        INT_ON;
    1071810443    }
    1071910444    parsebackquote = savepbq;
    10720     handler = savehandler;
     10445    exception_handler = savehandler;
    1072110446    if (arinest || dblquote)
    1072210447        USTPUTC(CTLBACKQ | CTLQUOTE, out);
     
    1072510450    if (oldstyle)
    1072610451        goto parsebackq_oldreturn;
    10727     else
    10728         goto parsebackq_newreturn;
    10729 }
    10730 
    10731 #ifdef CONFIG_ASH_MATH_SUPPORT
     10452    goto parsebackq_newreturn;
     10453}
     10454
     10455#if ENABLE_ASH_MATH_SUPPORT
    1073210456/*
    1073310457 * Parse an arithmetic expansion (indicate start of one and set state)
    1073410458 */
    1073510459parsearith: {
    10736 
    1073710460    if (++arinest == 1) {
    1073810461        prevsyntax = syntax;
     
    1074010463        USTPUTC(CTLARI, out);
    1074110464        if (dblquote)
    10742             USTPUTC('"',out);
     10465            USTPUTC('"', out);
    1074310466        else
    10744             USTPUTC(' ',out);
     10467            USTPUTC(' ', out);
    1074510468    } else {
    1074610469        /*
     
    1075610479} /* end of readtoken */
    1075710480
    10758 
    10759 
    10760 /*
    10761  * Returns true if the text contains nothing to expand (no dollar signs
    10762  * or backquotes).
    10763  */
     10481/*
     10482 * Read the next input token.
     10483 * If the token is a word, we set backquotelist to the list of cmds in
     10484 *      backquotes.  We set quoteflag to true if any part of the word was
     10485 *      quoted.
     10486 * If the token is TREDIR, then we set redirnode to a structure containing
     10487 *      the redirection.
     10488 * In all cases, the variable startlinno is set to the number of the line
     10489 *      on which the token starts.
     10490 *
     10491 * [Change comment:  here documents and internal procedures]
     10492 * [Readtoken shouldn't have any arguments.  Perhaps we should make the
     10493 *  word parsing code into a separate routine.  In this case, readtoken
     10494 *  doesn't need to have any internal procedures, but parseword does.
     10495 *  We could also make parseoperator in essence the main routine, and
     10496 *  have parseword (readtoken1?) handle both words and redirection.]
     10497 */
     10498#define NEW_xxreadtoken
     10499#ifdef NEW_xxreadtoken
     10500/* singles must be first! */
     10501static const char xxreadtoken_chars[7] ALIGN1 = {
     10502    '\n', '(', ')', '&', '|', ';', 0
     10503};
     10504
     10505static const char xxreadtoken_tokens[] ALIGN1 = {
     10506    TNL, TLP, TRP,          /* only single occurrence allowed */
     10507    TBACKGND, TPIPE, TSEMI, /* if single occurrence */
     10508    TEOF,                   /* corresponds to trailing nul */
     10509    TAND, TOR, TENDCASE     /* if double occurrence */
     10510};
     10511
     10512#define xxreadtoken_doubles \
     10513    (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
     10514#define xxreadtoken_singles \
     10515    (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
    1076410516
    1076510517static int
    10766 noexpand(char *text)
    10767 {
    10768     char *p;
    10769     char c;
    10770 
    10771     p = text;
    10772     while ((c = *p++) != '\0') {
    10773         if (c == CTLQUOTEMARK)
     10518xxreadtoken(void)
     10519{
     10520    int c;
     10521
     10522    if (tokpushback) {
     10523        tokpushback = 0;
     10524        return lasttoken;
     10525    }
     10526    if (needprompt) {
     10527        setprompt(2);
     10528    }
     10529    startlinno = plinno;
     10530    for (;;) {                      /* until token or start of word found */
     10531        c = pgetc_macro();
     10532
     10533        if ((c != ' ') && (c != '\t')
     10534#if ENABLE_ASH_ALIAS
     10535         && (c != PEOA)
     10536#endif
     10537        ) {
     10538            if (c == '#') {
     10539                while ((c = pgetc()) != '\n' && c != PEOF);
     10540                pungetc();
     10541            } else if (c == '\\') {
     10542                if (pgetc() != '\n') {
     10543                    pungetc();
     10544                    goto READTOKEN1;
     10545                }
     10546                startlinno = ++plinno;
     10547                if (doprompt)
     10548                    setprompt(2);
     10549            } else {
     10550                const char *p
     10551                    = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
     10552
     10553                if (c != PEOF) {
     10554                    if (c == '\n') {
     10555                        plinno++;
     10556                        needprompt = doprompt;
     10557                    }
     10558
     10559                    p = strchr(xxreadtoken_chars, c);
     10560                    if (p == NULL) {
     10561 READTOKEN1:
     10562                        return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
     10563                    }
     10564
     10565                    if (p - xxreadtoken_chars >= xxreadtoken_singles) {
     10566                        if (pgetc() == *p) {    /* double occurrence? */
     10567                            p += xxreadtoken_doubles + 1;
     10568                        } else {
     10569                            pungetc();
     10570                        }
     10571                    }
     10572                }
     10573                return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
     10574            }
     10575        }
     10576    } /* for */
     10577}
     10578#else
     10579#define RETURN(token)   return lasttoken = token
     10580static int
     10581xxreadtoken(void)
     10582{
     10583    int c;
     10584
     10585    if (tokpushback) {
     10586        tokpushback = 0;
     10587        return lasttoken;
     10588    }
     10589    if (needprompt) {
     10590        setprompt(2);
     10591    }
     10592    startlinno = plinno;
     10593    for (;;) {      /* until token or start of word found */
     10594        c = pgetc_macro();
     10595        switch (c) {
     10596        case ' ': case '\t':
     10597#if ENABLE_ASH_ALIAS
     10598        case PEOA:
     10599#endif
    1077410600            continue;
    10775         if (c == CTLESC)
    10776             p++;
    10777         else if (SIT(c, BASESYNTAX) == CCTL)
    10778             return 0;
    10779     }
    10780     return 1;
    10781 }
    10782 
    10783 
    10784 /*
    10785  * Return of a legal variable name (a letter or underscore followed by zero or
    10786  * more letters, underscores, and digits).
    10787  */
    10788 
    10789 static char *
    10790 endofname(const char *name)
    10791 {
    10792     char *p;
    10793 
    10794     p = (char *) name;
    10795     if (! is_name(*p))
    10796         return p;
    10797     while (*++p) {
    10798         if (! is_in_name(*p))
    10799             break;
    10800     }
    10801     return p;
    10802 }
    10803 
    10804 
    10805 /*
    10806  * Called when an unexpected token is read during the parse.  The argument
    10807  * is the token that is expected, or -1 if more than one type of token can
    10808  * occur at this point.
    10809  */
    10810 
    10811 static void synexpect(int token)
    10812 {
    10813     char msg[64];
    10814     int l;
    10815 
    10816     l = sprintf(msg, "%s unexpected", tokname(lasttoken));
    10817     if (token >= 0)
    10818         sprintf(msg + l, " (expecting %s)", tokname(token));
    10819     synerror(msg);
    10820     /* NOTREACHED */
    10821 }
    10822 
    10823 static void
    10824 synerror(const char *msg)
    10825 {
    10826     sh_error("Syntax error: %s", msg);
    10827     /* NOTREACHED */
    10828 }
    10829 
    10830 
    10831 /*
    10832  * called by editline -- any expansions to the prompt
    10833  *    should be added here.
    10834  */
    10835 
    10836 #ifdef CONFIG_ASH_EXPAND_PRMT
     10601        case '#':
     10602            while ((c = pgetc()) != '\n' && c != PEOF);
     10603            pungetc();
     10604            continue;
     10605        case '\\':
     10606            if (pgetc() == '\n') {
     10607                startlinno = ++plinno;
     10608                if (doprompt)
     10609                    setprompt(2);
     10610                continue;
     10611            }
     10612            pungetc();
     10613            goto breakloop;
     10614        case '\n':
     10615            plinno++;
     10616            needprompt = doprompt;
     10617            RETURN(TNL);
     10618        case PEOF:
     10619            RETURN(TEOF);
     10620        case '&':
     10621            if (pgetc() == '&')
     10622                RETURN(TAND);
     10623            pungetc();
     10624            RETURN(TBACKGND);
     10625        case '|':
     10626            if (pgetc() == '|')
     10627                RETURN(TOR);
     10628            pungetc();
     10629            RETURN(TPIPE);
     10630        case ';':
     10631            if (pgetc() == ';')
     10632                RETURN(TENDCASE);
     10633            pungetc();
     10634            RETURN(TSEMI);
     10635        case '(':
     10636            RETURN(TLP);
     10637        case ')':
     10638            RETURN(TRP);
     10639        default:
     10640            goto breakloop;
     10641        }
     10642    }
     10643 breakloop:
     10644    return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
     10645#undef RETURN
     10646}
     10647#endif /* NEW_xxreadtoken */
     10648
     10649static int
     10650readtoken(void)
     10651{
     10652    int t;
     10653#if DEBUG
     10654    int alreadyseen = tokpushback;
     10655#endif
     10656
     10657#if ENABLE_ASH_ALIAS
     10658 top:
     10659#endif
     10660
     10661    t = xxreadtoken();
     10662
     10663    /*
     10664     * eat newlines
     10665     */
     10666    if (checkkwd & CHKNL) {
     10667        while (t == TNL) {
     10668            parseheredoc();
     10669            t = xxreadtoken();
     10670        }
     10671    }
     10672
     10673    if (t != TWORD || quoteflag) {
     10674        goto out;
     10675    }
     10676
     10677    /*
     10678     * check for keywords
     10679     */
     10680    if (checkkwd & CHKKWD) {
     10681        const char *const *pp;
     10682
     10683        pp = findkwd(wordtext);
     10684        if (pp) {
     10685            lasttoken = t = pp - tokname_array;
     10686            TRACE(("keyword %s recognized\n", tokname(t)));
     10687            goto out;
     10688        }
     10689    }
     10690
     10691    if (checkkwd & CHKALIAS) {
     10692#if ENABLE_ASH_ALIAS
     10693        struct alias *ap;
     10694        ap = lookupalias(wordtext, 1);
     10695        if (ap != NULL) {
     10696            if (*ap->val) {
     10697                pushstring(ap->val, ap);
     10698            }
     10699            goto top;
     10700        }
     10701#endif
     10702    }
     10703 out:
     10704    checkkwd = 0;
     10705#if DEBUG
     10706    if (!alreadyseen)
     10707        TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
     10708    else
     10709        TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
     10710#endif
     10711    return t;
     10712}
     10713
     10714static char
     10715peektoken(void)
     10716{
     10717    int t;
     10718
     10719    t = readtoken();
     10720    tokpushback++;
     10721    return tokname_array[t][0];
     10722}
     10723
     10724/*
     10725 * Read and parse a command.  Returns NEOF on end of file.  (NULL is a
     10726 * valid parse tree indicating a blank line.)
     10727 */
     10728static union node *
     10729parsecmd(int interact)
     10730{
     10731    int t;
     10732
     10733    tokpushback = 0;
     10734    doprompt = interact;
     10735    if (doprompt)
     10736        setprompt(doprompt);
     10737    needprompt = 0;
     10738    t = readtoken();
     10739    if (t == TEOF)
     10740        return NEOF;
     10741    if (t == TNL)
     10742        return NULL;
     10743    tokpushback++;
     10744    return list(1);
     10745}
     10746
     10747/*
     10748 * Input any here documents.
     10749 */
     10750static void
     10751parseheredoc(void)
     10752{
     10753    struct heredoc *here;
     10754    union node *n;
     10755
     10756    here = heredoclist;
     10757    heredoclist = 0;
     10758
     10759    while (here) {
     10760        if (needprompt) {
     10761            setprompt(2);
     10762        }
     10763        readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
     10764                here->eofmark, here->striptabs);
     10765        n = stalloc(sizeof(struct narg));
     10766        n->narg.type = NARG;
     10767        n->narg.next = NULL;
     10768        n->narg.text = wordtext;
     10769        n->narg.backquote = backquotelist;
     10770        here->here->nhere.doc = n;
     10771        here = here->next;
     10772    }
     10773}
     10774
     10775
     10776/*
     10777 * called by editline -- any expansions to the prompt should be added here.
     10778 */
     10779#if ENABLE_ASH_EXPAND_PRMT
    1083710780static const char *
    1083810781expandstr(const char *ps)
     
    1085510798#endif
    1085610799
    10857 static void setprompt(int whichprompt)
    10858 {
    10859     const char *prompt;
    10860 #ifdef CONFIG_ASH_EXPAND_PRMT
     10800/*
     10801 * Execute a command or commands contained in a string.
     10802 */
     10803static int
     10804evalstring(char *s, int mask)
     10805{
     10806    union node *n;
    1086110807    struct stackmark smark;
    10862 #endif
    10863 
    10864     needprompt = 0;
    10865 
    10866     switch (whichprompt) {
    10867     case 1:
    10868         prompt = ps1val();
    10869         break;
    10870     case 2:
    10871         prompt = ps2val();
    10872         break;
    10873     default:                        /* 0 */
    10874         prompt = nullstr;
    10875     }
    10876 #ifdef CONFIG_ASH_EXPAND_PRMT
     10808    int skip;
     10809
     10810    setinputstring(s);
    1087710811    setstackmark(&smark);
    10878     stalloc(stackblocksize());
    10879 #endif
    10880     putprompt(expandstr(prompt));
    10881 #ifdef CONFIG_ASH_EXPAND_PRMT
    10882     popstackmark(&smark);
    10883 #endif
    10884 }
    10885 
    10886 
    10887 static const char *const *findkwd(const char *s)
    10888 {
    10889     return bsearch(s, tokname_array + KWDOFFSET,
    10890                (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
    10891                    sizeof(const char *), pstrcmp);
    10892 }
    10893 
    10894 /*      redir.c      */
    10895 
    10896 /*
    10897  * Code for dealing with input/output redirection.
    10898  */
    10899 
    10900 #define EMPTY -2                /* marks an unused slot in redirtab */
    10901 #ifndef PIPE_BUF
    10902 # define PIPESIZE 4096          /* amount of buffering in a pipe */
    10903 #else
    10904 # define PIPESIZE PIPE_BUF
    10905 #endif
    10906 
    10907 /*
    10908  * Open a file in noclobber mode.
    10909  * The code was copied from bash.
    10910  */
    10911 static inline int
    10912 noclobberopen(const char *fname)
    10913 {
    10914     int r, fd;
    10915     struct stat finfo, finfo2;
    10916 
    10917     /*
    10918      * If the file exists and is a regular file, return an error
    10919      * immediately.
    10920      */
    10921     r = stat(fname, &finfo);
    10922     if (r == 0 && S_ISREG(finfo.st_mode)) {
    10923         errno = EEXIST;
    10924         return -1;
    10925     }
    10926 
    10927     /*
    10928      * If the file was not present (r != 0), make sure we open it
    10929      * exclusively so that if it is created before we open it, our open
    10930      * will fail.  Make sure that we do not truncate an existing file.
    10931      * Note that we don't turn on O_EXCL unless the stat failed -- if the
    10932      * file was not a regular file, we leave O_EXCL off.
    10933      */
    10934     if (r != 0)
    10935         return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
    10936     fd = open(fname, O_WRONLY|O_CREAT, 0666);
    10937 
    10938     /* If the open failed, return the file descriptor right away. */
    10939     if (fd < 0)
    10940         return fd;
    10941 
    10942     /*
    10943      * OK, the open succeeded, but the file may have been changed from a
    10944      * non-regular file to a regular file between the stat and the open.
    10945      * We are assuming that the O_EXCL open handles the case where FILENAME
    10946      * did not exist and is symlinked to an existing file between the stat
    10947      * and open.
    10948      */
    10949 
    10950     /*
    10951      * If we can open it and fstat the file descriptor, and neither check
    10952      * revealed that it was a regular file, and the file has not been
    10953      * replaced, return the file descriptor.
    10954      */
    10955      if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
    10956          finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
    10957         return fd;
    10958 
    10959     /* The file has been replaced.  badness. */
    10960     close(fd);
    10961     errno = EEXIST;
    10962     return -1;
    10963 }
    10964 
    10965 /*
    10966  * Handle here documents.  Normally we fork off a process to write the
    10967  * data to a pipe.  If the document is short, we can stuff the data in
    10968  * the pipe without forking.
    10969  */
    10970 
    10971 static inline int
    10972 openhere(union node *redir)
    10973 {
    10974     int pip[2];
    10975     size_t len = 0;
    10976 
    10977     if (pipe(pip) < 0)
    10978         sh_error("Pipe call failed");
    10979     if (redir->type == NHERE) {
    10980         len = strlen(redir->nhere.doc->narg.text);
    10981         if (len <= PIPESIZE) {
    10982             bb_full_write(pip[1], redir->nhere.doc->narg.text, len);
    10983             goto out;
    10984         }
    10985     }
    10986     if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
    10987         close(pip[0]);
    10988         signal(SIGINT, SIG_IGN);
    10989         signal(SIGQUIT, SIG_IGN);
    10990         signal(SIGHUP, SIG_IGN);
    10991 #ifdef SIGTSTP
    10992         signal(SIGTSTP, SIG_IGN);
    10993 #endif
    10994         signal(SIGPIPE, SIG_DFL);
    10995         if (redir->type == NHERE)
    10996             bb_full_write(pip[1], redir->nhere.doc->narg.text, len);
     10812
     10813    skip = 0;
     10814    while ((n = parsecmd(0)) != NEOF) {
     10815        evaltree(n, 0);
     10816        popstackmark(&smark);
     10817        skip = evalskip;
     10818        if (skip)
     10819            break;
     10820    }
     10821    popfile();
     10822
     10823    skip &= mask;
     10824    evalskip = skip;
     10825    return skip;
     10826}
     10827
     10828/*
     10829 * The eval command.
     10830 */
     10831static int
     10832evalcmd(int argc, char **argv)
     10833{
     10834    char *p;
     10835    char *concat;
     10836    char **ap;
     10837
     10838    if (argc > 1) {
     10839        p = argv[1];
     10840        if (argc > 2) {
     10841            STARTSTACKSTR(concat);
     10842            ap = argv + 2;
     10843            for (;;) {
     10844                concat = stack_putstr(p, concat);
     10845                p = *ap++;
     10846                if (p == NULL)
     10847                    break;
     10848                STPUTC(' ', concat);
     10849            }
     10850            STPUTC('\0', concat);
     10851            p = grabstackstr(concat);
     10852        }
     10853        evalstring(p, ~SKIPEVAL);
     10854
     10855    }
     10856    return exitstatus;
     10857}
     10858
     10859/*
     10860 * Read and execute commands.  "Top" is nonzero for the top level command
     10861 * loop; it turns on prompting if the shell is interactive.
     10862 */
     10863static int
     10864cmdloop(int top)
     10865{
     10866    union node *n;
     10867    struct stackmark smark;
     10868    int inter;
     10869    int numeof = 0;
     10870
     10871    TRACE(("cmdloop(%d) called\n", top));
     10872    for (;;) {
     10873        int skip;
     10874
     10875        setstackmark(&smark);
     10876#if JOBS
     10877        if (jobctl)
     10878            showjobs(stderr, SHOW_CHANGED);
     10879#endif
     10880        inter = 0;
     10881        if (iflag && top) {
     10882            inter++;
     10883#if ENABLE_ASH_MAIL
     10884            chkmail();
     10885#endif
     10886        }
     10887        n = parsecmd(inter);
     10888        /* showtree(n); DEBUG */
     10889        if (n == NEOF) {
     10890            if (!top || numeof >= 50)
     10891                break;
     10892            if (!stoppedjobs()) {
     10893                if (!Iflag)
     10894                    break;
     10895                out2str("\nUse \"exit\" to leave shell.\n");
     10896            }
     10897            numeof++;
     10898        } else if (nflag == 0) {
     10899            /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
     10900            job_warning >>= 1;
     10901            numeof = 0;
     10902            evaltree(n, 0);
     10903        }
     10904        popstackmark(&smark);
     10905        skip = evalskip;
     10906
     10907        if (skip) {
     10908            evalskip = 0;
     10909            return skip & SKIPEVAL;
     10910        }
     10911    }
     10912    return 0;
     10913}
     10914
     10915/*
     10916 * Take commands from a file.  To be compatible we should do a path
     10917 * search for the file, which is necessary to find sub-commands.
     10918 */
     10919static char *
     10920find_dot_file(char *name)
     10921{
     10922    char *fullname;
     10923    const char *path = pathval();
     10924    struct stat statb;
     10925
     10926    /* don't try this for absolute or relative paths */
     10927    if (strchr(name, '/'))
     10928        return name;
     10929
     10930    while ((fullname = padvance(&path, name)) != NULL) {
     10931        if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
     10932            /*
     10933             * Don't bother freeing here, since it will
     10934             * be freed by the caller.
     10935             */
     10936            return fullname;
     10937        }
     10938        stunalloc(fullname);
     10939    }
     10940
     10941    /* not found in the PATH */
     10942    ash_msg_and_raise_error("%s: not found", name);
     10943    /* NOTREACHED */
     10944}
     10945
     10946static int
     10947dotcmd(int argc, char **argv)
     10948{
     10949    struct strlist *sp;
     10950    volatile struct shparam saveparam;
     10951    int status = 0;
     10952
     10953    for (sp = cmdenviron; sp; sp = sp->next)
     10954        setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
     10955
     10956    if (argc >= 2) {        /* That's what SVR2 does */
     10957        char *fullname;
     10958
     10959        fullname = find_dot_file(argv[1]);
     10960
     10961        if (argc > 2) {
     10962            saveparam = shellparam;
     10963            shellparam.malloc = 0;
     10964            shellparam.nparam = argc - 2;
     10965            shellparam.p = argv + 2;
     10966        };
     10967
     10968        setinputfile(fullname, INPUT_PUSH_FILE);
     10969        commandname = fullname;
     10970        cmdloop(0);
     10971        popfile();
     10972
     10973        if (argc > 2) {
     10974            freeparam(&shellparam);
     10975            shellparam = saveparam;
     10976        };
     10977        status = exitstatus;
     10978    }
     10979    return status;
     10980}
     10981
     10982static int
     10983exitcmd(int argc, char **argv)
     10984{
     10985    if (stoppedjobs())
     10986        return 0;
     10987    if (argc > 1)
     10988        exitstatus = number(argv[1]);
     10989    raise_exception(EXEXIT);
     10990    /* NOTREACHED */
     10991}
     10992
     10993#if ENABLE_ASH_BUILTIN_ECHO
     10994static int
     10995echocmd(int argc, char **argv)
     10996{
     10997    return bb_echo(argv);
     10998}
     10999#endif
     11000
     11001#if ENABLE_ASH_BUILTIN_TEST
     11002static int
     11003testcmd(int argc, char **argv)
     11004{
     11005    return test_main(argc, argv);
     11006}
     11007#endif
     11008
     11009/*
     11010 * Read a file containing shell functions.
     11011 */
     11012static void
     11013readcmdfile(char *name)
     11014{
     11015    setinputfile(name, INPUT_PUSH_FILE);
     11016    cmdloop(0);
     11017    popfile();
     11018}
     11019
     11020
     11021/* ============ find_command inplementation */
     11022
     11023/*
     11024 * Resolve a command name.  If you change this routine, you may have to
     11025 * change the shellexec routine as well.
     11026 */
     11027static void
     11028find_command(char *name, struct cmdentry *entry, int act, const char *path)
     11029{
     11030    struct tblentry *cmdp;
     11031    int idx;
     11032    int prev;
     11033    char *fullname;
     11034    struct stat statb;
     11035    int e;
     11036    int updatetbl;
     11037    struct builtincmd *bcmd;
     11038
     11039    /* If name contains a slash, don't use PATH or hash table */
     11040    if (strchr(name, '/') != NULL) {
     11041        entry->u.index = -1;
     11042        if (act & DO_ABS) {
     11043            while (stat(name, &statb) < 0) {
     11044#ifdef SYSV
     11045                if (errno == EINTR)
     11046                    continue;
     11047#endif
     11048                entry->cmdtype = CMDUNKNOWN;
     11049                return;
     11050            }
     11051        }
     11052        entry->cmdtype = CMDNORMAL;
     11053        return;
     11054    }
     11055
     11056/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
     11057
     11058    updatetbl = (path == pathval());
     11059    if (!updatetbl) {
     11060        act |= DO_ALTPATH;
     11061        if (strstr(path, "%builtin") != NULL)
     11062            act |= DO_ALTBLTIN;
     11063    }
     11064
     11065    /* If name is in the table, check answer will be ok */
     11066    cmdp = cmdlookup(name, 0);
     11067    if (cmdp != NULL) {
     11068        int bit;
     11069
     11070        switch (cmdp->cmdtype) {
     11071        default:
     11072#if DEBUG
     11073            abort();
     11074#endif
     11075        case CMDNORMAL:
     11076            bit = DO_ALTPATH;
     11077            break;
     11078        case CMDFUNCTION:
     11079            bit = DO_NOFUNC;
     11080            break;
     11081        case CMDBUILTIN:
     11082            bit = DO_ALTBLTIN;
     11083            break;
     11084        }
     11085        if (act & bit) {
     11086            updatetbl = 0;
     11087            cmdp = NULL;
     11088        } else if (cmdp->rehash == 0)
     11089            /* if not invalidated by cd, we're done */
     11090            goto success;
     11091    }
     11092
     11093    /* If %builtin not in path, check for builtin next */
     11094    bcmd = find_builtin(name);
     11095    if (bcmd) {
     11096        if (IS_BUILTIN_REGULAR(bcmd))
     11097            goto builtin_success;
     11098        if (act & DO_ALTPATH) {
     11099            if (!(act & DO_ALTBLTIN))
     11100                goto builtin_success;
     11101        } else if (builtinloc <= 0) {
     11102            goto builtin_success;
     11103        }
     11104    }
     11105
     11106#if ENABLE_FEATURE_SH_STANDALONE
     11107    if (find_applet_by_name(name)) {
     11108        entry->cmdtype = CMDNORMAL;
     11109        entry->u.index = -1;
     11110        return;
     11111    }
     11112#endif
     11113
     11114    /* We have to search path. */
     11115    prev = -1;              /* where to start */
     11116    if (cmdp && cmdp->rehash) {     /* doing a rehash */
     11117        if (cmdp->cmdtype == CMDBUILTIN)
     11118            prev = builtinloc;
    1099711119        else
    10998             expandhere(redir->nhere.doc, pip[1]);
    10999         _exit(0);
    11000     }
    11001 out:
    11002     close(pip[1]);
    11003     return pip[0];
    11004 }
    11005 
     11120            prev = cmdp->param.index;
     11121    }
     11122
     11123    e = ENOENT;
     11124    idx = -1;
     11125 loop:
     11126    while ((fullname = padvance(&path, name)) != NULL) {
     11127        stunalloc(fullname);
     11128        /* NB: code below will still use fullname
     11129         * despite it being "unallocated" */
     11130        idx++;
     11131        if (pathopt) {
     11132            if (prefix(pathopt, "builtin")) {
     11133                if (bcmd)
     11134                    goto builtin_success;
     11135                continue;
     11136            } else if (!(act & DO_NOFUNC)
     11137             && prefix(pathopt, "func")) {
     11138                /* handled below */
     11139            } else {
     11140                /* ignore unimplemented options */
     11141                continue;
     11142            }
     11143        }
     11144        /* if rehash, don't redo absolute path names */
     11145        if (fullname[0] == '/' && idx <= prev) {
     11146            if (idx < prev)
     11147                continue;
     11148            TRACE(("searchexec \"%s\": no change\n", name));
     11149            goto success;
     11150        }
     11151        while (stat(fullname, &statb) < 0) {
     11152#ifdef SYSV
     11153            if (errno == EINTR)
     11154                continue;
     11155#endif
     11156            if (errno != ENOENT && errno != ENOTDIR)
     11157                e = errno;
     11158            goto loop;
     11159        }
     11160        e = EACCES;     /* if we fail, this will be the error */
     11161        if (!S_ISREG(statb.st_mode))
     11162            continue;
     11163        if (pathopt) {          /* this is a %func directory */
     11164            stalloc(strlen(fullname) + 1);
     11165            /* NB: stalloc will return space pointed by fullname
     11166             * (because we don't have any intervening allocations
     11167             * between stunalloc above and this stalloc) */
     11168            readcmdfile(fullname);
     11169            cmdp = cmdlookup(name, 0);
     11170            if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
     11171                ash_msg_and_raise_error("%s not defined in %s", name, fullname);
     11172            stunalloc(fullname);
     11173            goto success;
     11174        }
     11175        TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
     11176        if (!updatetbl) {
     11177            entry->cmdtype = CMDNORMAL;
     11178            entry->u.index = idx;
     11179            return;
     11180        }
     11181        INT_OFF;
     11182        cmdp = cmdlookup(name, 1);
     11183        cmdp->cmdtype = CMDNORMAL;
     11184        cmdp->param.index = idx;
     11185        INT_ON;
     11186        goto success;
     11187    }
     11188
     11189    /* We failed.  If there was an entry for this command, delete it */
     11190    if (cmdp && updatetbl)
     11191        delete_cmd_entry();
     11192    if (act & DO_ERR)
     11193        ash_msg("%s: %s", name, errmsg(e, "not found"));
     11194    entry->cmdtype = CMDUNKNOWN;
     11195    return;
     11196
     11197 builtin_success:
     11198    if (!updatetbl) {
     11199        entry->cmdtype = CMDBUILTIN;
     11200        entry->u.cmd = bcmd;
     11201        return;
     11202    }
     11203    INT_OFF;
     11204    cmdp = cmdlookup(name, 1);
     11205    cmdp->cmdtype = CMDBUILTIN;
     11206    cmdp->param.cmd = bcmd;
     11207    INT_ON;
     11208 success:
     11209    cmdp->rehash = 0;
     11210    entry->cmdtype = cmdp->cmdtype;
     11211    entry->u = cmdp->param;
     11212}
     11213
     11214
     11215/* ============ trap.c */
     11216
     11217/*
     11218 * The trap builtin.
     11219 */
    1100611220static int
    11007 openredirect(union node *redir)
    11008 {
    11009     char *fname;
    11010     int f;
    11011 
    11012     switch (redir->nfile.type) {
    11013     case NFROM:
    11014         fname = redir->nfile.expfname;
    11015         if ((f = open(fname, O_RDONLY)) < 0)
    11016             goto eopen;
    11017         break;
    11018     case NFROMTO:
    11019         fname = redir->nfile.expfname;
    11020         if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
    11021             goto ecreate;
    11022         break;
    11023     case NTO:
    11024         /* Take care of noclobber mode. */
    11025         if (Cflag) {
    11026             fname = redir->nfile.expfname;
    11027             if ((f = noclobberopen(fname)) < 0)
    11028                 goto ecreate;
    11029             break;
    11030         }
    11031         /* FALLTHROUGH */
    11032     case NCLOBBER:
    11033         fname = redir->nfile.expfname;
    11034         if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
    11035             goto ecreate;
    11036         break;
    11037     case NAPPEND:
    11038         fname = redir->nfile.expfname;
    11039         if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
    11040             goto ecreate;
    11041         break;
    11042     default:
    11043 #ifdef DEBUG
    11044         abort();
    11045 #endif
    11046         /* Fall through to eliminate warning. */
    11047     case NTOFD:
    11048     case NFROMFD:
    11049         f = -1;
    11050         break;
    11051     case NHERE:
    11052     case NXHERE:
    11053         f = openhere(redir);
    11054         break;
    11055     }
    11056 
    11057     return f;
    11058 ecreate:
    11059     sh_error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
    11060 eopen:
    11061     sh_error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
    11062 }
    11063 
    11064 static inline void
    11065 dupredirect(union node *redir, int f)
    11066 {
    11067     int fd = redir->nfile.fd;
    11068 
    11069     if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
    11070         if (redir->ndup.dupfd >= 0) {   /* if not ">&-" */
    11071                 copyfd(redir->ndup.dupfd, fd);
    11072         }
    11073         return;
    11074     }
    11075 
    11076     if (f != fd) {
    11077         copyfd(f, fd);
    11078         close(f);
    11079     }
    11080     return;
    11081 }
    11082 
    11083 /*
    11084  * Process a list of redirection commands.  If the REDIR_PUSH flag is set,
    11085  * old file descriptors are stashed away so that the redirection can be
    11086  * undone by calling popredir.  If the REDIR_BACKQ flag is set, then the
    11087  * standard output, and the standard error if it becomes a duplicate of
    11088  * stdout, is saved in memory.
    11089  */
    11090 
    11091 static void
    11092 redirect(union node *redir, int flags)
    11093 {
    11094     union node *n;
    11095     struct redirtab *sv;
    11096     int i;
    11097     int fd;
    11098     int newfd;
    11099     int *p;
    11100     nullredirs++;
    11101     if (!redir) {
    11102         return;
    11103     }
    11104     sv = NULL;
    11105     INTOFF;
    11106     if (flags & REDIR_PUSH) {
    11107         struct redirtab *q;
    11108         q = ckmalloc(sizeof (struct redirtab));
    11109         q->next = redirlist;
    11110         redirlist = q;
    11111         q->nullredirs = nullredirs - 1;
    11112         for (i = 0 ; i < 10 ; i++)
    11113             q->renamed[i] = EMPTY;
    11114         nullredirs = 0;
    11115         sv = q;
    11116     }
    11117     n = redir;
    11118     do {
    11119         fd = n->nfile.fd;
    11120         if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
    11121             n->ndup.dupfd == fd)
    11122             continue; /* redirect from/to same file descriptor */
    11123 
    11124         newfd = openredirect(n);
    11125         if (fd == newfd)
    11126             continue;
    11127         if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
    11128             i = fcntl(fd, F_DUPFD, 10);
    11129 
    11130             if (i == -1) {
    11131                 i = errno;
    11132                 if (i != EBADF) {
    11133                     close(newfd);
    11134                     errno = i;
    11135                     sh_error("%d: %m", fd);
    11136                     /* NOTREACHED */
    11137                 }
    11138             } else {
    11139                 *p = i;
    11140                 close(fd);
    11141             }
    11142         } else {
    11143             close(fd);
    11144         }
    11145         dupredirect(n, newfd);
    11146     } while ((n = n->nfile.next));
    11147     INTON;
    11148     if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0)
    11149         preverrout_fd = sv->renamed[2];
    11150 }
    11151 
    11152 
    11153 /*
    11154  * Undo the effects of the last redirection.
    11155  */
    11156 
    11157 void
    11158 popredir(int drop)
    11159 {
    11160     struct redirtab *rp;
    11161     int i;
    11162 
    11163     if (--nullredirs >= 0)
    11164         return;
    11165     INTOFF;
    11166     rp = redirlist;
    11167     for (i = 0 ; i < 10 ; i++) {
    11168         if (rp->renamed[i] != EMPTY) {
    11169             if (!drop) {
    11170                 close(i);
    11171                 copyfd(rp->renamed[i], i);
    11172             }
    11173             close(rp->renamed[i]);
    11174         }
    11175     }
    11176     redirlist = rp->next;
    11177     nullredirs = rp->nullredirs;
    11178     ckfree(rp);
    11179     INTON;
    11180 }
    11181 
    11182 /*
    11183  * Undo all redirections.  Called on error or interrupt.
    11184  */
    11185 
    11186 /*
    11187  * Discard all saved file descriptors.
    11188  */
    11189 
    11190 void
    11191 clearredir(int drop)
    11192 {
    11193     for (;;) {
    11194         nullredirs = 0;
    11195         if (!redirlist)
    11196             break;
    11197         popredir(drop);
    11198     }
    11199 }
    11200 
    11201 
    11202 /*
    11203  * Copy a file descriptor to be >= to.  Returns -1
    11204  * if the source file descriptor is closed, EMPTY if there are no unused
    11205  * file descriptors left.
    11206  */
    11207 
    11208 int
    11209 copyfd(int from, int to)
    11210 {
    11211     int newfd;
    11212 
    11213     newfd = fcntl(from, F_DUPFD, to);
    11214     if (newfd < 0) {
    11215         if (errno == EMFILE)
    11216             return EMPTY;
    11217         else
    11218             sh_error("%d: %m", from);
    11219     }
    11220     return newfd;
    11221 }
    11222 
    11223 
    11224 int
    11225 redirectsafe(union node *redir, int flags)
    11226 {
    11227     int err;
    11228     volatile int saveint;
    11229     struct jmploc *volatile savehandler = handler;
    11230     struct jmploc jmploc;
    11231 
    11232     SAVEINT(saveint);
    11233     if (!(err = setjmp(jmploc.loc) * 2)) {
    11234         handler = &jmploc;
    11235         redirect(redir, flags);
    11236     }
    11237     handler = savehandler;
    11238     if (err && exception != EXERROR)
    11239         longjmp(handler->loc, 1);
    11240     RESTOREINT(saveint);
    11241     return err;
    11242 }
    11243 
    11244 /*      show.c    */
    11245 
    11246 #ifdef DEBUG
    11247 static void shtree(union node *, int, char *, FILE*);
    11248 static void shcmd(union node *, FILE *);
    11249 static void sharg(union node *, FILE *);
    11250 static void indent(int, char *, FILE *);
    11251 static void trstring(char *);
    11252 
    11253 
    11254 void
    11255 showtree(union node *n)
    11256 {
    11257     trputs("showtree called\n");
    11258     shtree(n, 1, NULL, stdout);
    11259 }
    11260 
    11261 
    11262 static void
    11263 shtree(union node *n, int ind, char *pfx, FILE *fp)
    11264 {
    11265     struct nodelist *lp;
    11266     const char *s;
    11267 
    11268     if (n == NULL)
    11269         return;
    11270 
    11271     indent(ind, pfx, fp);
    11272     switch(n->type) {
    11273     case NSEMI:
    11274         s = "; ";
    11275         goto binop;
    11276     case NAND:
    11277         s = " && ";
    11278         goto binop;
    11279     case NOR:
    11280         s = " || ";
    11281 binop:
    11282         shtree(n->nbinary.ch1, ind, NULL, fp);
    11283        /*    if (ind < 0) */
    11284             fputs(s, fp);
    11285         shtree(n->nbinary.ch2, ind, NULL, fp);
    11286         break;
    11287     case NCMD:
    11288         shcmd(n, fp);
    11289         if (ind >= 0)
    11290             putc('\n', fp);
    11291         break;
    11292     case NPIPE:
    11293         for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
    11294             shcmd(lp->n, fp);
    11295             if (lp->next)
    11296                 fputs(" | ", fp);
    11297         }
    11298         if (n->npipe.backgnd)
    11299             fputs(" &", fp);
    11300         if (ind >= 0)
    11301             putc('\n', fp);
    11302         break;
    11303     default:
    11304         fprintf(fp, "<node type %d>", n->type);
    11305         if (ind >= 0)
    11306             putc('\n', fp);
    11307         break;
    11308     }
    11309 }
    11310 
    11311 
    11312 static void
    11313 shcmd(union node *cmd, FILE *fp)
    11314 {
    11315     union node *np;
    11316     int first;
    11317     const char *s;
    11318     int dftfd;
    11319 
    11320     first = 1;
    11321     for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
    11322         if (! first)
    11323             putchar(' ');
    11324         sharg(np, fp);
    11325         first = 0;
    11326     }
    11327     for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
    11328         if (! first)
    11329             putchar(' ');
    11330         switch (np->nfile.type) {
    11331             case NTO:       s = ">";  dftfd = 1; break;
    11332             case NCLOBBER:  s = ">|"; dftfd = 1; break;
    11333             case NAPPEND:   s = ">>"; dftfd = 1; break;
    11334             case NTOFD:     s = ">&"; dftfd = 1; break;
    11335             case NFROM:     s = "<";  dftfd = 0; break;
    11336             case NFROMFD:   s = "<&"; dftfd = 0; break;
    11337             case NFROMTO:   s = "<>"; dftfd = 0; break;
    11338             default:        s = "*error*"; dftfd = 0; break;
    11339         }
    11340         if (np->nfile.fd != dftfd)
    11341             fprintf(fp, "%d", np->nfile.fd);
    11342         fputs(s, fp);
    11343         if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
    11344             fprintf(fp, "%d", np->ndup.dupfd);
    11345         } else {
    11346             sharg(np->nfile.fname, fp);
    11347         }
    11348         first = 0;
    11349     }
    11350 }
    11351 
    11352 
    11353 
    11354 static void
    11355 sharg(union node *arg, FILE *fp)
    11356 {
    11357     char *p;
    11358     struct nodelist *bqlist;
    11359     int subtype;
    11360 
    11361     if (arg->type != NARG) {
    11362         out1fmt("<node type %d>\n", arg->type);
    11363         abort();
    11364     }
    11365     bqlist = arg->narg.backquote;
    11366     for (p = arg->narg.text ; *p ; p++) {
    11367         switch (*p) {
    11368         case CTLESC:
    11369             putc(*++p, fp);
    11370             break;
    11371         case CTLVAR:
    11372             putc('$', fp);
    11373             putc('{', fp);
    11374             subtype = *++p;
    11375             if (subtype == VSLENGTH)
    11376                 putc('#', fp);
    11377 
    11378             while (*p != '=')
    11379                 putc(*p++, fp);
    11380 
    11381             if (subtype & VSNUL)
    11382                 putc(':', fp);
    11383 
    11384             switch (subtype & VSTYPE) {
    11385             case VSNORMAL:
    11386                 putc('}', fp);
    11387                 break;
    11388             case VSMINUS:
    11389                 putc('-', fp);
    11390                 break;
    11391             case VSPLUS:
    11392                 putc('+', fp);
    11393                 break;
    11394             case VSQUESTION:
    11395                 putc('?', fp);
    11396                 break;
    11397             case VSASSIGN:
    11398                 putc('=', fp);
    11399                 break;
    11400             case VSTRIMLEFT:
    11401                 putc('#', fp);
    11402                 break;
    11403             case VSTRIMLEFTMAX:
    11404                 putc('#', fp);
    11405                 putc('#', fp);
    11406                 break;
    11407             case VSTRIMRIGHT:
    11408                 putc('%', fp);
    11409                 break;
    11410             case VSTRIMRIGHTMAX:
    11411                 putc('%', fp);
    11412                 putc('%', fp);
    11413                 break;
    11414             case VSLENGTH:
    11415                 break;
    11416             default:
    11417                 out1fmt("<subtype %d>", subtype);
    11418             }
    11419             break;
    11420         case CTLENDVAR:
    11421              putc('}', fp);
    11422              break;
    11423         case CTLBACKQ:
    11424         case CTLBACKQ|CTLQUOTE:
    11425             putc('$', fp);
    11426             putc('(', fp);
    11427             shtree(bqlist->n, -1, NULL, fp);
    11428             putc(')', fp);
    11429             break;
    11430         default:
    11431             putc(*p, fp);
    11432             break;
    11433         }
    11434     }
    11435 }
    11436 
    11437 
    11438 static void
    11439 indent(int amount, char *pfx, FILE *fp)
    11440 {
    11441     int i;
    11442 
    11443     for (i = 0 ; i < amount ; i++) {
    11444         if (pfx && i == amount - 1)
    11445             fputs(pfx, fp);
    11446         putc('\t', fp);
    11447     }
    11448 }
    11449 
    11450 
    11451 
    11452 /*
    11453  * Debugging stuff.
    11454  */
    11455 
    11456 
    11457 FILE *tracefile;
    11458 
    11459 
    11460 void
    11461 trputc(int c)
    11462 {
    11463     if (debug != 1)
    11464         return;
    11465     putc(c, tracefile);
    11466 }
    11467 
    11468 void
    11469 trace(const char *fmt, ...)
    11470 {
    11471     va_list va;
    11472 
    11473     if (debug != 1)
    11474         return;
    11475     va_start(va, fmt);
    11476     (void) vfprintf(tracefile, fmt, va);
    11477     va_end(va);
    11478 }
    11479 
    11480 void
    11481 tracev(const char *fmt, va_list va)
    11482 {
    11483     if (debug != 1)
    11484         return;
    11485     (void) vfprintf(tracefile, fmt, va);
    11486 }
    11487 
    11488 
    11489 void
    11490 trputs(const char *s)
    11491 {
    11492     if (debug != 1)
    11493         return;
    11494     fputs(s, tracefile);
    11495 }
    11496 
    11497 
    11498 static void
    11499 trstring(char *s)
    11500 {
    11501     char *p;
    11502     char c;
    11503 
    11504     if (debug != 1)
    11505         return;
    11506     putc('"', tracefile);
    11507     for (p = s ; *p ; p++) {
    11508         switch (*p) {
    11509         case '\n':  c = 'n';  goto backslash;
    11510         case '\t':  c = 't';  goto backslash;
    11511         case '\r':  c = 'r';  goto backslash;
    11512         case '"':  c = '"';  goto backslash;
    11513         case '\\':  c = '\\';  goto backslash;
    11514         case CTLESC:  c = 'e';  goto backslash;
    11515         case CTLVAR:  c = 'v';  goto backslash;
    11516         case CTLVAR+CTLQUOTE:  c = 'V';  goto backslash;
    11517         case CTLBACKQ:  c = 'q';  goto backslash;
    11518         case CTLBACKQ+CTLQUOTE:  c = 'Q';  goto backslash;
    11519 backslash:        putc('\\', tracefile);
    11520             putc(c, tracefile);
    11521             break;
    11522         default:
    11523             if (*p >= ' ' && *p <= '~')
    11524                 putc(*p, tracefile);
    11525             else {
    11526                 putc('\\', tracefile);
    11527                 putc(*p >> 6 & 03, tracefile);
    11528                 putc(*p >> 3 & 07, tracefile);
    11529                 putc(*p & 07, tracefile);
    11530             }
    11531             break;
    11532         }
    11533     }
    11534     putc('"', tracefile);
    11535 }
    11536 
    11537 
    11538 void
    11539 trargs(char **ap)
    11540 {
    11541     if (debug != 1)
    11542         return;
    11543     while (*ap) {
    11544         trstring(*ap++);
    11545         if (*ap)
    11546             putc(' ', tracefile);
    11547         else
    11548             putc('\n', tracefile);
    11549     }
    11550 }
    11551 
    11552 
    11553 void
    11554 opentrace(void)
    11555 {
    11556     char s[100];
    11557 #ifdef O_APPEND
    11558     int flags;
    11559 #endif
    11560 
    11561     if (debug != 1) {
    11562         if (tracefile)
    11563             fflush(tracefile);
    11564         /* leave open because libedit might be using it */
    11565         return;
    11566     }
    11567     scopy("./trace", s);
    11568     if (tracefile) {
    11569         if (!freopen(s, "a", tracefile)) {
    11570             fprintf(stderr, "Can't re-open %s\n", s);
    11571             debug = 0;
    11572             return;
    11573         }
    11574     } else {
    11575         if ((tracefile = fopen(s, "a")) == NULL) {
    11576             fprintf(stderr, "Can't open %s\n", s);
    11577             debug = 0;
    11578             return;
    11579         }
    11580     }
    11581 #ifdef O_APPEND
    11582     if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
    11583         fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
    11584 #endif
    11585     setlinebuf(tracefile);
    11586     fputs("\nTracing started.\n", tracefile);
    11587 }
    11588 #endif /* DEBUG */
    11589 
    11590 
    11591 /*      trap.c       */
    11592 
    11593 /*
    11594  * Sigmode records the current value of the signal handlers for the various
    11595  * modes.  A value of zero means that the current handler is not known.
    11596  * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
    11597  */
    11598 
    11599 #define S_DFL 1                 /* default signal handling (SIG_DFL) */
    11600 #define S_CATCH 2               /* signal is caught */
    11601 #define S_IGN 3                 /* signal is ignored (SIG_IGN) */
    11602 #define S_HARD_IGN 4            /* signal is ignored permenantly */
    11603 #define S_RESET 5               /* temporary - to reset a hard ignored sig */
    11604 
    11605 
    11606 
    11607 /*
    11608  * The trap builtin.
    11609  */
    11610 
    11611 int
    1161211221trapcmd(int argc, char **argv)
    1161311222{
     
    1161911228    ap = argptr;
    1162011229    if (!*ap) {
    11621         for (signo = 0 ; signo < NSIG ; signo++) {
     11230        for (signo = 0; signo < NSIG; signo++) {
    1162211231            if (trap[signo] != NULL) {
    1162311232                const char *sn;
    1162411233
    11625                 sn = u_signal_names(0, &signo, 0);
    11626                 if (sn == NULL)
    11627                     sn = "???";
     11234                sn = get_signame(signo);
    1162811235                out1fmt("trap -- %s %s\n",
    1162911236                    single_quote(trap[signo]), sn);
     
    1163711244        action = *ap++;
    1163811245    while (*ap) {
    11639         if ((signo = decode_signal(*ap, 0)) < 0)
    11640             sh_error("%s: bad trap", *ap);
    11641         INTOFF;
     11246        signo = get_signum(*ap);
     11247        if (signo < 0)
     11248            ash_msg_and_raise_error("%s: bad trap", *ap);
     11249        INT_OFF;
    1164211250        if (action) {
    11643             if (action[0] == '-' && action[1] == '\0')
     11251            if (LONE_DASH(action))
    1164411252                action = NULL;
    1164511253            else
    11646                 action = savestr(action);
     11254                action = ckstrdup(action);
    1164711255        }
    1164811256        if (trap[signo])
    11649             ckfree(trap[signo]);
     11257            free(trap[signo]);
    1165011258        trap[signo] = action;
    1165111259        if (signo != 0)
    1165211260            setsignal(signo);
    11653         INTON;
     11261        INT_ON;
    1165411262        ap++;
    1165511263    }
     
    1165811266
    1165911267
    11660 /*
    11661  * Clear traps on a fork.
    11662  */
    11663 
    11664 void
    11665 clear_traps(void)
    11666 {
    11667     char **tp;
    11668 
    11669     for (tp = trap ; tp < &trap[NSIG] ; tp++) {
    11670         if (*tp && **tp) {      /* trap not NULL or SIG_IGN */
    11671             INTOFF;
    11672             ckfree(*tp);
    11673             *tp = NULL;
    11674             if (tp != &trap[0])
    11675                 setsignal(tp - trap);
    11676             INTON;
    11677         }
    11678     }
    11679 }
    11680 
    11681 
    11682 /*
    11683  * Set the signal handler for the specified signal.  The routine figures
    11684  * out what it should be set to.
    11685  */
    11686 
    11687 void
    11688 setsignal(int signo)
    11689 {
    11690     int action;
    11691     char *t, tsig;
    11692     struct sigaction act;
    11693 
    11694     if ((t = trap[signo]) == NULL)
    11695         action = S_DFL;
    11696     else if (*t != '\0')
    11697         action = S_CATCH;
    11698     else
    11699         action = S_IGN;
    11700     if (rootshell && action == S_DFL) {
    11701         switch (signo) {
    11702         case SIGINT:
    11703             if (iflag || minusc || sflag == 0)
    11704                 action = S_CATCH;
    11705             break;
    11706         case SIGQUIT:
    11707 #ifdef DEBUG
    11708             if (debug)
    11709                 break;
    11710 #endif
    11711             /* FALLTHROUGH */
    11712         case SIGTERM:
    11713             if (iflag)
    11714                 action = S_IGN;
    11715             break;
    11716 #if JOBS
    11717         case SIGTSTP:
    11718         case SIGTTOU:
    11719             if (mflag)
    11720                 action = S_IGN;
    11721             break;
    11722 #endif
    11723         }
    11724     }
    11725 
    11726     t = &sigmode[signo - 1];
    11727     tsig = *t;
    11728     if (tsig == 0) {
    11729         /*
    11730          * current setting unknown
    11731          */
    11732         if (sigaction(signo, 0, &act) == -1) {
    11733             /*
    11734              * Pretend it worked; maybe we should give a warning
    11735              * here, but other shells don't. We don't alter
    11736              * sigmode, so that we retry every time.
    11737              */
    11738             return;
    11739         }
    11740         if (act.sa_handler == SIG_IGN) {
    11741             if (mflag && (signo == SIGTSTP ||
    11742                  signo == SIGTTIN || signo == SIGTTOU)) {
    11743                 tsig = S_IGN;   /* don't hard ignore these */
    11744             } else
    11745                 tsig = S_HARD_IGN;
    11746         } else {
    11747             tsig = S_RESET; /* force to be set */
    11748         }
    11749     }
    11750     if (tsig == S_HARD_IGN || tsig == action)
    11751         return;
    11752     switch (action) {
    11753     case S_CATCH:
    11754         act.sa_handler = onsig;
    11755         break;
    11756     case S_IGN:
    11757         act.sa_handler = SIG_IGN;
    11758         break;
    11759     default:
    11760         act.sa_handler = SIG_DFL;
    11761     }
    11762     *t = action;
    11763     act.sa_flags = 0;
    11764     sigfillset(&act.sa_mask);
    11765     sigaction(signo, &act, 0);
    11766 }
    11767 
    11768 /*
    11769  * Ignore a signal.
    11770  */
    11771 
    11772 void
    11773 ignoresig(int signo)
    11774 {
    11775     if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
    11776         signal(signo, SIG_IGN);
    11777     }
    11778     sigmode[signo - 1] = S_HARD_IGN;
    11779 }
    11780 
    11781 
    11782 /*
    11783  * Signal handler.
    11784  */
    11785 
    11786 void
    11787 onsig(int signo)
    11788 {
    11789     gotsig[signo - 1] = 1;
    11790     pendingsigs = signo;
    11791 
    11792     if (exsig || (signo == SIGINT && !trap[SIGINT])) {
    11793         if (!suppressint)
    11794             onint();
    11795         intpending = 1;
    11796     }
    11797 }
    11798 
    11799 
    11800 /*
    11801  * Called to execute a trap.  Perhaps we should avoid entering new trap
    11802  * handlers while we are executing a trap handler.
    11803  */
    11804 
    11805 int
    11806 dotrap(void)
    11807 {
    11808     char *p;
    11809     char *q;
    11810     int i;
    11811     int savestatus;
    11812     int skip = 0;
    11813 
    11814     savestatus = exitstatus;
    11815     pendingsigs = 0;
    11816     xbarrier();
    11817 
    11818     for (i = 0, q = gotsig; i < NSIG - 1; i++, q++) {
    11819         if (!*q)
    11820             continue;
    11821         *q = 0;
    11822 
    11823         p = trap[i + 1];
    11824         if (!p)
    11825             continue;
    11826         skip = evalstring(p, SKIPEVAL);
    11827         exitstatus = savestatus;
    11828         if (skip)
    11829             break;
    11830     }
    11831 
    11832     return skip;
    11833 }
    11834 
    11835 
    11836 /*
    11837  * Controls whether the shell is interactive or not.
    11838  */
    11839 
    11840 void
    11841 setinteractive(int on)
    11842 {
    11843     static int is_interactive;
    11844 
    11845     if (++on == is_interactive)
    11846         return;
    11847     is_interactive = on;
    11848     setsignal(SIGINT);
    11849     setsignal(SIGQUIT);
    11850     setsignal(SIGTERM);
    11851 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
    11852         if(is_interactive > 1) {
    11853             /* Looks like they want an interactive shell */
    11854             static int do_banner;
    11855 
    11856                 if(!do_banner) {
    11857                     out1fmt(
    11858             "\n\n%s Built-in shell (ash)\n"
    11859             "Enter 'help' for a list of built-in commands.\n\n",
    11860                     BB_BANNER);
    11861                     do_banner++;
    11862                 }
    11863         }
    11864 #endif
    11865 }
    11866 
    11867 
    11868 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
    11869 /*** List the available builtins ***/
    11870 
    11871 static int helpcmd(int argc, char **argv)
     11268/* ============ Builtins */
     11269
     11270#if !ENABLE_FEATURE_SH_EXTRA_QUIET
     11271/*
     11272 * Lists available builtins
     11273 */
     11274static int
     11275helpcmd(int argc, char **argv)
    1187211276{
    1187311277    int col, i;
    1187411278
    1187511279    out1fmt("\nBuilt-in commands:\n-------------------\n");
    11876     for (col = 0, i = 0; i < NUMBUILTINS; i++) {
     11280    for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
    1187711281        col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
    11878                       builtincmd[i].name + 1);
     11282                    builtintab[i].name + 1);
    1187911283        if (col > 60) {
    1188011284            out1fmt("\n");
     
    1188211286        }
    1188311287    }
    11884 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
    11885     {
    11886         extern const struct BB_applet applets[];
    11887         extern const size_t NUM_APPLETS;
    11888 
    11889         for (i = 0; i < NUM_APPLETS; i++) {
    11890 
    11891             col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
    11892             if (col > 60) {
    11893                 out1fmt("\n");
    11894                 col = 0;
    11895             }
     11288#if ENABLE_FEATURE_SH_STANDALONE
     11289    for (i = 0; i < NUM_APPLETS; i++) {
     11290        col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
     11291        if (col > 60) {
     11292            out1fmt("\n");
     11293            col = 0;
    1189611294        }
    1189711295    }
     
    1190011298    return EXIT_SUCCESS;
    1190111299}
    11902 #endif /* CONFIG_FEATURE_SH_EXTRA_QUIET */
    11903 
    11904 /*
    11905  * Called to exit the shell.
    11906  */
    11907 
    11908 void
    11909 exitshell(void)
    11910 {
    11911     struct jmploc loc;
    11912     char *p;
    11913     int status;
    11914 
    11915     status = exitstatus;
    11916     TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
    11917     if (setjmp(loc.loc)) {
    11918         if (exception == EXEXIT)
    11919             _exit(exitstatus);
    11920         goto out;
    11921     }
    11922     handler = &loc;
    11923     if ((p = trap[0])) {
    11924         trap[0] = NULL;
    11925         evalstring(p, 0);
    11926     }
    11927     flushall();
    11928     setjobctl(0);
    11929 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
    11930     if (iflag && rootshell) {
    11931         const char *hp = lookupvar("HISTFILE");
    11932 
    11933         if(hp != NULL )
    11934             save_history ( hp );
    11935     }
    11936 #endif
    11937 out:
    11938     _exit(status);
    11939     /* NOTREACHED */
    11940 }
    11941 
    11942 static int decode_signal(const char *string, int minsig)
    11943 {
    11944     int signo;
    11945     const char *name = u_signal_names(string, &signo, minsig);
    11946 
    11947     return name ? signo : -1;
    11948 }
    11949 
    11950 /*      var.c     */
    11951 
    11952 static struct var *vartab[VTABSIZE];
    11953 
    11954 static int vpcmp(const void *, const void *);
    11955 static struct var **findvar(struct var **, const char *);
    11956 
    11957 /*
    11958  * Initialize the variable symbol tables and import the environment
    11959  */
    11960 
    11961 
    11962 #ifdef CONFIG_ASH_GETOPTS
    11963 /*
    11964  * Safe version of setvar, returns 1 on success 0 on failure.
    11965  */
    11966 
    11967 int
    11968 setvarsafe(const char *name, const char *val, int flags)
    11969 {
    11970     int err;
    11971     volatile int saveint;
    11972     struct jmploc *volatile savehandler = handler;
    11973     struct jmploc jmploc;
    11974 
    11975     SAVEINT(saveint);
    11976     if (setjmp(jmploc.loc))
    11977         err = 1;
    11978     else {
    11979         handler = &jmploc;
    11980         setvar(name, val, flags);
    11981         err = 0;
    11982     }
    11983     handler = savehandler;
    11984     RESTOREINT(saveint);
    11985     return err;
    11986 }
    11987 #endif
    11988 
    11989 /*
    11990  * Set the value of a variable.  The flags argument is ored with the
    11991  * flags of the variable.  If val is NULL, the variable is unset.
    11992  */
    11993 
    11994 static void
    11995 setvar(const char *name, const char *val, int flags)
    11996 {
    11997     char *p, *q;
    11998     size_t namelen;
    11999     char *nameeq;
    12000     size_t vallen;
    12001 
    12002     q = endofname(name);
    12003     p = strchrnul(q, '=');
    12004     namelen = p - name;
    12005     if (!namelen || p != q)
    12006         sh_error("%.*s: bad variable name", namelen, name);
    12007     vallen = 0;
    12008     if (val == NULL) {
    12009         flags |= VUNSET;
    12010     } else {
    12011         vallen = strlen(val);
    12012     }
    12013     INTOFF;
    12014     p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
    12015     if (val) {
    12016         *p++ = '=';
    12017         p = mempcpy(p, val, vallen);
    12018     }
    12019     *p = '\0';
    12020     setvareq(nameeq, flags | VNOSAVE);
    12021     INTON;
    12022 }
    12023 
    12024 
    12025 /*
    12026  * Same as setvar except that the variable and value are passed in
    12027  * the first argument as name=value.  Since the first argument will
    12028  * be actually stored in the table, it should not be a string that
    12029  * will go away.
    12030  * Called with interrupts off.
    12031  */
    12032 
    12033 void
    12034 setvareq(char *s, int flags)
    12035 {
    12036     struct var *vp, **vpp;
    12037 
    12038     vpp = hashvar(s);
    12039     flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
    12040     vp = *findvar(vpp, s);
    12041     if (vp) {
    12042         if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
    12043             const char *n;
    12044 
    12045             if (flags & VNOSAVE)
    12046                 free(s);
    12047             n = vp->text;
    12048             sh_error("%.*s: is read only", strchrnul(n, '=') - n, n);
    12049         }
    12050 
    12051         if (flags & VNOSET)
    12052             return;
    12053 
    12054         if (vp->func && (flags & VNOFUNC) == 0)
    12055             (*vp->func)(strchrnul(s, '=') + 1);
    12056 
    12057         if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
    12058             ckfree(vp->text);
    12059 
    12060         flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
    12061     } else {
    12062         if (flags & VNOSET)
    12063             return;
    12064         /* not found */
    12065         vp = ckmalloc(sizeof (*vp));
    12066         vp->next = *vpp;
    12067         vp->func = NULL;
    12068         *vpp = vp;
    12069     }
    12070     if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
    12071         s = savestr(s);
    12072     vp->text = s;
    12073     vp->flags = flags;
    12074 }
    12075 
    12076 
    12077 /*
    12078  * Process a linked list of variable assignments.
    12079  */
    12080 
    12081 static void
    12082 listsetvar(struct strlist *list_set_var, int flags)
    12083 {
    12084     struct strlist *lp = list_set_var;
    12085 
    12086     if (!lp)
    12087         return;
    12088     INTOFF;
    12089     do {
    12090         setvareq(lp->text, flags);
    12091     } while ((lp = lp->next));
    12092     INTON;
    12093 }
    12094 
    12095 
    12096 /*
    12097  * Find the value of a variable.  Returns NULL if not set.
    12098  */
    12099 
    12100 static char *
    12101 lookupvar(const char *name)
    12102 {
    12103     struct var *v;
    12104 
    12105     if ((v = *findvar(hashvar(name), name))) {
    12106 #ifdef DYNAMIC_VAR
    12107     /*
    12108      * Dynamic variables are implemented roughly the same way they are
    12109      * in bash. Namely, they're "special" so long as they aren't unset.
    12110      * As soon as they're unset, they're no longer dynamic, and dynamic
    12111      * lookup will no longer happen at that point. -- PFM.
    12112      */
    12113         if((v->flags & VDYNAMIC))
    12114             (*v->func)(NULL);
    12115 #endif
    12116         if(!(v->flags & VUNSET))
    12117             return strchrnul(v->text, '=') + 1;
    12118     }
    12119 
    12120     return NULL;
    12121 }
    12122 
    12123 
    12124 /*
    12125  * Search the environment of a builtin command.
    12126  */
    12127 
    12128 static char *
    12129 bltinlookup(const char *name)
    12130 {
    12131     struct strlist *sp;
    12132 
    12133     for (sp = cmdenviron ; sp ; sp = sp->next) {
    12134         if (varequal(sp->text, name))
    12135             return strchrnul(sp->text, '=') + 1;
    12136     }
    12137     return lookupvar(name);
    12138 }
    12139 
    12140 
    12141 /*
    12142  * Generate a list of variables satisfying the given conditions.
    12143  */
    12144 
    12145 static char **
    12146 listvars(int on, int off, char ***end)
    12147 {
    12148     struct var **vpp;
    12149     struct var *vp;
    12150     char **ep;
    12151     int mask;
    12152 
    12153     STARTSTACKSTR(ep);
    12154     vpp = vartab;
    12155     mask = on | off;
    12156     do {
    12157         for (vp = *vpp ; vp ; vp = vp->next)
    12158             if ((vp->flags & mask) == on) {
    12159                 if (ep == stackstrend())
    12160                     ep = growstackstr();
    12161                 *ep++ = (char *) vp->text;
    12162             }
    12163     } while (++vpp < vartab + VTABSIZE);
    12164     if (ep == stackstrend())
    12165         ep = growstackstr();
    12166     if (end)
    12167         *end = ep;
    12168     *ep++ = NULL;
    12169     return grabstackstr(ep);
    12170 }
    12171 
    12172 
    12173 /*
    12174  * POSIX requires that 'set' (but not export or readonly) output the
    12175  * variables in lexicographic order - by the locale's collating order (sigh).
    12176  * Maybe we could keep them in an ordered balanced binary tree
    12177  * instead of hashed lists.
    12178  * For now just roll 'em through qsort for printing...
    12179  */
    12180 
    12181 static int
    12182 showvars(const char *sep_prefix, int on, int off)
    12183 {
    12184     const char *sep;
    12185     char **ep, **epend;
    12186 
    12187     ep = listvars(on, off, &epend);
    12188     qsort(ep, epend - ep, sizeof(char *), vpcmp);
    12189 
    12190     sep = *sep_prefix ? spcstr : sep_prefix;
    12191 
    12192     for (; ep < epend; ep++) {
    12193         const char *p;
    12194         const char *q;
    12195 
    12196         p = strchrnul(*ep, '=');
    12197         q = nullstr;
    12198         if (*p)
    12199             q = single_quote(++p);
    12200 
    12201         out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
    12202     }
    12203 
    12204     return 0;
    12205 }
    12206 
    12207 
     11300#endif /* FEATURE_SH_EXTRA_QUIET */
    1220811301
    1220911302/*
    1221011303 * The export and readonly commands.
    1221111304 */
    12212 
    1221311305static int
    1221411306exportcmd(int argc, char **argv)
     
    1221911311    char **aptr;
    1222011312    int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
    12221     int notp;
    12222 
    12223     notp = nextopt("p") - 'p';
    12224     if (notp && ((name = *(aptr = argptr)))) {
    12225         do {
    12226             if ((p = strchr(name, '=')) != NULL) {
    12227                 p++;
    12228             } else {
    12229                 if ((vp = *findvar(hashvar(name), name))) {
    12230                     vp->flags |= flag;
    12231                     continue;
     11313
     11314    if (nextopt("p") != 'p') {
     11315        aptr = argptr;
     11316        name = *aptr;
     11317        if (name) {
     11318            do {
     11319                p = strchr(name, '=');
     11320                if (p != NULL) {
     11321                    p++;
     11322                } else {
     11323                    vp = *findvar(hashvar(name), name);
     11324                    if (vp) {
     11325                        vp->flags |= flag;
     11326                        continue;
     11327                    }
    1223211328                }
    12233             }
    12234             setvar(name, p, flag);
    12235         } while ((name = *++aptr) != NULL);
    12236     } else {
    12237         showvars(argv[0], flag, 0);
    12238     }
     11329                setvar(name, p, flag);
     11330            } while ((name = *++aptr) != NULL);
     11331            return 0;
     11332        }
     11333    }
     11334    showvars(argv[0], flag, 0);
    1223911335    return 0;
    1224011336}
    1224111337
    12242 
    12243 /*
    12244  * Make a variable a local variable.  When a variable is made local, it's
    12245  * value and flags are saved in a localvar structure.  The saved values
    12246  * will be restored when the shell function returns.  We handle the name
    12247  * "-" as a special case.
    12248  */
    12249 
    12250 static inline void
    12251 mklocal(char *name)
    12252 {
    12253     struct localvar *lvp;
    12254     struct var **vpp;
    12255     struct var *vp;
    12256 
    12257     INTOFF;
    12258     lvp = ckmalloc(sizeof (struct localvar));
    12259     if (name[0] == '-' && name[1] == '\0') {
    12260         char *p;
    12261         p = ckmalloc(sizeof(optlist));
    12262         lvp->text = memcpy(p, optlist, sizeof(optlist));
    12263         vp = NULL;
    12264     } else {
    12265         char *eq;
    12266 
    12267         vpp = hashvar(name);
    12268         vp = *findvar(vpp, name);
    12269         eq = strchr(name, '=');
    12270         if (vp == NULL) {
    12271             if (eq)
    12272                 setvareq(name, VSTRFIXED);
    12273             else
    12274                 setvar(name, NULL, VSTRFIXED);
    12275             vp = *vpp;      /* the new variable */
    12276             lvp->flags = VUNSET;
    12277         } else {
    12278             lvp->text = vp->text;
    12279             lvp->flags = vp->flags;
    12280             vp->flags |= VSTRFIXED|VTEXTFIXED;
    12281             if (eq)
    12282                 setvareq(name, 0);
    12283         }
    12284     }
    12285     lvp->vp = vp;
    12286     lvp->next = localvars;
    12287     localvars = lvp;
    12288     INTON;
    12289 }
    12290 
    12291 /*
    12292  * The "local" command.
    12293  */
    12294 
    12295 static int
    12296 localcmd(int argc, char **argv)
    12297 {
    12298     char *name;
    12299 
    12300     argv = argptr;
    12301     while ((name = *argv++) != NULL) {
    12302         mklocal(name);
    12303     }
    12304     return 0;
    12305 }
    12306 
    12307 
    12308 /*
    12309  * Called after a function returns.
    12310  * Interrupts must be off.
    12311  */
    12312 
    12313 static void
    12314 poplocalvars(void)
    12315 {
    12316     struct localvar *lvp;
    12317     struct var *vp;
    12318 
    12319     while ((lvp = localvars) != NULL) {
    12320         localvars = lvp->next;
    12321         vp = lvp->vp;
    12322         TRACE(("poplocalvar %s", vp ? vp->text : "-"));
    12323         if (vp == NULL) {       /* $- saved */
    12324             memcpy(optlist, lvp->text, sizeof(optlist));
    12325             ckfree(lvp->text);
    12326             optschanged();
    12327         } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
    12328             unsetvar(vp->text);
    12329         } else {
    12330             if (vp->func)
    12331                 (*vp->func)(strchrnul(lvp->text, '=') + 1);
    12332             if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
    12333                 ckfree(vp->text);
    12334             vp->flags = lvp->flags;
    12335             vp->text = lvp->text;
    12336         }
    12337         ckfree(lvp);
    12338     }
    12339 }
    12340 
     11338/*
     11339 * Delete a function if it exists.
     11340 */
     11341static void
     11342unsetfunc(const char *name)
     11343{
     11344    struct tblentry *cmdp;
     11345
     11346    cmdp = cmdlookup(name, 0);
     11347    if (cmdp!= NULL && cmdp->cmdtype == CMDFUNCTION)
     11348        delete_cmd_entry();
     11349}
    1234111350
    1234211351/*
     
    1234511354 * with the same name.
    1234611355 */
    12347 
    12348 int
     11356static int
    1234911357unsetcmd(int argc, char **argv)
    1235011358{
     
    1235811366    }
    1235911367
    12360     for (ap = argptr; *ap ; ap++) {
     11368    for (ap = argptr; *ap; ap++) {
    1236111369        if (flag != 'f') {
    1236211370            i = unsetvar(*ap);
     
    1237211380
    1237311381
    12374 /*
    12375  * Unset the specified variable.
    12376  */
    12377 
    12378 int
    12379 unsetvar(const char *s)
    12380 {
    12381     struct var **vpp;
    12382     struct var *vp;
    12383     int retval;
    12384 
    12385     vpp = findvar(hashvar(s), s);
    12386     vp = *vpp;
    12387     retval = 2;
    12388     if (vp) {
    12389         int flags = vp->flags;
    12390 
    12391         retval = 1;
    12392         if (flags & VREADONLY)
    12393             goto out;
    12394 #ifdef DYNAMIC_VAR
    12395         vp->flags &= ~VDYNAMIC;
    12396 #endif
    12397         if (flags & VUNSET)
    12398             goto ok;
    12399         if ((flags & VSTRFIXED) == 0) {
    12400             INTOFF;
    12401             if ((flags & (VTEXTFIXED|VSTACK)) == 0)
    12402                 ckfree(vp->text);
    12403             *vpp = vp->next;
    12404             ckfree(vp);
    12405             INTON;
    12406         } else {
    12407             setvar(s, 0, 0);
    12408             vp->flags &= ~VEXPORT;
    12409         }
    12410 ok:
    12411         retval = 0;
    12412     }
    12413 
    12414 out:
    12415     return retval;
    12416 }
    12417 
    12418 
    12419 
    12420 /*
    12421  * Find the appropriate entry in the hash table from the name.
    12422  */
    12423 
    12424 static struct var **
    12425 hashvar(const char *p)
    12426 {
    12427     unsigned int hashval;
    12428 
    12429     hashval = ((unsigned char) *p) << 4;
    12430     while (*p && *p != '=')
    12431         hashval += (unsigned char) *p++;
    12432     return &vartab[hashval % VTABSIZE];
    12433 }
    12434 
    12435 
    12436 
    12437 /*
    12438  * Compares two strings up to the first = or '\0'.  The first
    12439  * string must be terminated by '='; the second may be terminated by
    12440  * either '=' or '\0'.
    12441  */
    12442 
    12443 int
    12444 varcmp(const char *p, const char *q)
    12445 {
    12446     int c, d;
    12447 
    12448     while ((c = *p) == (d = *q)) {
    12449         if (!c || c == '=')
    12450             goto out;
    12451         p++;
    12452         q++;
    12453     }
    12454     if (c == '=')
    12455         c = 0;
    12456     if (d == '=')
    12457         d = 0;
    12458 out:
    12459     return c - d;
    12460 }
    12461 
    12462 static int
    12463 vpcmp(const void *a, const void *b)
    12464 {
    12465     return varcmp(*(const char **)a, *(const char **)b);
    12466 }
    12467 
    12468 static struct var **
    12469 findvar(struct var **vpp, const char *name)
    12470 {
    12471     for (; *vpp; vpp = &(*vpp)->next) {
    12472         if (varequal((*vpp)->text, name)) {
    12473             break;
    12474         }
    12475     }
    12476     return vpp;
    12477 }
    1247811382/*      setmode.c      */
    1247911383
    1248011384#include <sys/times.h>
    1248111385
    12482 static const unsigned char timescmd_str[] = {
     11386static const unsigned char timescmd_str[] ALIGN1 = {
    1248311387    ' ',  offsetof(struct tms, tms_utime),
    1248411388    '\n', offsetof(struct tms, tms_stime),
     
    1248811392};
    1248911393
    12490 static int timescmd(int ac, char **av)
    12491 {
    12492     long int clk_tck, s, t;
     11394static int
     11395timescmd(int ac, char **av)
     11396{
     11397    long clk_tck, s, t;
    1249311398    const unsigned char *p;
    1249411399    struct tms buf;
     
    1251011415}
    1251111416
    12512 #ifdef CONFIG_ASH_MATH_SUPPORT
     11417#if ENABLE_ASH_MATH_SUPPORT
    1251311418static arith_t
    1251411419dash_arith(const char *s)
     
    1251711422    int errcode = 0;
    1251811423
    12519     INTOFF;
     11424    INT_OFF;
    1252011425    result = arith(s, &errcode);
    1252111426    if (errcode < 0) {
    1252211427        if (errcode == -3)
    12523             sh_error("exponent less than 0");
    12524         else if (errcode == -2)
    12525             sh_error("divide by zero");
    12526         else if (errcode == -5)
    12527             sh_error("expression recursion loop detected");
    12528         else
    12529             synerror(s);
    12530     }
    12531     INTON;
    12532 
    12533     return (result);
    12534 }
    12535 
     11428            ash_msg_and_raise_error("exponent less than 0");
     11429        if (errcode == -2)
     11430            ash_msg_and_raise_error("divide by zero");
     11431        if (errcode == -5)
     11432            ash_msg_and_raise_error("expression recursion loop detected");
     11433        raise_error_syntax(s);
     11434    }
     11435    INT_ON;
     11436
     11437    return result;
     11438}
    1253611439
    1253711440/*
     
    1254111444 *  Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
    1254211445 */
    12543 
    1254411446static int
    1254511447letcmd(int argc, char **argv)
    1254611448{
    1254711449    char **ap;
    12548     arith_t i;
     11450    arith_t i = 0;
    1254911451
    1255011452    ap = argv + 1;
    12551     if(!*ap)
    12552         sh_error("expression expected");
     11453    if (!*ap)
     11454        ash_msg_and_raise_error("expression expected");
    1255311455    for (ap = argv + 1; *ap; ap++) {
    1255411456        i = dash_arith(*ap);
    1255511457    }
    1255611458
    12557     return (!i);
    12558 }
    12559 #endif /* CONFIG_ASH_MATH_SUPPORT */
    12560 
    12561 /*      miscbltin.c  */
    12562 
    12563 /*
     11459    return !i;
     11460}
     11461#endif /* ASH_MATH_SUPPORT */
     11462
     11463
     11464/* ============ miscbltin.c
     11465 *
    1256411466 * Miscellaneous builtins.
    1256511467 */
     
    1256711469#undef rflag
    1256811470
    12569 #ifdef __GLIBC__
    12570 #if __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
     11471#if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
    1257111472typedef enum __rlimit_resource rlim_t;
    1257211473#endif
    12573 #endif
    12574 
    1257511474
    1257611475/*
     
    1258011479 * This uses unbuffered input, which may be avoidable in some cases.
    1258111480 */
    12582 
    1258311481static int
    1258411482readcmd(int argc, char **argv)
     
    1259411492    int status;
    1259511493    int i;
    12596 #if defined(CONFIG_ASH_READ_NCHARS)
     11494#if ENABLE_ASH_READ_NCHARS
    1259711495    int nch_flag = 0;
    1259811496    int nchars = 0;
     
    1260011498    struct termios tty, old_tty;
    1260111499#endif
    12602 #if defined(CONFIG_ASH_READ_TIMEOUT)
     11500#if ENABLE_ASH_READ_TIMEOUT
    1260311501    fd_set set;
    1260411502    struct timeval ts;
     
    1260911507    rflag = 0;
    1261011508    prompt = NULL;
    12611 #if defined(CONFIG_ASH_READ_NCHARS) && defined(CONFIG_ASH_READ_TIMEOUT)
     11509#if ENABLE_ASH_READ_NCHARS && ENABLE_ASH_READ_TIMEOUT
    1261211510    while ((i = nextopt("p:rt:n:s")) != '\0')
    12613 #elif defined(CONFIG_ASH_READ_NCHARS)
     11511#elif ENABLE_ASH_READ_NCHARS
    1261411512    while ((i = nextopt("p:rn:s")) != '\0')
    12615 #elif defined(CONFIG_ASH_READ_TIMEOUT)
     11513#elif ENABLE_ASH_READ_TIMEOUT
    1261611514    while ((i = nextopt("p:rt:")) != '\0')
    1261711515#else
     
    1261911517#endif
    1262011518    {
    12621         switch(i) {
     11519        switch (i) {
    1262211520        case 'p':
    1262311521            prompt = optionarg;
    1262411522            break;
    12625 #if defined(CONFIG_ASH_READ_NCHARS)
     11523#if ENABLE_ASH_READ_NCHARS
    1262611524        case 'n':
    1262711525            nchars = strtol(optionarg, &p, 10);
    1262811526            if (*p)
    12629                 sh_error("invalid count");
     11527                ash_msg_and_raise_error("invalid count");
    1263011528            nch_flag = (nchars > 0);
    1263111529            break;
     
    1263411532            break;
    1263511533#endif
    12636 #if defined(CONFIG_ASH_READ_TIMEOUT)
     11534#if ENABLE_ASH_READ_TIMEOUT
    1263711535        case 't':
    1263811536            ts.tv_sec = strtol(optionarg, &p, 10);
     
    1264411542                    ts.tv_usec = strtol(p, &p2, 10);
    1264511543                    if (*p2)
    12646                         sh_error("invalid timeout");
     11544                        ash_msg_and_raise_error("invalid timeout");
    1264711545                    scale = p2 - p;
    1264811546                    /* normalize to usec */
    1264911547                    if (scale > 6)
    12650                         sh_error("invalid timeout");
     11548                        ash_msg_and_raise_error("invalid timeout");
    1265111549                    while (scale++ < 6)
    1265211550                        ts.tv_usec *= 10;
    1265311551                }
    1265411552            } else if (*p) {
    12655                 sh_error("invalid timeout");
     11553                ash_msg_and_raise_error("invalid timeout");
    1265611554            }
    1265711555            if ( ! ts.tv_sec && ! ts.tv_usec)
    12658                 sh_error("invalid timeout");
     11556                ash_msg_and_raise_error("invalid timeout");
    1265911557            break;
    1266011558#endif
     
    1266911567        out2str(prompt);
    1267011568    }
    12671     if (*(ap = argptr) == NULL)
    12672         sh_error("arg count");
    12673     if ((ifs = bltinlookup("IFS")) == NULL)
     11569    ap = argptr;
     11570    if (*ap == NULL)
     11571        ash_msg_and_raise_error("arg count");
     11572    ifs = bltinlookup("IFS");
     11573    if (ifs == NULL)
    1267411574        ifs = defifs;
    12675 #if defined(CONFIG_ASH_READ_NCHARS)
     11575#if ENABLE_ASH_READ_NCHARS
    1267611576    if (nch_flag || silent) {
    1267711577        tcgetattr(0, &tty);
    1267811578        old_tty = tty;
    1267911579        if (nch_flag) {
    12680             tty.c_lflag &= ~ICANON;
    12681             tty.c_cc[VMIN] = nchars;
     11580            tty.c_lflag &= ~ICANON;
     11581            tty.c_cc[VMIN] = nchars;
    1268211582        }
    1268311583        if (silent) {
    12684             tty.c_lflag &= ~(ECHO|ECHOK|ECHONL);
     11584            tty.c_lflag &= ~(ECHO|ECHOK|ECHONL);
    1268511585
    1268611586        }
     
    1268811588    }
    1268911589#endif
    12690 #if defined(CONFIG_ASH_READ_TIMEOUT)
     11590#if ENABLE_ASH_READ_TIMEOUT
    1269111591    if (ts.tv_sec || ts.tv_usec) {
    12692         FD_ZERO (&set);
    12693         FD_SET (0, &set);
    12694 
    12695         i = select (FD_SETSIZE, &set, NULL, NULL, &ts);
     11592        FD_ZERO(&set);
     11593        FD_SET(0, &set);
     11594
     11595        i = select(FD_SETSIZE, &set, NULL, NULL, &ts);
    1269611596        if (!i) {
    12697 #if defined(CONFIG_ASH_READ_NCHARS)
     11597#if ENABLE_ASH_READ_NCHARS
    1269811598            if (nch_flag)
    1269911599                tcsetattr(0, TCSANOW, &old_tty);
     
    1270711607    backslash = 0;
    1270811608    STARTSTACKSTR(p);
    12709 #if defined(CONFIG_ASH_READ_NCHARS)
     11609#if ENABLE_ASH_READ_NCHARS
    1271011610    while (!nch_flag || nchars--)
    1271111611#else
     
    1274211642            STARTSTACKSTR(p);
    1274311643        } else {
    12744 put:
     11644 put:
    1274511645            STPUTC(c, p);
    1274611646        }
    1274711647    }
    12748 #if defined(CONFIG_ASH_READ_NCHARS)
     11648#if ENABLE_ASH_READ_NCHARS
    1274911649    if (nch_flag || silent)
    1275011650        tcsetattr(0, TCSANOW, &old_tty);
     
    1276111661}
    1276211662
    12763 
    12764 static int umaskcmd(int argc, char **argv)
    12765 {
    12766     static const char permuser[3] = "ugo";
    12767     static const char permmode[3] = "rwx";
    12768     static const short int permmask[] = {
     11663static int
     11664umaskcmd(int argc, char **argv)
     11665{
     11666    static const char permuser[3] ALIGN1 = "ugo";
     11667    static const char permmode[3] ALIGN1 = "rwx";
     11668    static const short permmask[] ALIGN2 = {
    1276911669        S_IRUSR, S_IWUSR, S_IXUSR,
    1277011670        S_IRGRP, S_IWGRP, S_IXGRP,
     
    1278111681    }
    1278211682
    12783     INTOFF;
     11683    INT_OFF;
    1278411684    mask = umask(0);
    1278511685    umask(mask);
    12786     INTON;
    12787 
    12788     if ((ap = *argptr) == NULL) {
     11686    INT_ON;
     11687
     11688    ap = *argptr;
     11689    if (ap == NULL) {
    1278911690        if (symbolic_mode) {
    1279011691            char buf[18];
     
    1280911710        }
    1281011711    } else {
    12811         if (is_digit((unsigned char) *ap)) {
     11712        if (isdigit((unsigned char) *ap)) {
    1281211713            mask = 0;
    1281311714            do {
    1281411715                if (*ap >= '8' || *ap < '0')
    12815                     sh_error(illnum, argv[1]);
     11716                    ash_msg_and_raise_error(illnum, argv[1]);
    1281611717                mask = (mask << 3) + (*ap - '0');
    1281711718            } while (*++ap != '\0');
     
    1282011721            mask = ~mask & 0777;
    1282111722            if (!bb_parse_mode(ap, &mask)) {
    12822                 sh_error("Illegal mode: %s", ap);
     11723                ash_msg_and_raise_error("illegal mode: %s", ap);
    1282311724            }
    1282411725            umask(~mask & 0777);
     
    1287911780    { "locks",                      RLIMIT_LOCKS,      1, 'w' },
    1288011781#endif
    12881     { (char *) 0,                   0,                 0,  '\0' }
     11782    { NULL,                         0,                 0,  '\0' }
    1288211783};
    1288311784
    1288411785enum limtype { SOFT = 0x1, HARD = 0x2 };
    1288511786
    12886 static void printlim(enum limtype how, const struct rlimit *limit,
     11787static void
     11788printlim(enum limtype how, const struct rlimit *limit,
    1288711789            const struct limits *l)
    1288811790{
     
    1290111803}
    1290211804
    12903 int
     11805static int
    1290411806ulimitcmd(int argc, char **argv)
    1290511807{
    12906     int     c;
     11808    int c;
    1290711809    rlim_t val = 0;
    1290811810    enum limtype how = SOFT | HARD;
    12909     const struct limits     *l;
    12910     int             set, all = 0;
    12911     int             optc, what;
    12912     struct rlimit   limit;
     11811    const struct limits *l;
     11812    int set, all = 0;
     11813    int optc, what;
     11814    struct rlimit limit;
    1291311815
    1291411816    what = 'f';
     
    1294711849                "w"
    1294811850#endif
    12949                         )) != '\0')
     11851                    )) != '\0')
    1295011852        switch (optc) {
    1295111853        case 'H':
     
    1297011872
    1297111873        if (all || argptr[1])
    12972             sh_error("too many arguments");
     11874            ash_msg_and_raise_error("too many arguments");
    1297311875        if (strncmp(p, "unlimited\n", 9) == 0)
    1297411876            val = RLIM_INFINITY;
     
    1297611878            val = (rlim_t) 0;
    1297711879
    12978             while ((c = *p++) >= '0' && c <= '9')
    12979             {
     11880            while ((c = *p++) >= '0' && c <= '9') {
    1298011881                val = (val * 10) + (long)(c - '0');
    1298111882                if (val < (rlim_t) 0)
     
    1298311884            }
    1298411885            if (c)
    12985                 sh_error("bad number");
     11886                ash_msg_and_raise_error("bad number");
    1298611887            val *= l->factor;
    1298711888        }
     
    1300311904            limit.rlim_cur = val;
    1300411905        if (setrlimit(l->cmd, &limit) < 0)
    13005             sh_error("error setting limit (%m)");
     11906            ash_msg_and_raise_error("error setting limit (%m)");
    1300611907    } else {
    1300711908        printlim(how, &limit, l);
     
    1301111912
    1301211913
    13013 #ifdef CONFIG_ASH_MATH_SUPPORT
     11914/* ============ Math support */
     11915
     11916#if ENABLE_ASH_MATH_SUPPORT
    1301411917
    1301511918/* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
     
    1310712010 */
    1310812011
    13109 
    1311012012#define arith_isspace(arithval) \
    1311112013    (arithval == ' ' || arithval == '\n' || arithval == '\t')
    13112 
    1311312014
    1311412015typedef unsigned char operator;
     
    1314112042
    1314212043/* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
    13143 #define convert_prec_is_assing(prec) do { if(prec == 3) prec = 2; } while(0)
     12044#define convert_prec_is_assing(prec) do { if (prec == 3) prec = 2; } while (0)
    1314412045
    1314512046/* conditional is right associativity too */
     
    1320312104#define NUMPTR (*numstackptr)
    1320412105
    13205 static inline int tok_have_assign(operator op)
     12106static int
     12107tok_have_assign(operator op)
    1320612108{
    1320712109    operator prec = PREC(op);
     
    1321212114}
    1321312115
    13214 static inline int is_right_associativity(operator prec)
    13215 {
    13216     return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) ||
    13217         prec == PREC(TOK_CONDITIONAL));
    13218 }
    13219 
     12116static int
     12117is_right_associativity(operator prec)
     12118{
     12119    return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT)
     12120            || prec == PREC(TOK_CONDITIONAL));
     12121}
    1322012122
    1322112123typedef struct ARITCH_VAR_NUM {
     
    1322712129} v_n_t;
    1322812130
    13229 
    1323012131typedef struct CHK_VAR_RECURSIVE_LOOPED {
    1323112132    const char *var;
     
    1323512136static chk_var_recursive_looped_t *prev_chk_var_recursive;
    1323612137
    13237 
    13238 static int arith_lookup_val(v_n_t *t)
    13239 {
    13240     if(t->var) {
    13241     const char * p = lookupvar(t->var);
    13242 
    13243     if(p) {
    13244         int errcode;
    13245 
    13246         /* recursive try as expression */
    13247         chk_var_recursive_looped_t *cur;
    13248         chk_var_recursive_looped_t cur_save;
    13249 
    13250         for(cur = prev_chk_var_recursive; cur; cur = cur->next) {
    13251         if(strcmp(cur->var, t->var) == 0) {
    13252             /* expression recursion loop detected */
    13253             return -5;
    13254         }
    13255         }
    13256         /* save current lookuped var name */
    13257         cur = prev_chk_var_recursive;
    13258         cur_save.var = t->var;
    13259         cur_save.next = cur;
    13260         prev_chk_var_recursive = &cur_save;
    13261 
    13262         t->val = arith (p, &errcode);
    13263         /* restore previous ptr after recursiving */
    13264         prev_chk_var_recursive = cur;
    13265         return errcode;
    13266     } else {
    13267         /* allow undefined var as 0 */
    13268         t->val = 0;
    13269     }
    13270     }
    13271     return 0;
     12138static int
     12139arith_lookup_val(v_n_t *t)
     12140{
     12141    if (t->var) {
     12142        const char * p = lookupvar(t->var);
     12143
     12144        if (p) {
     12145            int errcode;
     12146
     12147            /* recursive try as expression */
     12148            chk_var_recursive_looped_t *cur;
     12149            chk_var_recursive_looped_t cur_save;
     12150
     12151            for (cur = prev_chk_var_recursive; cur; cur = cur->next) {
     12152                if (strcmp(cur->var, t->var) == 0) {
     12153                    /* expression recursion loop detected */
     12154                    return -5;
     12155                }
     12156            }
     12157            /* save current lookuped var name */
     12158            cur = prev_chk_var_recursive;
     12159            cur_save.var = t->var;
     12160            cur_save.next = cur;
     12161            prev_chk_var_recursive = &cur_save;
     12162
     12163            t->val = arith (p, &errcode);
     12164            /* restore previous ptr after recursiving */
     12165            prev_chk_var_recursive = cur;
     12166            return errcode;
     12167        }
     12168        /* allow undefined var as 0 */
     12169        t->val = 0;
     12170    }
     12171    return 0;
    1327212172}
    1327312173
     
    1327512175 * stack. For a unary operator it will only change the top element, but a
    1327612176 * binary operator will pop two arguments and push a result */
    13277 static inline int
     12177static int
    1327812178arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
    1327912179{
     
    1328212182    int ret_arith_lookup_val;
    1328312183
    13284     if (NUMPTR == numstack) goto err; /* There is no operator that can work
    13285                                          without arguments */
     12184    /* There is no operator that can work without arguments */
     12185    if (NUMPTR == numstack) goto err;
    1328612186    numptr_m1 = NUMPTR - 1;
    1328712187
    1328812188    /* check operand is var with noninteger value */
    1328912189    ret_arith_lookup_val = arith_lookup_val(numptr_m1);
    13290     if(ret_arith_lookup_val)
     12190    if (ret_arith_lookup_val)
    1329112191        return ret_arith_lookup_val;
    1329212192
     
    1330512205        /* Binary operators */
    1330612206
    13307         /* check and binary operators need two arguments */
    13308         if (numptr_m1 == numstack) goto err;
    13309 
    13310         /* ... and they pop one */
    13311         --NUMPTR;
    13312         numptr_val = rez;
    13313         if (op == TOK_CONDITIONAL) {
    13314         if(! numptr_m1->contidional_second_val_initialized) {
    13315             /* protect $((expr1 ? expr2)) without ": expr" */
    13316             goto err;
    13317         }
    13318         rez = numptr_m1->contidional_second_val;
    13319         } else if(numptr_m1->contidional_second_val_initialized) {
    13320             /* protect $((expr1 : expr2)) without "expr ? " */
    13321             goto err;
    13322         }
    13323         numptr_m1 = NUMPTR - 1;
    13324         if(op != TOK_ASSIGN) {
    13325         /* check operand is var with noninteger value for not '=' */
    13326         ret_arith_lookup_val = arith_lookup_val(numptr_m1);
    13327         if(ret_arith_lookup_val)
    13328             return ret_arith_lookup_val;
    13329         }
    13330         if (op == TOK_CONDITIONAL) {
    13331             numptr_m1->contidional_second_val = rez;
    13332         }
    13333         rez = numptr_m1->val;
    13334         if (op == TOK_BOR || op == TOK_OR_ASSIGN)
     12207        /* check and binary operators need two arguments */
     12208        if (numptr_m1 == numstack) goto err;
     12209
     12210        /* ... and they pop one */
     12211        --NUMPTR;
     12212        numptr_val = rez;
     12213        if (op == TOK_CONDITIONAL) {
     12214            if (! numptr_m1->contidional_second_val_initialized) {
     12215                /* protect $((expr1 ? expr2)) without ": expr" */
     12216                goto err;
     12217            }
     12218            rez = numptr_m1->contidional_second_val;
     12219        } else if (numptr_m1->contidional_second_val_initialized) {
     12220            /* protect $((expr1 : expr2)) without "expr ? " */
     12221            goto err;
     12222        }
     12223        numptr_m1 = NUMPTR - 1;
     12224        if (op != TOK_ASSIGN) {
     12225            /* check operand is var with noninteger value for not '=' */
     12226            ret_arith_lookup_val = arith_lookup_val(numptr_m1);
     12227            if (ret_arith_lookup_val)
     12228                return ret_arith_lookup_val;
     12229        }
     12230        if (op == TOK_CONDITIONAL) {
     12231            numptr_m1->contidional_second_val = rez;
     12232        }
     12233        rez = numptr_m1->val;
     12234        if (op == TOK_BOR || op == TOK_OR_ASSIGN)
    1333512235            rez |= numptr_val;
    13336         else if (op == TOK_OR)
     12236        else if (op == TOK_OR)
    1333712237            rez = numptr_val || rez;
    13338         else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
     12238        else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
    1333912239            rez &= numptr_val;
    13340         else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
     12240        else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
    1334112241            rez ^= numptr_val;
    13342         else if (op == TOK_AND)
     12242        else if (op == TOK_AND)
    1334312243            rez = rez && numptr_val;
    13344         else if (op == TOK_EQ)
     12244        else if (op == TOK_EQ)
    1334512245            rez = (rez == numptr_val);
    13346         else if (op == TOK_NE)
     12246        else if (op == TOK_NE)
    1334712247            rez = (rez != numptr_val);
    13348         else if (op == TOK_GE)
     12248        else if (op == TOK_GE)
    1334912249            rez = (rez >= numptr_val);
    13350         else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
     12250        else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
    1335112251            rez >>= numptr_val;
    13352         else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
     12252        else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
    1335312253            rez <<= numptr_val;
    13354         else if (op == TOK_GT)
     12254        else if (op == TOK_GT)
    1335512255            rez = (rez > numptr_val);
    13356         else if (op == TOK_LT)
     12256        else if (op == TOK_LT)
    1335712257            rez = (rez < numptr_val);
    13358         else if (op == TOK_LE)
     12258        else if (op == TOK_LE)
    1335912259            rez = (rez <= numptr_val);
    13360         else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
     12260        else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
    1336112261            rez *= numptr_val;
    13362         else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
     12262        else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
    1336312263            rez += numptr_val;
    13364         else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
     12264        else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
    1336512265            rez -= numptr_val;
    13366         else if (op == TOK_ASSIGN || op == TOK_COMMA)
     12266        else if (op == TOK_ASSIGN || op == TOK_COMMA)
    1336712267            rez = numptr_val;
    13368         else if (op == TOK_CONDITIONAL_SEP) {
     12268        else if (op == TOK_CONDITIONAL_SEP) {
    1336912269            if (numptr_m1 == numstack) {
    13370                 /* protect $((expr : expr)) without "expr ? " */
    13371                 goto err;
     12270                /* protect $((expr : expr)) without "expr ? " */
     12271                goto err;
    1337212272            }
    1337312273            numptr_m1->contidional_second_val_initialized = op;
    1337412274            numptr_m1->contidional_second_val = numptr_val;
    13375         }
    13376         else if (op == TOK_CONDITIONAL) {
     12275        } else if (op == TOK_CONDITIONAL) {
    1337712276            rez = rez ?
    13378                   numptr_val : numptr_m1->contidional_second_val;
    13379         }
    13380         else if(op == TOK_EXPONENT) {
    13381             if(numptr_val < 0)
     12277                numptr_val : numptr_m1->contidional_second_val;
     12278        } else if (op == TOK_EXPONENT) {
     12279            if (numptr_val < 0)
    1338212280                return -3;      /* exponent less than 0 */
    1338312281            else {
    1338412282                arith_t c = 1;
    1338512283
    13386                 if(numptr_val)
    13387                     while(numptr_val--)
     12284                if (numptr_val)
     12285                    while (numptr_val--)
    1338812286                        c *= rez;
    1338912287                rez = c;
    1339012288            }
    13391         }
    13392         else if(numptr_val==0)          /* zero divisor check */
     12289        } else if (numptr_val==0)          /* zero divisor check */
    1339312290            return -2;
    13394         else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
     12291        else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
    1339512292            rez /= numptr_val;
    13396         else if (op == TOK_REM || op == TOK_REM_ASSIGN)
     12293        else if (op == TOK_REM || op == TOK_REM_ASSIGN)
    1339712294            rez %= numptr_val;
    1339812295    }
    13399     if(tok_have_assign(op)) {
    13400         char buf[32];
    13401 
    13402         if(numptr_m1->var == NULL) {
     12296    if (tok_have_assign(op)) {
     12297        char buf[sizeof(arith_t_type)*3 + 2];
     12298
     12299        if (numptr_m1->var == NULL) {
    1340312300            /* Hmm, 1=2 ? */
    1340412301            goto err;
    1340512302        }
    1340612303        /* save to shell variable */
    13407 #ifdef CONFIG_ASH_MATH_SUPPORT_64
    13408         snprintf(buf, sizeof(buf), "%lld", arith_t_type rez);
     12304#if ENABLE_ASH_MATH_SUPPORT_64
     12305        snprintf(buf, sizeof(buf), "%lld", (arith_t_type) rez);
    1340912306#else
    13410         snprintf(buf, sizeof(buf), "%ld", arith_t_type rez);
     12307        snprintf(buf, sizeof(buf), "%ld", (arith_t_type) rez);
    1341112308#endif
    1341212309        setvar(numptr_m1->var, buf, 0);
    1341312310        /* after saving, make previous value for v++ or v-- */
    13414         if(op == TOK_POST_INC)
     12311        if (op == TOK_POST_INC)
    1341512312            rez--;
    13416         else if(op == TOK_POST_DEC)
     12313        else if (op == TOK_POST_DEC)
    1341712314            rez++;
    1341812315    }
     
    1342112318    numptr_m1->var = NULL;
    1342212319    return 0;
    13423 err: return(-1);
    13424 }
    13425 
    13426 /* longest must first */
    13427 static const char op_tokens[] = {
     12320 err:
     12321    return -1;
     12322}
     12323
     12324/* longest must be first */
     12325static const char op_tokens[] ALIGN1 = {
    1342812326    '<','<','=',0, TOK_LSHIFT_ASSIGN,
    1342912327    '>','>','=',0, TOK_RSHIFT_ASSIGN,
     
    1347112369#define endexpression &op_tokens[sizeof(op_tokens)-7]
    1347212370
    13473 
    13474 static arith_t arith (const char *expr, int *perrcode)
    13475 {
    13476     register char arithval; /* Current character under analysis */
    13477     operator lasttok, op;
    13478     operator prec;
    13479 
    13480     const char *p = endexpression;
    13481     int errcode;
    13482 
    13483     size_t datasizes = strlen(expr) + 2;
    13484 
    13485     /* Stack of integers */
    13486     /* The proof that there can be no more than strlen(startbuf)/2+1 integers
    13487      * in any given correct or incorrect expression is left as an exercise to
    13488      * the reader. */
    13489     v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
    13490         *numstackptr = numstack;
    13491     /* Stack of operator tokens */
    13492     operator *stack = alloca((datasizes) * sizeof(operator)),
    13493         *stackptr = stack;
    13494 
    13495     *stackptr++ = lasttok = TOK_LPAREN;     /* start off with a left paren */
    13496     *perrcode = errcode = 0;
    13497 
    13498     while(1) {
    13499     if ((arithval = *expr) == 0) {
    13500         if (p == endexpression) {
    13501             /* Null expression. */
    13502             return 0;
    13503         }
    13504 
    13505         /* This is only reached after all tokens have been extracted from the
    13506          * input stream. If there are still tokens on the operator stack, they
    13507          * are to be applied in order. At the end, there should be a final
    13508          * result on the integer stack */
    13509 
    13510         if (expr != endexpression + 1) {
    13511             /* If we haven't done so already, */
    13512             /* append a closing right paren */
    13513             expr = endexpression;
    13514             /* and let the loop process it. */
    13515             continue;
    13516         }
    13517         /* At this point, we're done with the expression. */
    13518         if (numstackptr != numstack+1) {
    13519             /* ... but if there isn't, it's bad */
    13520           err:
    13521             return (*perrcode = -1);
    13522         }
    13523         if(numstack->var) {
    13524             /* expression is $((var)) only, lookup now */
    13525             errcode = arith_lookup_val(numstack);
    13526         }
    13527     ret:
    13528         *perrcode = errcode;
    13529         return numstack->val;
    13530     } else {
     12371static arith_t
     12372arith(const char *expr, int *perrcode)
     12373{
     12374    char arithval; /* Current character under analysis */
     12375    operator lasttok, op;
     12376    operator prec;
     12377
     12378    const char *p = endexpression;
     12379    int errcode;
     12380
     12381    size_t datasizes = strlen(expr) + 2;
     12382
     12383    /* Stack of integers */
     12384    /* The proof that there can be no more than strlen(startbuf)/2+1 integers
     12385     * in any given correct or incorrect expression is left as an exercise to
     12386     * the reader. */
     12387    v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
     12388                *numstackptr = numstack;
     12389    /* Stack of operator tokens */
     12390    operator *stack = alloca((datasizes) * sizeof(operator)),
     12391                *stackptr = stack;
     12392
     12393    *stackptr++ = lasttok = TOK_LPAREN;     /* start off with a left paren */
     12394    *perrcode = errcode = 0;
     12395
     12396    while (1) {
     12397        arithval = *expr;
     12398        if (arithval == 0) {
     12399            if (p == endexpression) {
     12400                /* Null expression. */
     12401                return 0;
     12402            }
     12403
     12404            /* This is only reached after all tokens have been extracted from the
     12405             * input stream. If there are still tokens on the operator stack, they
     12406             * are to be applied in order. At the end, there should be a final
     12407             * result on the integer stack */
     12408
     12409            if (expr != endexpression + 1) {
     12410                /* If we haven't done so already, */
     12411                /* append a closing right paren */
     12412                expr = endexpression;
     12413                /* and let the loop process it. */
     12414                continue;
     12415            }
     12416            /* At this point, we're done with the expression. */
     12417            if (numstackptr != numstack+1) {
     12418                /* ... but if there isn't, it's bad */
     12419 err:
     12420                return (*perrcode = -1);
     12421            }
     12422            if (numstack->var) {
     12423                /* expression is $((var)) only, lookup now */
     12424                errcode = arith_lookup_val(numstack);
     12425            }
     12426 ret:
     12427            *perrcode = errcode;
     12428            return numstack->val;
     12429        }
     12430
    1353112431        /* Continue processing the expression. */
    1353212432        if (arith_isspace(arithval)) {
     
    1353412434            goto prologue;
    1353512435        }
    13536         if((p = endofname(expr)) != expr) {
     12436        p = endofname(expr);
     12437        if (p != expr) {
    1353712438            size_t var_name_size = (p-expr) + 1;  /* trailing zero */
    1353812439
     
    1354012441            safe_strncpy(numstackptr->var, expr, var_name_size);
    1354112442            expr = p;
    13542         num:
     12443 num:
    1354312444            numstackptr->contidional_second_val_initialized = 0;
    1354412445            numstackptr++;
    1354512446            lasttok = TOK_NUM;
    1354612447            continue;
    13547         } else if (is_digit(arithval)) {
     12448        }
     12449        if (isdigit(arithval)) {
    1354812450            numstackptr->var = NULL;
    13549 #ifdef CONFIG_ASH_MATH_SUPPORT_64
     12451#if ENABLE_ASH_MATH_SUPPORT_64
    1355012452            numstackptr->val = strtoll(expr, (char **) &expr, 0);
    1355112453#else
     
    1355412456            goto num;
    1355512457        }
    13556         for(p = op_tokens; ; p++) {
     12458        for (p = op_tokens; ; p++) {
    1355712459            const char *o;
    1355812460
    13559             if(*p == 0) {
     12461            if (*p == 0) {
    1356012462                /* strange operator not found */
    1356112463                goto err;
    1356212464            }
    13563             for(o = expr; *p && *o == *p; p++)
     12465            for (o = expr; *p && *o == *p; p++)
    1356412466                o++;
    13565             if(! *p) {
     12467            if (! *p) {
    1356612468                /* found */
    1356712469                expr = o - 1;
     
    1356912471            }
    1357012472            /* skip tail uncompared token */
    13571             while(*p)
     12473            while (*p)
    1357212474                p++;
    1357312475            /* skip zero delim */
     
    1357712479
    1357812480        /* post grammar: a++ reduce to num */
    13579         if(lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
    13580             lasttok = TOK_NUM;
     12481        if (lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
     12482            lasttok = TOK_NUM;
    1358112483
    1358212484        /* Plus and minus are binary (not unary) _only_ if the last
     
    1358512487         * It makes sense. */
    1358612488        if (lasttok != TOK_NUM) {
    13587             switch(op) {
    13588                 case TOK_ADD:
    13589                     op = TOK_UPLUS;
    13590                     break;
    13591                 case TOK_SUB:
    13592                     op = TOK_UMINUS;
    13593                     break;
    13594                 case TOK_POST_INC:
    13595                     op = TOK_PRE_INC;
    13596                     break;
    13597                 case TOK_POST_DEC:
    13598                     op = TOK_PRE_DEC;
    13599                     break;
     12489            switch (op) {
     12490            case TOK_ADD:
     12491                op = TOK_UPLUS;
     12492                break;
     12493            case TOK_SUB:
     12494                op = TOK_UMINUS;
     12495                break;
     12496            case TOK_POST_INC:
     12497                op = TOK_PRE_INC;
     12498                break;
     12499            case TOK_POST_DEC:
     12500                op = TOK_PRE_DEC;
     12501                break;
    1360012502            }
    1360112503        }
     
    1361912521            }
    1362012522            while (stackptr != stack) {
    13621                 if (op == TOK_RPAREN) {
    13622                 /* The algorithm employed here is simple: while we don't
    13623                  * hit an open paren nor the bottom of the stack, pop
    13624                  * tokens and apply them */
    13625                 if (stackptr[-1] == TOK_LPAREN) {
    13626                     --stackptr;
    13627                     /* Any operator directly after a */
    13628                     lasttok = TOK_NUM;
    13629                     /* close paren should consider itself binary */
    13630                     goto prologue;
     12523                if (op == TOK_RPAREN) {
     12524                    /* The algorithm employed here is simple: while we don't
     12525                     * hit an open paren nor the bottom of the stack, pop
     12526                     * tokens and apply them */
     12527                    if (stackptr[-1] == TOK_LPAREN) {
     12528                        --stackptr;
     12529                        /* Any operator directly after a */
     12530                        lasttok = TOK_NUM;
     12531                        /* close paren should consider itself binary */
     12532                        goto prologue;
     12533                    }
     12534                } else {
     12535                    operator prev_prec = PREC(stackptr[-1]);
     12536
     12537                    convert_prec_is_assing(prec);
     12538                    convert_prec_is_assing(prev_prec);
     12539                    if (prev_prec < prec)
     12540                        break;
     12541                    /* check right assoc */
     12542                    if (prev_prec == prec && is_right_associativity(prec))
     12543                        break;
    1363112544                }
    13632                 } else {
    13633                 operator prev_prec = PREC(stackptr[-1]);
    13634 
    13635                 convert_prec_is_assing(prec);
    13636                 convert_prec_is_assing(prev_prec);
    13637                 if (prev_prec < prec)
    13638                     break;
    13639                 /* check right assoc */
    13640                 if(prev_prec == prec && is_right_associativity(prec))
    13641                     break;
    13642                 }
    13643                 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
    13644                 if(errcode) goto ret;
     12545                errcode = arith_apply(*--stackptr, numstack, &numstackptr);
     12546                if (errcode) goto ret;
    1364512547            }
    1364612548            if (op == TOK_RPAREN) {
     
    1365112553        /* Push this operator to the stack and remember it. */
    1365212554        *stackptr++ = lasttok = op;
    13653 
    13654       prologue:
     12555 prologue:
    1365512556        ++expr;
    13656     }
    13657     }
    13658 }
    13659 #endif /* CONFIG_ASH_MATH_SUPPORT */
    13660 
    13661 
    13662 #ifdef DEBUG
    13663 const char *bb_applet_name = "debug stuff usage";
     12557    } /* while */
     12558}
     12559#endif /* ASH_MATH_SUPPORT */
     12560
     12561
     12562/* ============ main() and helpers */
     12563
     12564/*
     12565 * Called to exit the shell.
     12566 */
     12567static void exitshell(void) ATTRIBUTE_NORETURN;
     12568static void
     12569exitshell(void)
     12570{
     12571    struct jmploc loc;
     12572    char *p;
     12573    int status;
     12574
     12575    status = exitstatus;
     12576    TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
     12577    if (setjmp(loc.loc)) {
     12578        if (exception == EXEXIT)
     12579/* dash bug: it just does _exit(exitstatus) here
     12580 * but we have to do setjobctl(0) first!
     12581 * (bug is still not fixed in dash-0.5.3 - if you run dash
     12582 * under Midnight Commander, on exit from dash MC is backgrounded) */
     12583            status = exitstatus;
     12584        goto out;
     12585    }
     12586    exception_handler = &loc;
     12587    p = trap[0];
     12588    if (p) {
     12589        trap[0] = NULL;
     12590        evalstring(p, 0);
     12591    }
     12592    flush_stdout_stderr();
     12593 out:
     12594    setjobctl(0);
     12595    _exit(status);
     12596    /* NOTREACHED */
     12597}
     12598
     12599static void
     12600init(void)
     12601{
     12602    /* from input.c: */
     12603    basepf.nextc = basepf.buf = basebuf;
     12604
     12605    /* from trap.c: */
     12606    signal(SIGCHLD, SIG_DFL);
     12607
     12608    /* from var.c: */
     12609    {
     12610        char **envp;
     12611        char ppid[sizeof(int)*3 + 1];
     12612        const char *p;
     12613        struct stat st1, st2;
     12614
     12615        initvar();
     12616        for (envp = environ; envp && *envp; envp++) {
     12617            if (strchr(*envp, '=')) {
     12618                setvareq(*envp, VEXPORT|VTEXTFIXED);
     12619            }
     12620        }
     12621
     12622        snprintf(ppid, sizeof(ppid), "%u", (unsigned) getppid());
     12623        setvar("PPID", ppid, 0);
     12624
     12625        p = lookupvar("PWD");
     12626        if (p)
     12627            if (*p != '/' || stat(p, &st1) || stat(".", &st2)
     12628             || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
     12629                p = '\0';
     12630        setpwd(p, 0);
     12631    }
     12632}
     12633
     12634/*
     12635 * Process the shell command line arguments.
     12636 */
     12637static void
     12638procargs(int argc, char **argv)
     12639{
     12640    int i;
     12641    const char *xminusc;
     12642    char **xargv;
     12643
     12644    xargv = argv;
     12645    arg0 = xargv[0];
     12646    if (argc > 0)
     12647        xargv++;
     12648    for (i = 0; i < NOPTS; i++)
     12649        optlist[i] = 2;
     12650    argptr = xargv;
     12651    options(1);
     12652    xargv = argptr;
     12653    xminusc = minusc;
     12654    if (*xargv == NULL) {
     12655        if (xminusc)
     12656            ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
     12657        sflag = 1;
     12658    }
     12659    if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
     12660        iflag = 1;
     12661    if (mflag == 2)
     12662        mflag = iflag;
     12663    for (i = 0; i < NOPTS; i++)
     12664        if (optlist[i] == 2)
     12665            optlist[i] = 0;
     12666#if DEBUG == 2
     12667    debug = 1;
     12668#endif
     12669    /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
     12670    if (xminusc) {
     12671        minusc = *xargv++;
     12672        if (*xargv)
     12673            goto setarg0;
     12674    } else if (!sflag) {
     12675        setinputfile(*xargv, 0);
     12676 setarg0:
     12677        arg0 = *xargv++;
     12678        commandname = arg0;
     12679    }
     12680
     12681    shellparam.p = xargv;
     12682#if ENABLE_ASH_GETOPTS
     12683    shellparam.optind = 1;
     12684    shellparam.optoff = -1;
     12685#endif
     12686    /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
     12687    while (*xargv) {
     12688        shellparam.nparam++;
     12689        xargv++;
     12690    }
     12691    optschanged();
     12692}
     12693
     12694/*
     12695 * Read /etc/profile or .profile.
     12696 */
     12697static void
     12698read_profile(const char *name)
     12699{
     12700    int skip;
     12701
     12702    if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
     12703        return;
     12704    skip = cmdloop(0);
     12705    popfile();
     12706    if (skip)
     12707        exitshell();
     12708}
     12709
     12710/*
     12711 * This routine is called when an error or an interrupt occurs in an
     12712 * interactive shell and control is returned to the main command loop.
     12713 */
     12714static void
     12715reset(void)
     12716{
     12717    /* from eval.c: */
     12718    evalskip = 0;
     12719    loopnest = 0;
     12720    /* from input.c: */
     12721    parselleft = parsenleft = 0;      /* clear input buffer */
     12722    popallfiles();
     12723    /* from parser.c: */
     12724    tokpushback = 0;
     12725    checkkwd = 0;
     12726    /* from redir.c: */
     12727    clearredir(0);
     12728}
     12729
     12730#if PROFILE
     12731static short profile_buf[16384];
     12732extern int etext();
     12733#endif
     12734
     12735/*
     12736 * Main routine.  We initialize things, parse the arguments, execute
     12737 * profiles if we're a login shell, and then call cmdloop to execute
     12738 * commands.  The setjmp call sets up the location to jump to when an
     12739 * exception occurs.  When an exception occurs the variable "state"
     12740 * is used to figure out how far we had gotten.
     12741 */
     12742int ash_main(int argc, char **argv);
     12743int ash_main(int argc, char **argv)
     12744{
     12745    char *shinit;
     12746    volatile int state;
     12747    struct jmploc jmploc;
     12748    struct stackmark smark;
     12749
     12750#if PROFILE
     12751    monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
     12752#endif
     12753
     12754#if ENABLE_FEATURE_EDITING
     12755    line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
     12756#endif
     12757    state = 0;
     12758    if (setjmp(jmploc.loc)) {
     12759        int e;
     12760        int s;
     12761
     12762        reset();
     12763
     12764        e = exception;
     12765        if (e == EXERROR)
     12766            exitstatus = 2;
     12767        s = state;
     12768        if (e == EXEXIT || s == 0 || iflag == 0 || shlvl)
     12769            exitshell();
     12770
     12771        if (e == EXINT) {
     12772            outcslow('\n', stderr);
     12773        }
     12774        popstackmark(&smark);
     12775        FORCE_INT_ON; /* enable interrupts */
     12776        if (s == 1)
     12777            goto state1;
     12778        if (s == 2)
     12779            goto state2;
     12780        if (s == 3)
     12781            goto state3;
     12782        goto state4;
     12783    }
     12784    exception_handler = &jmploc;
     12785#if DEBUG
     12786    opentrace();
     12787    trace_puts("Shell args: ");
     12788    trace_puts_args(argv);
     12789#endif
     12790    rootpid = getpid();
     12791
     12792#if ENABLE_ASH_RANDOM_SUPPORT
     12793    rseed = rootpid + time(NULL);
     12794#endif
     12795    init();
     12796    setstackmark(&smark);
     12797    procargs(argc, argv);
     12798#if ENABLE_FEATURE_EDITING_SAVEHISTORY
     12799    if (iflag) {
     12800        const char *hp = lookupvar("HISTFILE");
     12801
     12802        if (hp == NULL) {
     12803            hp = lookupvar("HOME");
     12804            if (hp != NULL) {
     12805                char *defhp = concat_path_file(hp, ".ash_history");
     12806                setvar("HISTFILE", defhp, 0);
     12807                free(defhp);
     12808            }
     12809        }
     12810    }
     12811#endif
     12812    if (argv[0] && argv[0][0] == '-')
     12813        isloginsh = 1;
     12814    if (isloginsh) {
     12815        state = 1;
     12816        read_profile("/etc/profile");
     12817 state1:
     12818        state = 2;
     12819        read_profile(".profile");
     12820    }
     12821 state2:
     12822    state = 3;
     12823    if (
     12824#ifndef linux
     12825     getuid() == geteuid() && getgid() == getegid() &&
     12826#endif
     12827     iflag
     12828    ) {
     12829        shinit = lookupvar("ENV");
     12830        if (shinit != NULL && *shinit != '\0') {
     12831            read_profile(shinit);
     12832        }
     12833    }
     12834 state3:
     12835    state = 4;
     12836    if (minusc)
     12837        evalstring(minusc, 0);
     12838
     12839    if (sflag || minusc == NULL) {
     12840#if ENABLE_FEATURE_EDITING_SAVEHISTORY
     12841        if ( iflag ) {
     12842            const char *hp = lookupvar("HISTFILE");
     12843
     12844            if (hp != NULL)
     12845                line_input_state->hist_file = hp;
     12846        }
     12847#endif
     12848 state4: /* XXX ??? - why isn't this before the "if" statement */
     12849        cmdloop(1);
     12850    }
     12851#if PROFILE
     12852    monitor(0);
     12853#endif
     12854#ifdef GPROF
     12855    {
     12856        extern void _mcleanup(void);
     12857        _mcleanup();
     12858    }
     12859#endif
     12860    exitshell();
     12861    /* NOTREACHED */
     12862}
     12863
     12864#if DEBUG
     12865const char *applet_name = "debug stuff usage";
    1366412866int main(int argc, char **argv)
    1366512867{
     
    1366712869}
    1366812870#endif
     12871
    1366912872
    1367012873/*-
Note: See TracChangeset for help on using the changeset viewer.