1  | 
     | 
     | 
    /*	$OpenBSD: csh.c,v 1.41 2017/08/30 06:42:21 anton Exp $	*/  | 
    
    
    2  | 
     | 
     | 
    /*	$NetBSD: csh.c,v 1.14 1995/04/29 23:21:28 mycroft Exp $	*/  | 
    
    
    3  | 
     | 
     | 
     | 
    
    
    4  | 
     | 
     | 
    /*-  | 
    
    
    5  | 
     | 
     | 
     * Copyright (c) 1980, 1991, 1993  | 
    
    
    6  | 
     | 
     | 
     *	The Regents of the University of California.  All rights reserved.  | 
    
    
    7  | 
     | 
     | 
     *  | 
    
    
    8  | 
     | 
     | 
     * Redistribution and use in source and binary forms, with or without  | 
    
    
    9  | 
     | 
     | 
     * modification, are permitted provided that the following conditions  | 
    
    
    10  | 
     | 
     | 
     * are met:  | 
    
    
    11  | 
     | 
     | 
     * 1. Redistributions of source code must retain the above copyright  | 
    
    
    12  | 
     | 
     | 
     *    notice, this list of conditions and the following disclaimer.  | 
    
    
    13  | 
     | 
     | 
     * 2. Redistributions in binary form must reproduce the above copyright  | 
    
    
    14  | 
     | 
     | 
     *    notice, this list of conditions and the following disclaimer in the  | 
    
    
    15  | 
     | 
     | 
     *    documentation and/or other materials provided with the distribution.  | 
    
    
    16  | 
     | 
     | 
     * 3. Neither the name of the University nor the names of its contributors  | 
    
    
    17  | 
     | 
     | 
     *    may be used to endorse or promote products derived from this software  | 
    
    
    18  | 
     | 
     | 
     *    without specific prior written permission.  | 
    
    
    19  | 
     | 
     | 
     *  | 
    
    
    20  | 
     | 
     | 
     * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND  | 
    
    
    21  | 
     | 
     | 
     * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE  | 
    
    
    22  | 
     | 
     | 
     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE  | 
    
    
    23  | 
     | 
     | 
     * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE  | 
    
    
    24  | 
     | 
     | 
     * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL  | 
    
    
    25  | 
     | 
     | 
     * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS  | 
    
    
    26  | 
     | 
     | 
     * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)  | 
    
    
    27  | 
     | 
     | 
     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT  | 
    
    
    28  | 
     | 
     | 
     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY  | 
    
    
    29  | 
     | 
     | 
     * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF  | 
    
    
    30  | 
     | 
     | 
     * SUCH DAMAGE.  | 
    
    
    31  | 
     | 
     | 
     */  | 
    
    
    32  | 
     | 
     | 
     | 
    
    
    33  | 
     | 
     | 
    #include <sys/types.h>  | 
    
    
    34  | 
     | 
     | 
    #include <sys/stat.h>  | 
    
    
    35  | 
     | 
     | 
    #include <fcntl.h>  | 
    
    
    36  | 
     | 
     | 
    #include <errno.h>  | 
    
    
    37  | 
     | 
     | 
    #include <pwd.h>  | 
    
    
    38  | 
     | 
     | 
    #include <stdlib.h>  | 
    
    
    39  | 
     | 
     | 
    #include <string.h>  | 
    
    
    40  | 
     | 
     | 
    #include <locale.h>  | 
    
    
    41  | 
     | 
     | 
    #include <unistd.h>  | 
    
    
    42  | 
     | 
     | 
    #include <limits.h>  | 
    
    
    43  | 
     | 
     | 
    #include <vis.h>  | 
    
    
    44  | 
     | 
     | 
    #include <stdarg.h>  | 
    
    
    45  | 
     | 
     | 
     | 
    
    
    46  | 
     | 
     | 
    #include "csh.h"  | 
    
    
    47  | 
     | 
     | 
    #include "proc.h"  | 
    
    
    48  | 
     | 
     | 
    #include "extern.h"  | 
    
    
    49  | 
     | 
     | 
    #include "pathnames.h"  | 
    
    
    50  | 
     | 
     | 
     | 
    
    
    51  | 
     | 
     | 
    /*  | 
    
    
    52  | 
     | 
     | 
     * C Shell  | 
    
    
    53  | 
     | 
     | 
     *  | 
    
    
    54  | 
     | 
     | 
     * Bill Joy, UC Berkeley, California, USA  | 
    
    
    55  | 
     | 
     | 
     * October 1978, May 1980  | 
    
    
    56  | 
     | 
     | 
     *  | 
    
    
    57  | 
     | 
     | 
     * Jim Kulp, IIASA, Laxenburg, Austria  | 
    
    
    58  | 
     | 
     | 
     * April 1980  | 
    
    
    59  | 
     | 
     | 
     *  | 
    
    
    60  | 
     | 
     | 
     * Christos Zoulas, Cornell University  | 
    
    
    61  | 
     | 
     | 
     * June, 1991  | 
    
    
    62  | 
     | 
     | 
     */  | 
    
    
    63  | 
     | 
     | 
     | 
    
    
    64  | 
     | 
     | 
    Char   *dumphist[] = {STRhistory, STRmh, 0, 0}; | 
    
    
    65  | 
     | 
     | 
    Char   *loadhist[] = {STRsource, STRmh, STRtildothist, 0}; | 
    
    
    66  | 
     | 
     | 
     | 
    
    
    67  | 
     | 
     | 
    int     nofile = 0;  | 
    
    
    68  | 
     | 
     | 
    bool    reenter = 0;  | 
    
    
    69  | 
     | 
     | 
    bool    nverbose = 0;  | 
    
    
    70  | 
     | 
     | 
    bool    nexececho = 0;  | 
    
    
    71  | 
     | 
     | 
    bool    quitit = 0;  | 
    
    
    72  | 
     | 
     | 
    bool    fast = 0;  | 
    
    
    73  | 
     | 
     | 
    bool    batch = 0;  | 
    
    
    74  | 
     | 
     | 
    bool    mflag = 0;  | 
    
    
    75  | 
     | 
     | 
    bool    prompt = 1;  | 
    
    
    76  | 
     | 
     | 
    bool    enterhist = 0;  | 
    
    
    77  | 
     | 
     | 
    bool    tellwhat = 0;  | 
    
    
    78  | 
     | 
     | 
     | 
    
    
    79  | 
     | 
     | 
    extern char **environ;  | 
    
    
    80  | 
     | 
     | 
     | 
    
    
    81  | 
     | 
     | 
    static int	readf(void *, char *, int);  | 
    
    
    82  | 
     | 
     | 
    static fpos_t	seekf(void *, fpos_t, int);  | 
    
    
    83  | 
     | 
     | 
    static int	writef(void *, const char *, int);  | 
    
    
    84  | 
     | 
     | 
    static int	closef(void *);  | 
    
    
    85  | 
     | 
     | 
    static int	srccat(Char *, Char *);  | 
    
    
    86  | 
     | 
     | 
    static int	srcfile(char *, bool, bool);  | 
    
    
    87  | 
     | 
     | 
    static void	phup(int);  | 
    
    
    88  | 
     | 
     | 
    static void	srcunit(int, bool, bool);  | 
    
    
    89  | 
     | 
     | 
    static void	mailchk(void);  | 
    
    
    90  | 
     | 
     | 
    static Char   **defaultpath(void);  | 
    
    
    91  | 
     | 
     | 
     | 
    
    
    92  | 
     | 
     | 
    int  | 
    
    
    93  | 
     | 
     | 
    main(int argc, char *argv[])  | 
    
    
    94  | 
     | 
     | 
    { | 
    
    
    95  | 
     | 
     | 
        Char *cp;  | 
    
    
    96  | 
     | 
     | 
        char *tcp;  | 
    
    
    97  | 
     | 
     | 
        int f;  | 
    
    
    98  | 
     | 
     | 
        char **tempv;  | 
    
    
    99  | 
     | 
     | 
        struct sigaction oact;  | 
    
    
    100  | 
     | 
     | 
        sigset_t sigset;  | 
    
    
    101  | 
     | 
     | 
     | 
    
    
    102  | 
     | 
     | 
        cshin = stdin;  | 
    
    
    103  | 
     | 
     | 
        cshout = stdout;  | 
    
    
    104  | 
     | 
     | 
        csherr = stderr;  | 
    
    
    105  | 
     | 
     | 
     | 
    
    
    106  | 
     | 
     | 
        settimes();			/* Immed. estab. timing base */  | 
    
    
    107  | 
     | 
     | 
     | 
    
    
    108  | 
     | 
     | 
        /*  | 
    
    
    109  | 
     | 
     | 
         * Initialize non constant strings  | 
    
    
    110  | 
     | 
     | 
         */  | 
    
    
    111  | 
     | 
     | 
        STR_BSHELL = SAVE(_PATH_BSHELL);  | 
    
    
    112  | 
     | 
     | 
        STR_SHELLPATH = SAVE(_PATH_CSHELL);  | 
    
    
    113  | 
     | 
     | 
        STR_environ = blk2short(environ);  | 
    
    
    114  | 
     | 
     | 
        environ = short2blk(STR_environ);	/* So that we can free it */  | 
    
    
    115  | 
     | 
     | 
        STR_WORD_CHARS = SAVE(WORD_CHARS);  | 
    
    
    116  | 
     | 
     | 
     | 
    
    
    117  | 
     | 
     | 
        HIST = '!';  | 
    
    
    118  | 
     | 
     | 
        HISTSUB = '^';  | 
    
    
    119  | 
     | 
     | 
        word_chars = STR_WORD_CHARS;  | 
    
    
    120  | 
     | 
     | 
     | 
    
    
    121  | 
     | 
     | 
        tempv = argv;  | 
    
    
    122  | 
     | 
     | 
        if (eq(str2short(tempv[0]), STRaout))	/* A.out's are quittable */  | 
    
    
    123  | 
     | 
     | 
    	quitit = 1;  | 
    
    
    124  | 
     | 
     | 
        uid = getuid();  | 
    
    
    125  | 
     | 
     | 
        gid = getgid();  | 
    
    
    126  | 
     | 
     | 
        euid = geteuid();  | 
    
    
    127  | 
     | 
     | 
        egid = getegid();  | 
    
    
    128  | 
     | 
     | 
        /*  | 
    
    
    129  | 
     | 
     | 
         * We are a login shell if: 1. we were invoked as -<something> and we had  | 
    
    
    130  | 
     | 
     | 
         * no arguments 2. or we were invoked only with the -l flag  | 
    
    
    131  | 
     | 
     | 
         */  | 
    
    
    132  | 
     | 
     | 
        loginsh = (**tempv == '-' && argc == 1) ||  | 
    
    
    133  | 
     | 
     | 
    	(argc == 2 && tempv[1][0] == '-' && tempv[1][1] == 'l' &&  | 
    
    
    134  | 
     | 
     | 
    	 tempv[1][2] == '\0');  | 
    
    
    135  | 
     | 
     | 
     | 
    
    
    136  | 
     | 
     | 
        if (loginsh && **tempv != '-') { | 
    
    
    137  | 
     | 
     | 
    	/*  | 
    
    
    138  | 
     | 
     | 
    	 * Mangle the argv space  | 
    
    
    139  | 
     | 
     | 
    	 */  | 
    
    
    140  | 
     | 
     | 
    	tempv[1][0] = '\0';  | 
    
    
    141  | 
     | 
     | 
    	tempv[1][1] = '\0';  | 
    
    
    142  | 
     | 
     | 
    	tempv[1] = NULL;  | 
    
    
    143  | 
     | 
     | 
    	for (tcp = *tempv; *tcp++;)  | 
    
    
    144  | 
     | 
     | 
    	    continue;  | 
    
    
    145  | 
     | 
     | 
    	for (tcp--; tcp >= *tempv; tcp--)  | 
    
    
    146  | 
     | 
     | 
    	    tcp[1] = tcp[0];  | 
    
    
    147  | 
     | 
     | 
    	*++tcp = '-';  | 
    
    
    148  | 
     | 
     | 
    	argc--;  | 
    
    
    149  | 
     | 
     | 
        }  | 
    
    
    150  | 
     | 
     | 
        if (loginsh)  | 
    
    
    151  | 
     | 
     | 
    	(void) time(&chktim);  | 
    
    
    152  | 
     | 
     | 
     | 
    
    
    153  | 
     | 
     | 
        if (pledge("stdio rpath wpath cpath fattr getpw proc exec tty", | 
    
    
    154  | 
     | 
     | 
    	NULL) == -1) { | 
    
    
    155  | 
     | 
     | 
    	    perror("pledge"); | 
    
    
    156  | 
     | 
     | 
    	    exit(1);  | 
    
    
    157  | 
     | 
     | 
        }  | 
    
    
    158  | 
     | 
     | 
     | 
    
    
    159  | 
     | 
     | 
        /*  | 
    
    
    160  | 
     | 
     | 
         * Move the descriptors to safe places. The variable didfds is 0 while we  | 
    
    
    161  | 
     | 
     | 
         * have only FSH* to work with. When didfds is true, we have 0,1,2 and  | 
    
    
    162  | 
     | 
     | 
         * prefer to use these.  | 
    
    
    163  | 
     | 
     | 
         */  | 
    
    
    164  | 
     | 
     | 
        initdesc();  | 
    
    
    165  | 
     | 
     | 
        /*  | 
    
    
    166  | 
     | 
     | 
         * XXX: This is to keep programs that use stdio happy.  | 
    
    
    167  | 
     | 
     | 
         *	    what we really want is freunopen() ....  | 
    
    
    168  | 
     | 
     | 
         *	    Closing cshin cshout and csherr (which are really stdin stdout  | 
    
    
    169  | 
     | 
     | 
         *	    and stderr at this point and then reopening them in the same order  | 
    
    
    170  | 
     | 
     | 
         *	    gives us again stdin == cshin stdout == cshout and stderr == csherr.  | 
    
    
    171  | 
     | 
     | 
         *	    If that was not the case builtins like printf that use stdio  | 
    
    
    172  | 
     | 
     | 
         *	    would break. But in any case we could fix that with memcpy and  | 
    
    
    173  | 
     | 
     | 
         *	    a bit of pointer manipulation...  | 
    
    
    174  | 
     | 
     | 
         *	    Fortunately this is not needed under the current implementation  | 
    
    
    175  | 
     | 
     | 
         *	    of stdio.  | 
    
    
    176  | 
     | 
     | 
         */  | 
    
    
    177  | 
     | 
     | 
        (void) fclose(cshin);  | 
    
    
    178  | 
     | 
     | 
        (void) fclose(cshout);  | 
    
    
    179  | 
     | 
     | 
        (void) fclose(csherr);  | 
    
    
    180  | 
     | 
     | 
        if (!(cshin  = funopen((void *) &SHIN,  readf, writef, seekf, closef)))  | 
    
    
    181  | 
     | 
     | 
    	exit(1);  | 
    
    
    182  | 
     | 
     | 
        if (!(cshout = funopen((void *) &SHOUT, readf, writef, seekf, closef)))  | 
    
    
    183  | 
     | 
     | 
    	exit(1);  | 
    
    
    184  | 
     | 
     | 
        if (!(csherr = funopen((void *) &SHERR, readf, writef, seekf, closef)))  | 
    
    
    185  | 
     | 
     | 
    	exit(1);  | 
    
    
    186  | 
     | 
     | 
        (void) setvbuf(cshin,  NULL, _IOLBF, 0);  | 
    
    
    187  | 
     | 
     | 
        (void) setvbuf(cshout, NULL, _IOLBF, 0);  | 
    
    
    188  | 
     | 
     | 
        (void) setvbuf(csherr, NULL, _IOLBF, 0);  | 
    
    
    189  | 
     | 
     | 
     | 
    
    
    190  | 
     | 
     | 
        /*  | 
    
    
    191  | 
     | 
     | 
         * Initialize the shell variables. ARGV and PROMPT are initialized later.  | 
    
    
    192  | 
     | 
     | 
         * STATUS is also munged in several places. CHILD is munged when  | 
    
    
    193  | 
     | 
     | 
         * forking/waiting  | 
    
    
    194  | 
     | 
     | 
         */  | 
    
    
    195  | 
     | 
     | 
        set(STRstatus, Strsave(STR0));  | 
    
    
    196  | 
     | 
     | 
     | 
    
    
    197  | 
     | 
     | 
        if ((tcp = getenv("HOME")) != NULL && strlen(tcp) < PATH_MAX) | 
    
    
    198  | 
     | 
     | 
    	cp = SAVE(tcp);  | 
    
    
    199  | 
     | 
     | 
        else  | 
    
    
    200  | 
     | 
     | 
    	cp = NULL;  | 
    
    
    201  | 
     | 
     | 
     | 
    
    
    202  | 
     | 
     | 
        if (cp == NULL)  | 
    
    
    203  | 
     | 
     | 
    	fast = 1;		/* No home -> can't read scripts */  | 
    
    
    204  | 
     | 
     | 
        else  | 
    
    
    205  | 
     | 
     | 
    	set(STRhome, cp);  | 
    
    
    206  | 
     | 
     | 
        dinit(cp);			/* dinit thinks that HOME == cwd in a login  | 
    
    
    207  | 
     | 
     | 
    				 * shell */  | 
    
    
    208  | 
     | 
     | 
        /*  | 
    
    
    209  | 
     | 
     | 
         * Grab other useful things from the environment. Should we grab  | 
    
    
    210  | 
     | 
     | 
         * everything??  | 
    
    
    211  | 
     | 
     | 
         */  | 
    
    
    212  | 
     | 
     | 
        if ((tcp = getenv("LOGNAME")) != NULL || | 
    
    
    213  | 
     | 
     | 
    	(tcp = getenv("USER")) != NULL) | 
    
    
    214  | 
     | 
     | 
    	set(STRuser, quote(SAVE(tcp)));  | 
    
    
    215  | 
     | 
     | 
        if ((tcp = getenv("TERM")) != NULL) | 
    
    
    216  | 
     | 
     | 
    	set(STRterm, quote(SAVE(tcp)));  | 
    
    
    217  | 
     | 
     | 
     | 
    
    
    218  | 
     | 
     | 
        /*  | 
    
    
    219  | 
     | 
     | 
         * Re-initialize path if set in environment  | 
    
    
    220  | 
     | 
     | 
         */  | 
    
    
    221  | 
     | 
     | 
        if ((tcp = getenv("PATH")) == NULL) | 
    
    
    222  | 
     | 
     | 
    	setq(STRpath, defaultpath(), &shvhed);  | 
    
    
    223  | 
     | 
     | 
        else  | 
    
    
    224  | 
     | 
     | 
    	importpath(str2short(tcp));  | 
    
    
    225  | 
     | 
     | 
     | 
    
    
    226  | 
     | 
     | 
        set(STRshell, Strsave(STR_SHELLPATH));  | 
    
    
    227  | 
     | 
     | 
     | 
    
    
    228  | 
     | 
     | 
        doldol = putn((int) getpid());	/* For $$ */  | 
    
    
    229  | 
     | 
     | 
     | 
    
    
    230  | 
     | 
     | 
        /*  | 
    
    
    231  | 
     | 
     | 
         * Record the interrupt states from the parent process. If the parent is  | 
    
    
    232  | 
     | 
     | 
         * non-interruptible our hand must be forced or we (and our children) won't  | 
    
    
    233  | 
     | 
     | 
         * be either. Our children inherit termination from our parent. We catch it  | 
    
    
    234  | 
     | 
     | 
         * only if we are the login shell.  | 
    
    
    235  | 
     | 
     | 
         */  | 
    
    
    236  | 
     | 
     | 
        /* parents interruptibility */  | 
    
    
    237  | 
     | 
     | 
        (void) sigaction(SIGINT, NULL, &oact);  | 
    
    
    238  | 
     | 
     | 
        parintr = oact.sa_handler;  | 
    
    
    239  | 
     | 
     | 
        (void) sigaction(SIGTERM, NULL, &oact);  | 
    
    
    240  | 
     | 
     | 
        parterm = oact.sa_handler;  | 
    
    
    241  | 
     | 
     | 
     | 
    
    
    242  | 
     | 
     | 
        /* catch these all, login shell or not */  | 
    
    
    243  | 
     | 
     | 
        (void) signal(SIGHUP, phup);	/* exit processing on HUP */  | 
    
    
    244  | 
     | 
     | 
        (void) signal(SIGXCPU, phup);	/* ...and on XCPU */  | 
    
    
    245  | 
     | 
     | 
        (void) signal(SIGXFSZ, phup);	/* ...and on XFSZ */  | 
    
    
    246  | 
     | 
     | 
     | 
    
    
    247  | 
     | 
     | 
        /*  | 
    
    
    248  | 
     | 
     | 
         * Process the arguments.  | 
    
    
    249  | 
     | 
     | 
         *  | 
    
    
    250  | 
     | 
     | 
         * Note that processing of -v/-x is actually delayed till after script  | 
    
    
    251  | 
     | 
     | 
         * processing.  | 
    
    
    252  | 
     | 
     | 
         *  | 
    
    
    253  | 
     | 
     | 
         * We set the first character of our name to be '-' if we are a shell  | 
    
    
    254  | 
     | 
     | 
         * running interruptible commands.  Many programs which examine ps'es  | 
    
    
    255  | 
     | 
     | 
         * use this to filter such shells out.  | 
    
    
    256  | 
     | 
     | 
         */  | 
    
    
    257  | 
     | 
     | 
        argc--, tempv++;  | 
    
    
    258  | 
     | 
     | 
        while (argc > 0 && (tcp = tempv[0])[0] == '-' && *++tcp != '\0' && !batch) { | 
    
    
    259  | 
     | 
     | 
    	do  | 
    
    
    260  | 
     | 
     | 
    	    switch (*tcp++) { | 
    
    
    261  | 
     | 
     | 
     | 
    
    
    262  | 
     | 
     | 
    	    case 0:		/* -	Interruptible, no prompt */  | 
    
    
    263  | 
     | 
     | 
    		prompt = 0;  | 
    
    
    264  | 
     | 
     | 
    		setintr = 1;  | 
    
    
    265  | 
     | 
     | 
    		nofile = 1;  | 
    
    
    266  | 
     | 
     | 
    		break;  | 
    
    
    267  | 
     | 
     | 
     | 
    
    
    268  | 
     | 
     | 
    	    case 'b':		/* -b	Next arg is input file */  | 
    
    
    269  | 
     | 
     | 
    		batch = 1;  | 
    
    
    270  | 
     | 
     | 
    		break;  | 
    
    
    271  | 
     | 
     | 
     | 
    
    
    272  | 
     | 
     | 
    	    case 'c':		/* -c	Command input from arg */  | 
    
    
    273  | 
     | 
     | 
    		if (argc == 1)  | 
    
    
    274  | 
     | 
     | 
    		    xexit(0);  | 
    
    
    275  | 
     | 
     | 
    		argc--, tempv++;  | 
    
    
    276  | 
     | 
     | 
    		arginp = SAVE(tempv[0]);  | 
    
    
    277  | 
     | 
     | 
    		prompt = 0;  | 
    
    
    278  | 
     | 
     | 
    		nofile = 1;  | 
    
    
    279  | 
     | 
     | 
    		break;  | 
    
    
    280  | 
     | 
     | 
     | 
    
    
    281  | 
     | 
     | 
    	    case 'e':		/* -e	Exit on any error */  | 
    
    
    282  | 
     | 
     | 
    		exiterr = 1;  | 
    
    
    283  | 
     | 
     | 
    		break;  | 
    
    
    284  | 
     | 
     | 
     | 
    
    
    285  | 
     | 
     | 
    	    case 'f':		/* -f	Fast start */  | 
    
    
    286  | 
     | 
     | 
    		fast = 1;  | 
    
    
    287  | 
     | 
     | 
    		break;  | 
    
    
    288  | 
     | 
     | 
     | 
    
    
    289  | 
     | 
     | 
    	    case 'i':		/* -i	Interactive, even if !intty */  | 
    
    
    290  | 
     | 
     | 
    		intact = 1;  | 
    
    
    291  | 
     | 
     | 
    		nofile = 1;  | 
    
    
    292  | 
     | 
     | 
    		break;  | 
    
    
    293  | 
     | 
     | 
     | 
    
    
    294  | 
     | 
     | 
    	    case 'm':		/* -m	read .cshrc (from su) */  | 
    
    
    295  | 
     | 
     | 
    		mflag = 1;  | 
    
    
    296  | 
     | 
     | 
    		break;  | 
    
    
    297  | 
     | 
     | 
     | 
    
    
    298  | 
     | 
     | 
    	    case 'n':		/* -n	Don't execute */  | 
    
    
    299  | 
     | 
     | 
    		noexec = 1;  | 
    
    
    300  | 
     | 
     | 
    		break;  | 
    
    
    301  | 
     | 
     | 
     | 
    
    
    302  | 
     | 
     | 
    	    case 'q':		/* -q	(Undoc'd) ... die on quit */  | 
    
    
    303  | 
     | 
     | 
    		quitit = 1;  | 
    
    
    304  | 
     | 
     | 
    		break;  | 
    
    
    305  | 
     | 
     | 
     | 
    
    
    306  | 
     | 
     | 
    	    case 's':		/* -s	Read from std input */  | 
    
    
    307  | 
     | 
     | 
    		nofile = 1;  | 
    
    
    308  | 
     | 
     | 
    		break;  | 
    
    
    309  | 
     | 
     | 
     | 
    
    
    310  | 
     | 
     | 
    	    case 't':		/* -t	Read one line from input */  | 
    
    
    311  | 
     | 
     | 
    		onelflg = 2;  | 
    
    
    312  | 
     | 
     | 
    		prompt = 0;  | 
    
    
    313  | 
     | 
     | 
    		nofile = 1;  | 
    
    
    314  | 
     | 
     | 
    		break;  | 
    
    
    315  | 
     | 
     | 
     | 
    
    
    316  | 
     | 
     | 
    	    case 'v':		/* -v	Echo hist expanded input */  | 
    
    
    317  | 
     | 
     | 
    		nverbose = 1;	/* ... later */  | 
    
    
    318  | 
     | 
     | 
    		break;  | 
    
    
    319  | 
     | 
     | 
     | 
    
    
    320  | 
     | 
     | 
    	    case 'x':		/* -x	Echo just before execution */  | 
    
    
    321  | 
     | 
     | 
    		nexececho = 1;	/* ... later */  | 
    
    
    322  | 
     | 
     | 
    		break;  | 
    
    
    323  | 
     | 
     | 
     | 
    
    
    324  | 
     | 
     | 
    	    case 'V':		/* -V	Echo hist expanded input */  | 
    
    
    325  | 
     | 
     | 
    		setNS(STRverbose);	/* NOW! */  | 
    
    
    326  | 
     | 
     | 
    		break;  | 
    
    
    327  | 
     | 
     | 
     | 
    
    
    328  | 
     | 
     | 
    	    case 'X':		/* -X	Echo just before execution */  | 
    
    
    329  | 
     | 
     | 
    		setNS(STRecho);	/* NOW! */  | 
    
    
    330  | 
     | 
     | 
    		break;  | 
    
    
    331  | 
     | 
     | 
     | 
    
    
    332  | 
     | 
     | 
    	} while (*tcp);  | 
    
    
    333  | 
     | 
     | 
    	tempv++, argc--;  | 
    
    
    334  | 
     | 
     | 
        }  | 
    
    
    335  | 
     | 
     | 
     | 
    
    
    336  | 
     | 
     | 
        if (quitit)			/* With all due haste, for debugging */  | 
    
    
    337  | 
     | 
     | 
    	(void) signal(SIGQUIT, SIG_DFL);  | 
    
    
    338  | 
     | 
     | 
     | 
    
    
    339  | 
     | 
     | 
        /*  | 
    
    
    340  | 
     | 
     | 
         * Unless prevented by -, -c, -i, -s, or -t, if there are remaining  | 
    
    
    341  | 
     | 
     | 
         * arguments the first of them is the name of a shell file from which to  | 
    
    
    342  | 
     | 
     | 
         * read commands.  | 
    
    
    343  | 
     | 
     | 
         */  | 
    
    
    344  | 
     | 
     | 
        if (nofile == 0 && argc > 0) { | 
    
    
    345  | 
     | 
     | 
    	nofile = open(tempv[0], O_RDONLY);  | 
    
    
    346  | 
     | 
     | 
    	if (nofile < 0) { | 
    
    
    347  | 
     | 
     | 
    	    child = 1;		/* So this doesn't return */  | 
    
    
    348  | 
     | 
     | 
    	    stderror(ERR_SYSTEM, tempv[0], strerror(errno));  | 
    
    
    349  | 
     | 
     | 
    	}  | 
    
    
    350  | 
     | 
     | 
    	ffile = SAVE(tempv[0]);  | 
    
    
    351  | 
     | 
     | 
    	/*  | 
    
    
    352  | 
     | 
     | 
    	 * Replace FSHIN. Handle /dev/std{in,out,err} specially | 
    
    
    353  | 
     | 
     | 
    	 * since once they are closed we cannot open them again.  | 
    
    
    354  | 
     | 
     | 
    	 * In that case we use our own saved descriptors  | 
    
    
    355  | 
     | 
     | 
    	 */  | 
    
    
    356  | 
     | 
     | 
    	if ((SHIN = dmove(nofile, FSHIN)) < 0)  | 
    
    
    357  | 
     | 
     | 
    	    switch(nofile) { | 
    
    
    358  | 
     | 
     | 
    	    case 0:  | 
    
    
    359  | 
     | 
     | 
    		SHIN = FSHIN;  | 
    
    
    360  | 
     | 
     | 
    		break;  | 
    
    
    361  | 
     | 
     | 
    	    case 1:  | 
    
    
    362  | 
     | 
     | 
    		SHIN = FSHOUT;  | 
    
    
    363  | 
     | 
     | 
    		break;  | 
    
    
    364  | 
     | 
     | 
    	    case 2:  | 
    
    
    365  | 
     | 
     | 
    		SHIN = FSHERR;  | 
    
    
    366  | 
     | 
     | 
    		break;  | 
    
    
    367  | 
     | 
     | 
    	    default:  | 
    
    
    368  | 
     | 
     | 
    		stderror(ERR_SYSTEM, tempv[0], strerror(errno));  | 
    
    
    369  | 
     | 
     | 
    		break;  | 
    
    
    370  | 
     | 
     | 
    	    }  | 
    
    
    371  | 
     | 
     | 
    	(void) fcntl(SHIN, F_SETFD, FD_CLOEXEC);  | 
    
    
    372  | 
     | 
     | 
    	prompt = 0;  | 
    
    
    373  | 
     | 
     | 
    	 /* argc not used any more */ tempv++;  | 
    
    
    374  | 
     | 
     | 
        }  | 
    
    
    375  | 
     | 
     | 
     | 
    
    
    376  | 
     | 
     | 
        intty = isatty(SHIN);  | 
    
    
    377  | 
     | 
     | 
        intty |= intact;  | 
    
    
    378  | 
     | 
     | 
        if (intty || (intact && isatty(SHOUT))) { | 
    
    
    379  | 
     | 
     | 
    	if (!batch && (uid != euid || gid != egid)) { | 
    
    
    380  | 
     | 
     | 
    	    errno = EACCES;  | 
    
    
    381  | 
     | 
     | 
    	    child = 1;		/* So this doesn't return */  | 
    
    
    382  | 
     | 
     | 
    	    stderror(ERR_SYSTEM, "csh", strerror(errno));  | 
    
    
    383  | 
     | 
     | 
    	}  | 
    
    
    384  | 
     | 
     | 
        }  | 
    
    
    385  | 
     | 
     | 
        /*  | 
    
    
    386  | 
     | 
     | 
         * Decide whether we should play with signals or not. If we are explicitly  | 
    
    
    387  | 
     | 
     | 
         * told (via -i, or -) or we are a login shell (arg0 starts with -) or the  | 
    
    
    388  | 
     | 
     | 
         * input and output are both the ttys("csh", or "csh</dev/ttyx>/dev/ttyx") | 
    
    
    389  | 
     | 
     | 
         * Note that in only the login shell is it likely that parent may have set  | 
    
    
    390  | 
     | 
     | 
         * signals to be ignored  | 
    
    
    391  | 
     | 
     | 
         */  | 
    
    
    392  | 
     | 
     | 
        if (loginsh || intact || (intty && isatty(SHOUT)))  | 
    
    
    393  | 
     | 
     | 
    	setintr = 1;  | 
    
    
    394  | 
     | 
     | 
        settell();  | 
    
    
    395  | 
     | 
     | 
        /*  | 
    
    
    396  | 
     | 
     | 
         * Save the remaining arguments in argv.  | 
    
    
    397  | 
     | 
     | 
         */  | 
    
    
    398  | 
     | 
     | 
        setq(STRargv, blk2short(tempv), &shvhed);  | 
    
    
    399  | 
     | 
     | 
     | 
    
    
    400  | 
     | 
     | 
        /*  | 
    
    
    401  | 
     | 
     | 
         * Set up the prompt.  | 
    
    
    402  | 
     | 
     | 
         */  | 
    
    
    403  | 
     | 
     | 
        if (prompt) { | 
    
    
    404  | 
     | 
     | 
    	set(STRprompt, Strsave(uid == 0 ? STRsymhash : STRsymcent));  | 
    
    
    405  | 
     | 
     | 
    	/* that's a meta-questionmark */  | 
    
    
    406  | 
     | 
     | 
    	set(STRprompt2, Strsave(STRmquestion));  | 
    
    
    407  | 
     | 
     | 
        }  | 
    
    
    408  | 
     | 
     | 
     | 
    
    
    409  | 
     | 
     | 
        /*  | 
    
    
    410  | 
     | 
     | 
         * If we are an interactive shell, then start fiddling with the signals;  | 
    
    
    411  | 
     | 
     | 
         * this is a tricky game.  | 
    
    
    412  | 
     | 
     | 
         */  | 
    
    
    413  | 
     | 
     | 
        shpgrp = getpgrp();  | 
    
    
    414  | 
     | 
     | 
        opgrp = tpgrp = -1;  | 
    
    
    415  | 
     | 
     | 
        if (setintr) { | 
    
    
    416  | 
     | 
     | 
    	**argv = '-';  | 
    
    
    417  | 
     | 
     | 
    	if (!quitit)		/* Wary! */  | 
    
    
    418  | 
     | 
     | 
    	    (void) signal(SIGQUIT, SIG_IGN);  | 
    
    
    419  | 
     | 
     | 
    	(void) signal(SIGINT, pintr);  | 
    
    
    420  | 
     | 
     | 
    	sigemptyset(&sigset);  | 
    
    
    421  | 
     | 
     | 
    	sigaddset(&sigset, SIGINT);  | 
    
    
    422  | 
     | 
     | 
    	sigprocmask(SIG_BLOCK, &sigset, NULL);  | 
    
    
    423  | 
     | 
     | 
    	(void) signal(SIGTERM, SIG_IGN);  | 
    
    
    424  | 
     | 
     | 
    	if (quitit == 0 && arginp == 0) { | 
    
    
    425  | 
     | 
     | 
    	    (void) signal(SIGTSTP, SIG_IGN);  | 
    
    
    426  | 
     | 
     | 
    	    (void) signal(SIGTTIN, SIG_IGN);  | 
    
    
    427  | 
     | 
     | 
    	    (void) signal(SIGTTOU, SIG_IGN);  | 
    
    
    428  | 
     | 
     | 
    	    /*  | 
    
    
    429  | 
     | 
     | 
    	     * Wait till in foreground, in case someone stupidly runs csh &  | 
    
    
    430  | 
     | 
     | 
    	     * dont want to try to grab away the tty.  | 
    
    
    431  | 
     | 
     | 
    	     */  | 
    
    
    432  | 
     | 
     | 
    	    if (isatty(FSHERR))  | 
    
    
    433  | 
     | 
     | 
    		f = FSHERR;  | 
    
    
    434  | 
     | 
     | 
    	    else if (isatty(FSHOUT))  | 
    
    
    435  | 
     | 
     | 
    		f = FSHOUT;  | 
    
    
    436  | 
     | 
     | 
    	    else if (isatty(OLDSTD))  | 
    
    
    437  | 
     | 
     | 
    		f = OLDSTD;  | 
    
    
    438  | 
     | 
     | 
    	    else  | 
    
    
    439  | 
     | 
     | 
    		f = -1;  | 
    
    
    440  | 
     | 
     | 
        retry:  | 
    
    
    441  | 
     | 
     | 
    	    if ((tpgrp = tcgetpgrp(f)) != -1) { | 
    
    
    442  | 
     | 
     | 
    		if (tpgrp != shpgrp) { | 
    
    
    443  | 
     | 
     | 
    		    sig_t old = signal(SIGTTIN, SIG_DFL);  | 
    
    
    444  | 
     | 
     | 
    		    (void) kill(0, SIGTTIN);  | 
    
    
    445  | 
     | 
     | 
    		    (void) signal(SIGTTIN, old);  | 
    
    
    446  | 
     | 
     | 
    		    goto retry;  | 
    
    
    447  | 
     | 
     | 
    		}  | 
    
    
    448  | 
     | 
     | 
    		opgrp = shpgrp;  | 
    
    
    449  | 
     | 
     | 
    		shpgrp = getpid();  | 
    
    
    450  | 
     | 
     | 
    		tpgrp = shpgrp;  | 
    
    
    451  | 
     | 
     | 
    		/*  | 
    
    
    452  | 
     | 
     | 
    		 * Setpgid will fail if we are a session leader and  | 
    
    
    453  | 
     | 
     | 
    		 * mypid == mypgrp (POSIX 4.3.3)  | 
    
    
    454  | 
     | 
     | 
    		 */  | 
    
    
    455  | 
     | 
     | 
    		if (opgrp != shpgrp)  | 
    
    
    456  | 
     | 
     | 
    		    if (setpgid(0, shpgrp) == -1)  | 
    
    
    457  | 
     | 
     | 
    			goto notty;  | 
    
    
    458  | 
     | 
     | 
    		/*  | 
    
    
    459  | 
     | 
     | 
    		 * We do that after we set our process group, to make sure  | 
    
    
    460  | 
     | 
     | 
    		 * that the process group belongs to a process in the same  | 
    
    
    461  | 
     | 
     | 
    		 * session as the tty (our process and our group) (POSIX 7.2.4)  | 
    
    
    462  | 
     | 
     | 
    		 */  | 
    
    
    463  | 
     | 
     | 
    		if (tcsetpgrp(f, shpgrp) == -1)  | 
    
    
    464  | 
     | 
     | 
    		    goto notty;  | 
    
    
    465  | 
     | 
     | 
    		(void) fcntl(dcopy(f, FSHTTY), F_SETFD, FD_CLOEXEC);  | 
    
    
    466  | 
     | 
     | 
    	    }  | 
    
    
    467  | 
     | 
     | 
    	    if (tpgrp == -1) { | 
    
    
    468  | 
     | 
     | 
    notty:  | 
    
    
    469  | 
     | 
     | 
    		(void) fprintf(csherr, "Warning: no access to tty (%s).\n",  | 
    
    
    470  | 
     | 
     | 
    			       strerror(errno));  | 
    
    
    471  | 
     | 
     | 
    		(void) fprintf(csherr, "Thus no job control in this shell.\n");  | 
    
    
    472  | 
     | 
     | 
    	    }  | 
    
    
    473  | 
     | 
     | 
    	}  | 
    
    
    474  | 
     | 
     | 
        }  | 
    
    
    475  | 
     | 
     | 
        if ((setintr == 0) && (parintr == SIG_DFL))  | 
    
    
    476  | 
     | 
     | 
    	setintr = 1;  | 
    
    
    477  | 
     | 
     | 
        (void) signal(SIGCHLD, pchild);	/* while signals not ready */  | 
    
    
    478  | 
     | 
     | 
     | 
    
    
    479  | 
     | 
     | 
        /*  | 
    
    
    480  | 
     | 
     | 
         * Set an exit here in case of an interrupt or error reading the shell  | 
    
    
    481  | 
     | 
     | 
         * start-up scripts.  | 
    
    
    482  | 
     | 
     | 
         */  | 
    
    
    483  | 
     | 
     | 
        reenter = setexit();	/* PWP */  | 
    
    
    484  | 
     | 
     | 
        exitset++;  | 
    
    
    485  | 
     | 
     | 
        haderr = 0;			/* In case second time through */  | 
    
    
    486  | 
     | 
     | 
        if (!fast && reenter == 0) { | 
    
    
    487  | 
     | 
     | 
    	/* Will have value(STRhome) here because set fast if don't */  | 
    
    
    488  | 
     | 
     | 
    	{ | 
    
    
    489  | 
     | 
     | 
    	    int     osetintr = setintr;  | 
    
    
    490  | 
     | 
     | 
    	    sig_t   oparintr = parintr;  | 
    
    
    491  | 
     | 
     | 
    	    sigset_t osigset;  | 
    
    
    492  | 
     | 
     | 
     | 
    
    
    493  | 
     | 
     | 
    	    sigemptyset(&sigset);  | 
    
    
    494  | 
     | 
     | 
    	    sigaddset(&sigset, SIGINT);  | 
    
    
    495  | 
     | 
     | 
    	    sigprocmask(SIG_BLOCK, &sigset, &osigset);  | 
    
    
    496  | 
     | 
     | 
     | 
    
    
    497  | 
     | 
     | 
    	    setintr = 0;  | 
    
    
    498  | 
     | 
     | 
    	    parintr = SIG_IGN;	/* Disable onintr */  | 
    
    
    499  | 
     | 
     | 
    	    (void) srcfile(_PATH_DOTCSHRC, 0, 0);  | 
    
    
    500  | 
     | 
     | 
    	    if (!fast && !arginp && !onelflg)  | 
    
    
    501  | 
     | 
     | 
    		dohash(NULL, NULL);  | 
    
    
    502  | 
     | 
     | 
    	    if (loginsh)  | 
    
    
    503  | 
     | 
     | 
    		(void) srcfile(_PATH_DOTLOGIN, 0, 0);  | 
    
    
    504  | 
     | 
     | 
    	    sigprocmask(SIG_SETMASK, &osigset, NULL);  | 
    
    
    505  | 
     | 
     | 
    	    setintr = osetintr;  | 
    
    
    506  | 
     | 
     | 
    	    parintr = oparintr;  | 
    
    
    507  | 
     | 
     | 
    	}  | 
    
    
    508  | 
     | 
     | 
    	(void) srccat(value(STRhome), STRsldotcshrc);  | 
    
    
    509  | 
     | 
     | 
     | 
    
    
    510  | 
     | 
     | 
    	if (!fast && !arginp && !onelflg && !havhash)  | 
    
    
    511  | 
     | 
     | 
    	    dohash(NULL, NULL);  | 
    
    
    512  | 
     | 
     | 
    	/*  | 
    
    
    513  | 
     | 
     | 
    	 * Source history before .login so that it is available in .login  | 
    
    
    514  | 
     | 
     | 
    	 */  | 
    
    
    515  | 
     | 
     | 
    	if ((cp = value(STRhistfile)) != STRNULL)  | 
    
    
    516  | 
     | 
     | 
    	    loadhist[2] = cp;  | 
    
    
    517  | 
     | 
     | 
    	dosource(loadhist, NULL);  | 
    
    
    518  | 
     | 
     | 
    	if (loginsh)  | 
    
    
    519  | 
     | 
     | 
    	      (void) srccat(value(STRhome), STRsldotlogin);  | 
    
    
    520  | 
     | 
     | 
        }  | 
    
    
    521  | 
     | 
     | 
     | 
    
    
    522  | 
     | 
     | 
        /*  | 
    
    
    523  | 
     | 
     | 
         * Now are ready for the -v and -x flags  | 
    
    
    524  | 
     | 
     | 
         */  | 
    
    
    525  | 
     | 
     | 
        if (nverbose)  | 
    
    
    526  | 
     | 
     | 
    	setNS(STRverbose);  | 
    
    
    527  | 
     | 
     | 
        if (nexececho)  | 
    
    
    528  | 
     | 
     | 
    	setNS(STRecho);  | 
    
    
    529  | 
     | 
     | 
     | 
    
    
    530  | 
     | 
     | 
        /*  | 
    
    
    531  | 
     | 
     | 
         * All the rest of the world is inside this call. The argument to process  | 
    
    
    532  | 
     | 
     | 
         * indicates whether it should catch "error unwinds".  Thus if we are a  | 
    
    
    533  | 
     | 
     | 
         * interactive shell our call here will never return by being blown past on  | 
    
    
    534  | 
     | 
     | 
         * an error.  | 
    
    
    535  | 
     | 
     | 
         */  | 
    
    
    536  | 
     | 
     | 
        process(setintr);  | 
    
    
    537  | 
     | 
     | 
     | 
    
    
    538  | 
     | 
     | 
        /*  | 
    
    
    539  | 
     | 
     | 
         * Mop-up.  | 
    
    
    540  | 
     | 
     | 
         */  | 
    
    
    541  | 
     | 
     | 
        if (intty) { | 
    
    
    542  | 
     | 
     | 
    	if (loginsh) { | 
    
    
    543  | 
     | 
     | 
    	    (void) fprintf(cshout, "logout\n");  | 
    
    
    544  | 
     | 
     | 
    	    (void) close(SHIN);  | 
    
    
    545  | 
     | 
     | 
    	    child = 1;  | 
    
    
    546  | 
     | 
     | 
    	    goodbye();  | 
    
    
    547  | 
     | 
     | 
    	}  | 
    
    
    548  | 
     | 
     | 
    	else { | 
    
    
    549  | 
     | 
     | 
    	    (void) fprintf(cshout, "exit\n");  | 
    
    
    550  | 
     | 
     | 
    	}  | 
    
    
    551  | 
     | 
     | 
        }  | 
    
    
    552  | 
     | 
     | 
        rechist();  | 
    
    
    553  | 
     | 
     | 
        exitstat();  | 
    
    
    554  | 
     | 
     | 
        return (0);  | 
    
    
    555  | 
     | 
     | 
    }  | 
    
    
    556  | 
     | 
     | 
     | 
    
    
    557  | 
     | 
     | 
    void  | 
    
    
    558  | 
     | 
     | 
    untty(void)  | 
    
    
    559  | 
     | 
     | 
    { | 
    
    
    560  | 
     | 
     | 
        if (tpgrp > 0) { | 
    
    
    561  | 
     | 
     | 
    	(void) setpgid(0, opgrp);  | 
    
    
    562  | 
     | 
     | 
    	(void) tcsetpgrp(FSHTTY, opgrp);  | 
    
    
    563  | 
     | 
     | 
        }  | 
    
    
    564  | 
     | 
     | 
    }  | 
    
    
    565  | 
     | 
     | 
     | 
    
    
    566  | 
     | 
     | 
    void  | 
    
    
    567  | 
     | 
     | 
    importpath(Char *cp)  | 
    
    
    568  | 
     | 
     | 
    { | 
    
    
    569  | 
     | 
     | 
        int i = 0;  | 
    
    
    570  | 
     | 
     | 
        Char *dp;  | 
    
    
    571  | 
     | 
     | 
        Char **pv;  | 
    
    
    572  | 
     | 
     | 
        int     c;  | 
    
    
    573  | 
     | 
     | 
     | 
    
    
    574  | 
     | 
     | 
        for (dp = cp; *dp; dp++)  | 
    
    
    575  | 
     | 
     | 
    	if (*dp == ':')  | 
    
    
    576  | 
     | 
     | 
    	    i++;  | 
    
    
    577  | 
     | 
     | 
        /*  | 
    
    
    578  | 
     | 
     | 
         * i+2 where i is the number of colons in the path. There are i+1  | 
    
    
    579  | 
     | 
     | 
         * directories in the path plus we need room for a zero terminator.  | 
    
    
    580  | 
     | 
     | 
         */  | 
    
    
    581  | 
     | 
     | 
        pv = (Char **) xcalloc((size_t) (i + 2), sizeof(Char **));  | 
    
    
    582  | 
     | 
     | 
        dp = cp;  | 
    
    
    583  | 
     | 
     | 
        i = 0;  | 
    
    
    584  | 
     | 
     | 
        if (*dp)  | 
    
    
    585  | 
     | 
     | 
    	for (;;) { | 
    
    
    586  | 
     | 
     | 
    	    if ((c = *dp) == ':' || c == 0) { | 
    
    
    587  | 
     | 
     | 
    		*dp = 0;  | 
    
    
    588  | 
     | 
     | 
    		pv[i++] = Strsave(*cp ? cp : STRdot);  | 
    
    
    589  | 
     | 
     | 
    		if (c) { | 
    
    
    590  | 
     | 
     | 
    		    cp = dp + 1;  | 
    
    
    591  | 
     | 
     | 
    		    *dp = ':';  | 
    
    
    592  | 
     | 
     | 
    		}  | 
    
    
    593  | 
     | 
     | 
    		else  | 
    
    
    594  | 
     | 
     | 
    		    break;  | 
    
    
    595  | 
     | 
     | 
    	    }  | 
    
    
    596  | 
     | 
     | 
    	    dp++;  | 
    
    
    597  | 
     | 
     | 
    	}  | 
    
    
    598  | 
     | 
     | 
        pv[i] = 0;  | 
    
    
    599  | 
     | 
     | 
        setq(STRpath, pv, &shvhed);  | 
    
    
    600  | 
     | 
     | 
    }  | 
    
    
    601  | 
     | 
     | 
     | 
    
    
    602  | 
     | 
     | 
    /*  | 
    
    
    603  | 
     | 
     | 
     * Source to the file which is the catenation of the argument names.  | 
    
    
    604  | 
     | 
     | 
     */  | 
    
    
    605  | 
     | 
     | 
    static int  | 
    
    
    606  | 
     | 
     | 
    srccat(Char *cp, Char *dp)  | 
    
    
    607  | 
     | 
     | 
    { | 
    
    
    608  | 
     | 
     | 
        Char *ep = Strspl(cp, dp);  | 
    
    
    609  | 
     | 
     | 
        char   *ptr = short2str(ep);  | 
    
    
    610  | 
     | 
     | 
     | 
    
    
    611  | 
     | 
     | 
        free(ep);  | 
    
    
    612  | 
     | 
     | 
        return srcfile(ptr, mflag ? 0 : 1, 0);  | 
    
    
    613  | 
     | 
     | 
    }  | 
    
    
    614  | 
     | 
     | 
     | 
    
    
    615  | 
     | 
     | 
    /*  | 
    
    
    616  | 
     | 
     | 
     * Source to a file putting the file descriptor in a safe place (> 2).  | 
    
    
    617  | 
     | 
     | 
     */  | 
    
    
    618  | 
     | 
     | 
    static int  | 
    
    
    619  | 
     | 
     | 
    srcfile(char *f, bool onlyown, bool flag)  | 
    
    
    620  | 
     | 
     | 
    { | 
    
    
    621  | 
     | 
     | 
        int unit;  | 
    
    
    622  | 
     | 
     | 
     | 
    
    
    623  | 
     | 
     | 
        if ((unit = open(f, O_RDONLY)) == -1)  | 
    
    
    624  | 
     | 
     | 
    	return 0;  | 
    
    
    625  | 
     | 
     | 
        unit = dmove(unit, -1);  | 
    
    
    626  | 
     | 
     | 
     | 
    
    
    627  | 
     | 
     | 
        (void) fcntl(unit, F_SETFD, FD_CLOEXEC);  | 
    
    
    628  | 
     | 
     | 
        srcunit(unit, onlyown, flag);  | 
    
    
    629  | 
     | 
     | 
        return 1;  | 
    
    
    630  | 
     | 
     | 
    }  | 
    
    
    631  | 
     | 
     | 
     | 
    
    
    632  | 
     | 
     | 
    /*  | 
    
    
    633  | 
     | 
     | 
     * Source to a unit.  If onlyown it must be our file or our group or  | 
    
    
    634  | 
     | 
     | 
     * we don't chance it.	This occurs on ".cshrc"s and the like.  | 
    
    
    635  | 
     | 
     | 
     */  | 
    
    
    636  | 
     | 
     | 
    int     insource;  | 
    
    
    637  | 
     | 
     | 
    static void  | 
    
    
    638  | 
     | 
     | 
    srcunit(int unit, bool onlyown, bool hflg)  | 
    
    
    639  | 
     | 
     | 
    { | 
    
    
    640  | 
     | 
     | 
        /* We have to push down a lot of state here */  | 
    
    
    641  | 
     | 
     | 
        /* All this could go into a structure */  | 
    
    
    642  | 
     | 
     | 
        int     oSHIN = -1, oldintty = intty, oinsource = insource;  | 
    
    
    643  | 
     | 
     | 
        struct whyle *oldwhyl = whyles;  | 
    
    
    644  | 
     | 
     | 
        Char   *ogointr = gointr, *oarginp = arginp;  | 
    
    
    645  | 
     | 
     | 
        Char   *oevalp = evalp, **oevalvec = evalvec;  | 
    
    
    646  | 
     | 
     | 
        int     oonelflg = onelflg;  | 
    
    
    647  | 
     | 
     | 
        bool    oenterhist = enterhist;  | 
    
    
    648  | 
     | 
     | 
        char    OHIST = HIST;  | 
    
    
    649  | 
     | 
     | 
        bool    otell = cantell;  | 
    
    
    650  | 
     | 
     | 
     | 
    
    
    651  | 
     | 
     | 
        struct Bin saveB;  | 
    
    
    652  | 
     | 
     | 
        sigset_t sigset, osigset;  | 
    
    
    653  | 
     | 
     | 
        jmp_buf oldexit;  | 
    
    
    654  | 
     | 
     | 
     | 
    
    
    655  | 
     | 
     | 
        /* The (few) real local variables */  | 
    
    
    656  | 
     | 
     | 
        int     my_reenter;  | 
    
    
    657  | 
     | 
     | 
     | 
    
    
    658  | 
     | 
     | 
        if (unit < 0)  | 
    
    
    659  | 
     | 
     | 
    	return;  | 
    
    
    660  | 
     | 
     | 
        if (didfds)  | 
    
    
    661  | 
     | 
     | 
    	donefds();  | 
    
    
    662  | 
     | 
     | 
        if (onlyown) { | 
    
    
    663  | 
     | 
     | 
    	struct stat stb;  | 
    
    
    664  | 
     | 
     | 
     | 
    
    
    665  | 
     | 
     | 
    	if (fstat(unit, &stb) < 0) { | 
    
    
    666  | 
     | 
     | 
    	    (void) close(unit);  | 
    
    
    667  | 
     | 
     | 
    	    return;  | 
    
    
    668  | 
     | 
     | 
    	}  | 
    
    
    669  | 
     | 
     | 
        }  | 
    
    
    670  | 
     | 
     | 
     | 
    
    
    671  | 
     | 
     | 
        /*  | 
    
    
    672  | 
     | 
     | 
         * There is a critical section here while we are pushing down the input  | 
    
    
    673  | 
     | 
     | 
         * stream since we have stuff in different structures. If we weren't  | 
    
    
    674  | 
     | 
     | 
         * careful an interrupt could corrupt SHIN's Bin structure and kill the  | 
    
    
    675  | 
     | 
     | 
         * shell.  | 
    
    
    676  | 
     | 
     | 
         *  | 
    
    
    677  | 
     | 
     | 
         * We could avoid the critical region by grouping all the stuff in a single  | 
    
    
    678  | 
     | 
     | 
         * structure and pointing at it to move it all at once.  This is less  | 
    
    
    679  | 
     | 
     | 
         * efficient globally on many variable references however.  | 
    
    
    680  | 
     | 
     | 
         */  | 
    
    
    681  | 
     | 
     | 
        insource = 1;  | 
    
    
    682  | 
     | 
     | 
        getexit(oldexit);  | 
    
    
    683  | 
     | 
     | 
     | 
    
    
    684  | 
     | 
     | 
        if (setintr) { | 
    
    
    685  | 
     | 
     | 
    	sigemptyset(&sigset);  | 
    
    
    686  | 
     | 
     | 
    	sigaddset(&sigset, SIGINT);  | 
    
    
    687  | 
     | 
     | 
    	sigprocmask(SIG_BLOCK, &sigset, &osigset);  | 
    
    
    688  | 
     | 
     | 
        }  | 
    
    
    689  | 
     | 
     | 
        /* Setup the new values of the state stuff saved above */  | 
    
    
    690  | 
     | 
     | 
        memcpy(&saveB, &B, sizeof(B));  | 
    
    
    691  | 
     | 
     | 
        fbuf = NULL;  | 
    
    
    692  | 
     | 
     | 
        fseekp = feobp = fblocks = 0;  | 
    
    
    693  | 
     | 
     | 
        oSHIN = SHIN, SHIN = unit, arginp = 0, onelflg = 0;  | 
    
    
    694  | 
     | 
     | 
        intty = isatty(SHIN), whyles = 0, gointr = 0;  | 
    
    
    695  | 
     | 
     | 
        evalvec = 0;  | 
    
    
    696  | 
     | 
     | 
        evalp = 0;  | 
    
    
    697  | 
     | 
     | 
        enterhist = hflg;  | 
    
    
    698  | 
     | 
     | 
        if (enterhist)  | 
    
    
    699  | 
     | 
     | 
    	HIST = '\0';  | 
    
    
    700  | 
     | 
     | 
     | 
    
    
    701  | 
     | 
     | 
        /*  | 
    
    
    702  | 
     | 
     | 
         * Now if we are allowing commands to be interrupted, we let ourselves be  | 
    
    
    703  | 
     | 
     | 
         * interrupted.  | 
    
    
    704  | 
     | 
     | 
         */  | 
    
    
    705  | 
     | 
     | 
        if (setintr)  | 
    
    
    706  | 
     | 
     | 
    	sigprocmask(SIG_SETMASK, &osigset, NULL);  | 
    
    
    707  | 
     | 
     | 
        settell();  | 
    
    
    708  | 
     | 
     | 
     | 
    
    
    709  | 
     | 
     | 
        if ((my_reenter = setexit()) == 0)  | 
    
    
    710  | 
     | 
     | 
    	process(0);		/* 0 -> blow away on errors */  | 
    
    
    711  | 
     | 
     | 
     | 
    
    
    712  | 
     | 
     | 
        if (setintr)  | 
    
    
    713  | 
     | 
     | 
    	sigprocmask(SIG_SETMASK, &osigset, NULL);  | 
    
    
    714  | 
     | 
     | 
        if (oSHIN >= 0) { | 
    
    
    715  | 
     | 
     | 
    	int i;  | 
    
    
    716  | 
     | 
     | 
     | 
    
    
    717  | 
     | 
     | 
    	/* We made it to the new state... free up its storage */  | 
    
    
    718  | 
     | 
     | 
    	/* This code could get run twice but free doesn't care */  | 
    
    
    719  | 
     | 
     | 
    	for (i = 0; i < fblocks; i++)  | 
    
    
    720  | 
     | 
     | 
    	    free(fbuf[i]);  | 
    
    
    721  | 
     | 
     | 
    	free(fbuf);  | 
    
    
    722  | 
     | 
     | 
     | 
    
    
    723  | 
     | 
     | 
    	/* Reset input arena */  | 
    
    
    724  | 
     | 
     | 
    	memcpy(&B, &saveB, sizeof(B));  | 
    
    
    725  | 
     | 
     | 
     | 
    
    
    726  | 
     | 
     | 
    	(void) close(SHIN), SHIN = oSHIN;  | 
    
    
    727  | 
     | 
     | 
    	arginp = oarginp, onelflg = oonelflg;  | 
    
    
    728  | 
     | 
     | 
    	evalp = oevalp, evalvec = oevalvec;  | 
    
    
    729  | 
     | 
     | 
    	intty = oldintty, whyles = oldwhyl, gointr = ogointr;  | 
    
    
    730  | 
     | 
     | 
    	if (enterhist)  | 
    
    
    731  | 
     | 
     | 
    	    HIST = OHIST;  | 
    
    
    732  | 
     | 
     | 
    	enterhist = oenterhist;  | 
    
    
    733  | 
     | 
     | 
    	cantell = otell;  | 
    
    
    734  | 
     | 
     | 
        }  | 
    
    
    735  | 
     | 
     | 
     | 
    
    
    736  | 
     | 
     | 
        resexit(oldexit);  | 
    
    
    737  | 
     | 
     | 
        /*  | 
    
    
    738  | 
     | 
     | 
         * If process reset() (effectively an unwind) then we must also unwind.  | 
    
    
    739  | 
     | 
     | 
         */  | 
    
    
    740  | 
     | 
     | 
        if (my_reenter)  | 
    
    
    741  | 
     | 
     | 
    	stderror(ERR_SILENT);  | 
    
    
    742  | 
     | 
     | 
        insource = oinsource;  | 
    
    
    743  | 
     | 
     | 
    }  | 
    
    
    744  | 
     | 
     | 
     | 
    
    
    745  | 
     | 
     | 
    void  | 
    
    
    746  | 
     | 
     | 
    rechist(void)  | 
    
    
    747  | 
     | 
     | 
    { | 
    
    
    748  | 
     | 
     | 
        Char    buf[BUFSIZ], hbuf[BUFSIZ], *hfile;  | 
    
    
    749  | 
     | 
     | 
        int     fd, ftmp, oldidfds;  | 
    
    
    750  | 
     | 
     | 
        struct  varent *shist;  | 
    
    
    751  | 
     | 
     | 
     | 
    
    
    752  | 
     | 
     | 
        if (!fast) { | 
    
    
    753  | 
     | 
     | 
    	/*  | 
    
    
    754  | 
     | 
     | 
    	 * If $savehist is just set, we use the value of $history  | 
    
    
    755  | 
     | 
     | 
    	 * else we use the value in $savehist  | 
    
    
    756  | 
     | 
     | 
    	 */  | 
    
    
    757  | 
     | 
     | 
    	if ((shist = adrof(STRsavehist)) != NULL) { | 
    
    
    758  | 
     | 
     | 
    	    if (shist->vec[0][0] != '\0')  | 
    
    
    759  | 
     | 
     | 
    		(void) Strlcpy(hbuf, shist->vec[0], sizeof hbuf/sizeof(Char));  | 
    
    
    760  | 
     | 
     | 
    	    else if ((shist = adrof(STRhistory)) && shist->vec[0][0] != '\0')  | 
    
    
    761  | 
     | 
     | 
    		(void) Strlcpy(hbuf, shist->vec[0], sizeof hbuf/sizeof(Char));  | 
    
    
    762  | 
     | 
     | 
    	    else  | 
    
    
    763  | 
     | 
     | 
    		return;  | 
    
    
    764  | 
     | 
     | 
    	}  | 
    
    
    765  | 
     | 
     | 
    	else  | 
    
    
    766  | 
     | 
     | 
    	    return;  | 
    
    
    767  | 
     | 
     | 
     | 
    
    
    768  | 
     | 
     | 
    	if ((hfile = value(STRhistfile)) == STRNULL) { | 
    
    
    769  | 
     | 
     | 
    	    Strlcpy(buf, value(STRhome), sizeof buf/sizeof(Char));  | 
    
    
    770  | 
     | 
     | 
    	    hfile = buf;  | 
    
    
    771  | 
     | 
     | 
    	    (void) Strlcat(buf, STRsldthist, sizeof buf/sizeof(Char));  | 
    
    
    772  | 
     | 
     | 
    	}  | 
    
    
    773  | 
     | 
     | 
     | 
    
    
    774  | 
     | 
     | 
    	if ((fd = open(short2str(hfile), O_WRONLY | O_CREAT | O_TRUNC,  | 
    
    
    775  | 
     | 
     | 
    	    0600)) == -1)  | 
    
    
    776  | 
     | 
     | 
    	    return;  | 
    
    
    777  | 
     | 
     | 
     | 
    
    
    778  | 
     | 
     | 
    	oldidfds = didfds;  | 
    
    
    779  | 
     | 
     | 
    	didfds = 0;  | 
    
    
    780  | 
     | 
     | 
    	ftmp = SHOUT;  | 
    
    
    781  | 
     | 
     | 
    	SHOUT = fd;  | 
    
    
    782  | 
     | 
     | 
    	dumphist[2] = hbuf;  | 
    
    
    783  | 
     | 
     | 
    	dohist(dumphist, NULL);  | 
    
    
    784  | 
     | 
     | 
    	SHOUT = ftmp;  | 
    
    
    785  | 
     | 
     | 
    	(void) close(fd);  | 
    
    
    786  | 
     | 
     | 
    	didfds = oldidfds;  | 
    
    
    787  | 
     | 
     | 
        }  | 
    
    
    788  | 
     | 
     | 
    }  | 
    
    
    789  | 
     | 
     | 
     | 
    
    
    790  | 
     | 
     | 
    void  | 
    
    
    791  | 
     | 
     | 
    goodbye(void)  | 
    
    
    792  | 
     | 
     | 
    { | 
    
    
    793  | 
     | 
     | 
        rechist();  | 
    
    
    794  | 
     | 
     | 
     | 
    
    
    795  | 
     | 
     | 
        if (loginsh) { | 
    
    
    796  | 
     | 
     | 
    	(void) signal(SIGQUIT, SIG_IGN);  | 
    
    
    797  | 
     | 
     | 
    	(void) signal(SIGINT, SIG_IGN);  | 
    
    
    798  | 
     | 
     | 
    	(void) signal(SIGTERM, SIG_IGN);  | 
    
    
    799  | 
     | 
     | 
    	setintr = 0;		/* No interrupts after "logout" */  | 
    
    
    800  | 
     | 
     | 
    	if (!(adrof(STRlogout)))  | 
    
    
    801  | 
     | 
     | 
    	    set(STRlogout, STRnormal);  | 
    
    
    802  | 
     | 
     | 
    	(void) srcfile(_PATH_DOTLOGOUT, 0, 0);  | 
    
    
    803  | 
     | 
     | 
    	if (adrof(STRhome))  | 
    
    
    804  | 
     | 
     | 
    	    (void) srccat(value(STRhome), STRsldtlogout);  | 
    
    
    805  | 
     | 
     | 
        }  | 
    
    
    806  | 
     | 
     | 
        exitstat();  | 
    
    
    807  | 
     | 
     | 
    }  | 
    
    
    808  | 
     | 
     | 
     | 
    
    
    809  | 
     | 
     | 
    void  | 
    
    
    810  | 
     | 
     | 
    exitstat(void)  | 
    
    
    811  | 
     | 
     | 
    { | 
    
    
    812  | 
     | 
     | 
        Char *s;  | 
    
    
    813  | 
     | 
     | 
        /*  | 
    
    
    814  | 
     | 
     | 
         * Note that if STATUS is corrupted (i.e. getn bombs) then error will exit  | 
    
    
    815  | 
     | 
     | 
         * directly because we poke child here. Otherwise we might continue  | 
    
    
    816  | 
     | 
     | 
         * unwarrantedly (sic).  | 
    
    
    817  | 
     | 
     | 
         */  | 
    
    
    818  | 
     | 
     | 
        child = 1;  | 
    
    
    819  | 
     | 
     | 
        s = value(STRstatus);  | 
    
    
    820  | 
     | 
     | 
        xexit(s ? getn(s) : 0);  | 
    
    
    821  | 
     | 
     | 
    }  | 
    
    
    822  | 
     | 
     | 
     | 
    
    
    823  | 
     | 
     | 
    /*  | 
    
    
    824  | 
     | 
     | 
     * in the event of a HUP we want to save the history  | 
    
    
    825  | 
     | 
     | 
     */  | 
    
    
    826  | 
     | 
     | 
    static void  | 
    
    
    827  | 
     | 
     | 
    phup(int sig)  | 
    
    
    828  | 
     | 
     | 
    { | 
    
    
    829  | 
     | 
     | 
        /* XXX sigh, everything after this is a signal race */  | 
    
    
    830  | 
     | 
     | 
     | 
    
    
    831  | 
     | 
     | 
        rechist();  | 
    
    
    832  | 
     | 
     | 
     | 
    
    
    833  | 
     | 
     | 
        /*  | 
    
    
    834  | 
     | 
     | 
         * We kill the last foreground process group. It then becomes  | 
    
    
    835  | 
     | 
     | 
         * responsible to propagate the SIGHUP to its progeny.  | 
    
    
    836  | 
     | 
     | 
         */  | 
    
    
    837  | 
     | 
     | 
        { | 
    
    
    838  | 
     | 
     | 
    	struct process *pp, *np;  | 
    
    
    839  | 
     | 
     | 
     | 
    
    
    840  | 
     | 
     | 
    	for (pp = proclist.p_next; pp; pp = pp->p_next) { | 
    
    
    841  | 
     | 
     | 
    	    np = pp;  | 
    
    
    842  | 
     | 
     | 
    	    /*  | 
    
    
    843  | 
     | 
     | 
    	     * Find if this job is in the foreground. It could be that  | 
    
    
    844  | 
     | 
     | 
    	     * the process leader has exited and the foreground flag  | 
    
    
    845  | 
     | 
     | 
    	     * is cleared for it.  | 
    
    
    846  | 
     | 
     | 
    	     */  | 
    
    
    847  | 
     | 
     | 
    	    do  | 
    
    
    848  | 
     | 
     | 
    		/*  | 
    
    
    849  | 
     | 
     | 
    		 * If a process is in the foreground; we try to kill  | 
    
    
    850  | 
     | 
     | 
    		 * it's process group. If we succeed, then the  | 
    
    
    851  | 
     | 
     | 
    		 * whole job is gone. Otherwise we keep going...  | 
    
    
    852  | 
     | 
     | 
    		 * But avoid sending HUP to the shell again.  | 
    
    
    853  | 
     | 
     | 
    		 */  | 
    
    
    854  | 
     | 
     | 
    		if ((np->p_flags & PFOREGND) != 0 && np->p_jobid != shpgrp &&  | 
    
    
    855  | 
     | 
     | 
    		    kill(-np->p_jobid, SIGHUP) != -1) { | 
    
    
    856  | 
     | 
     | 
    		    /* In case the job was suspended... */  | 
    
    
    857  | 
     | 
     | 
    		    (void) kill(-np->p_jobid, SIGCONT);  | 
    
    
    858  | 
     | 
     | 
    		    break;  | 
    
    
    859  | 
     | 
     | 
    		}  | 
    
    
    860  | 
     | 
     | 
    	    while ((np = np->p_friends) != pp);  | 
    
    
    861  | 
     | 
     | 
    	}  | 
    
    
    862  | 
     | 
     | 
        }  | 
    
    
    863  | 
     | 
     | 
        xexit(sig);  | 
    
    
    864  | 
     | 
     | 
    }  | 
    
    
    865  | 
     | 
     | 
     | 
    
    
    866  | 
     | 
     | 
    Char   *jobargv[2] = {STRjobs, 0}; | 
    
    
    867  | 
     | 
     | 
     | 
    
    
    868  | 
     | 
     | 
    /*  | 
    
    
    869  | 
     | 
     | 
     * Catch an interrupt, e.g. during lexical input.  | 
    
    
    870  | 
     | 
     | 
     * If we are an interactive shell, we reset the interrupt catch  | 
    
    
    871  | 
     | 
     | 
     * immediately.  In any case we drain the shell output,  | 
    
    
    872  | 
     | 
     | 
     * and finally go through the normal error mechanism, which  | 
    
    
    873  | 
     | 
     | 
     * gets a chance to make the shell go away.  | 
    
    
    874  | 
     | 
     | 
     */  | 
    
    
    875  | 
     | 
     | 
    /* ARGSUSED */  | 
    
    
    876  | 
     | 
     | 
    void  | 
    
    
    877  | 
     | 
     | 
    pintr(int notused)  | 
    
    
    878  | 
     | 
     | 
    { | 
    
    
    879  | 
     | 
     | 
        int save_errno = errno;  | 
    
    
    880  | 
     | 
     | 
     | 
    
    
    881  | 
     | 
     | 
        pintr1(1);  | 
    
    
    882  | 
     | 
     | 
        errno = save_errno;  | 
    
    
    883  | 
     | 
     | 
    }  | 
    
    
    884  | 
     | 
     | 
     | 
    
    
    885  | 
     | 
     | 
    void  | 
    
    
    886  | 
     | 
     | 
    pintr1(bool wantnl)  | 
    
    
    887  | 
     | 
     | 
    { | 
    
    
    888  | 
     | 
     | 
        Char **v;  | 
    
    
    889  | 
     | 
     | 
        sigset_t sigset, osigset;  | 
    
    
    890  | 
     | 
     | 
     | 
    
    
    891  | 
     | 
     | 
        sigemptyset(&sigset);  | 
    
    
    892  | 
     | 
     | 
        sigprocmask(SIG_BLOCK, &sigset, &osigset);  | 
    
    
    893  | 
     | 
     | 
        if (setintr) { | 
    
    
    894  | 
     | 
     | 
    	sigset = osigset;  | 
    
    
    895  | 
     | 
     | 
    	sigdelset(&sigset, SIGINT);  | 
    
    
    896  | 
     | 
     | 
    	sigprocmask(SIG_SETMASK, &sigset, NULL);  | 
    
    
    897  | 
     | 
     | 
    	if (pjobs) { | 
    
    
    898  | 
     | 
     | 
    	    pjobs = 0;  | 
    
    
    899  | 
     | 
     | 
    	    (void) fprintf(cshout, "\n");  | 
    
    
    900  | 
     | 
     | 
    	    dojobs(jobargv, NULL);  | 
    
    
    901  | 
     | 
     | 
    	    stderror(ERR_NAME | ERR_INTR);  | 
    
    
    902  | 
     | 
     | 
    	}  | 
    
    
    903  | 
     | 
     | 
        }  | 
    
    
    904  | 
     | 
     | 
        sigdelset(&osigset, SIGCHLD);  | 
    
    
    905  | 
     | 
     | 
        sigprocmask(SIG_SETMASK, &osigset, NULL);  | 
    
    
    906  | 
     | 
     | 
        (void) fpurge(cshout);  | 
    
    
    907  | 
     | 
     | 
        (void) endpwent();  | 
    
    
    908  | 
     | 
     | 
     | 
    
    
    909  | 
     | 
     | 
        /*  | 
    
    
    910  | 
     | 
     | 
         * If we have an active "onintr" then we search for the label. Note that if  | 
    
    
    911  | 
     | 
     | 
         * one does "onintr -" then we shan't be interruptible so we needn't worry  | 
    
    
    912  | 
     | 
     | 
         * about that here.  | 
    
    
    913  | 
     | 
     | 
         */  | 
    
    
    914  | 
     | 
     | 
        if (gointr) { | 
    
    
    915  | 
     | 
     | 
    	gotolab(gointr);  | 
    
    
    916  | 
     | 
     | 
    	timflg = 0;  | 
    
    
    917  | 
     | 
     | 
    	if ((v = pargv) != NULL)  | 
    
    
    918  | 
     | 
     | 
    	    pargv = 0, blkfree(v);  | 
    
    
    919  | 
     | 
     | 
    	if ((v = gargv) != NULL)  | 
    
    
    920  | 
     | 
     | 
    	    gargv = 0, blkfree(v);  | 
    
    
    921  | 
     | 
     | 
    	reset();  | 
    
    
    922  | 
     | 
     | 
        }  | 
    
    
    923  | 
     | 
     | 
        else if (intty && wantnl) { | 
    
    
    924  | 
     | 
     | 
    	(void) fputc('\r', cshout); | 
    
    
    925  | 
     | 
     | 
    	(void) fputc('\n', cshout); | 
    
    
    926  | 
     | 
     | 
        }  | 
    
    
    927  | 
     | 
     | 
        stderror(ERR_SILENT);  | 
    
    
    928  | 
     | 
     | 
    }  | 
    
    
    929  | 
     | 
     | 
     | 
    
    
    930  | 
     | 
     | 
    /*  | 
    
    
    931  | 
     | 
     | 
     * Process is the main driving routine for the shell.  | 
    
    
    932  | 
     | 
     | 
     * It runs all command processing, except for those within { ... } | 
    
    
    933  | 
     | 
     | 
     * in expressions (which is run by a routine evalav in sh.exp.c which  | 
    
    
    934  | 
     | 
     | 
     * is a stripped down process), and `...` evaluation which is run  | 
    
    
    935  | 
     | 
     | 
     * also by a subset of this code in sh.glob.c in the routine backeval.  | 
    
    
    936  | 
     | 
     | 
     *  | 
    
    
    937  | 
     | 
     | 
     * The code here is a little strange because part of it is interruptible  | 
    
    
    938  | 
     | 
     | 
     * and hence freeing of structures appears to occur when none is necessary  | 
    
    
    939  | 
     | 
     | 
     * if this is ignored.  | 
    
    
    940  | 
     | 
     | 
     *  | 
    
    
    941  | 
     | 
     | 
     * Note that if catch is not set then we will unwind on any error.  | 
    
    
    942  | 
     | 
     | 
     * If an end-of-file occurs, we return.  | 
    
    
    943  | 
     | 
     | 
     */  | 
    
    
    944  | 
     | 
     | 
    static struct command *savet = NULL;  | 
    
    
    945  | 
     | 
     | 
    void  | 
    
    
    946  | 
     | 
     | 
    process(bool catch)  | 
    
    
    947  | 
     | 
     | 
    { | 
    
    
    948  | 
     | 
     | 
        jmp_buf osetexit;  | 
    
    
    949  | 
     | 
     | 
        struct command *t = savet;  | 
    
    
    950  | 
     | 
     | 
        sigset_t sigset;  | 
    
    
    951  | 
     | 
     | 
     | 
    
    
    952  | 
     | 
     | 
        savet = NULL;  | 
    
    
    953  | 
     | 
     | 
        getexit(osetexit);  | 
    
    
    954  | 
     | 
     | 
        for (;;) { | 
    
    
    955  | 
     | 
     | 
    	pendjob();  | 
    
    
    956  | 
     | 
     | 
    	paraml.next = paraml.prev = ¶ml;  | 
    
    
    957  | 
     | 
     | 
    	paraml.word = STRNULL;  | 
    
    
    958  | 
     | 
     | 
    	(void) setexit();  | 
    
    
    959  | 
     | 
     | 
    	justpr = enterhist;	/* execute if not entering history */  | 
    
    
    960  | 
     | 
     | 
     | 
    
    
    961  | 
     | 
     | 
    	/*  | 
    
    
    962  | 
     | 
     | 
    	 * Interruptible during interactive reads  | 
    
    
    963  | 
     | 
     | 
    	 */  | 
    
    
    964  | 
     | 
     | 
    	if (setintr) { | 
    
    
    965  | 
     | 
     | 
    	    sigemptyset(&sigset);  | 
    
    
    966  | 
     | 
     | 
    	    sigaddset(&sigset, SIGINT);  | 
    
    
    967  | 
     | 
     | 
    	    sigprocmask(SIG_UNBLOCK, &sigset, NULL);  | 
    
    
    968  | 
     | 
     | 
    	}  | 
    
    
    969  | 
     | 
     | 
     | 
    
    
    970  | 
     | 
     | 
    	/*  | 
    
    
    971  | 
     | 
     | 
    	 * For the sake of reset()  | 
    
    
    972  | 
     | 
     | 
    	 */  | 
    
    
    973  | 
     | 
     | 
    	freelex(¶ml);  | 
    
    
    974  | 
     | 
     | 
    	if (savet)  | 
    
    
    975  | 
     | 
     | 
    	    freesyn(savet), savet = NULL;  | 
    
    
    976  | 
     | 
     | 
     | 
    
    
    977  | 
     | 
     | 
    	if (haderr) { | 
    
    
    978  | 
     | 
     | 
    	    if (!catch) { | 
    
    
    979  | 
     | 
     | 
    		/* unwind */  | 
    
    
    980  | 
     | 
     | 
    		doneinp = 0;  | 
    
    
    981  | 
     | 
     | 
    		resexit(osetexit);  | 
    
    
    982  | 
     | 
     | 
    		savet = t;  | 
    
    
    983  | 
     | 
     | 
    		reset();  | 
    
    
    984  | 
     | 
     | 
    	    }  | 
    
    
    985  | 
     | 
     | 
    	    haderr = 0;  | 
    
    
    986  | 
     | 
     | 
    	    /*  | 
    
    
    987  | 
     | 
     | 
    	     * Every error is eventually caught here or the shell dies.  It is  | 
    
    
    988  | 
     | 
     | 
    	     * at this point that we clean up any left-over open files, by  | 
    
    
    989  | 
     | 
     | 
    	     * closing all but a fixed number of pre-defined files.  Thus  | 
    
    
    990  | 
     | 
     | 
    	     * routines don't have to worry about leaving files open due to  | 
    
    
    991  | 
     | 
     | 
    	     * deeper errors... they will get closed here.  | 
    
    
    992  | 
     | 
     | 
    	     */  | 
    
    
    993  | 
     | 
     | 
    	    closem();  | 
    
    
    994  | 
     | 
     | 
    	    continue;  | 
    
    
    995  | 
     | 
     | 
    	}  | 
    
    
    996  | 
     | 
     | 
    	if (doneinp) { | 
    
    
    997  | 
     | 
     | 
    	    doneinp = 0;  | 
    
    
    998  | 
     | 
     | 
    	    break;  | 
    
    
    999  | 
     | 
     | 
    	}  | 
    
    
    1000  | 
     | 
     | 
    	if (chkstop)  | 
    
    
    1001  | 
     | 
     | 
    	    chkstop--;  | 
    
    
    1002  | 
     | 
     | 
    	if (neednote)  | 
    
    
    1003  | 
     | 
     | 
    	    pnote();  | 
    
    
    1004  | 
     | 
     | 
    	if (intty && prompt && evalvec == 0) { | 
    
    
    1005  | 
     | 
     | 
    	    mailchk();  | 
    
    
    1006  | 
     | 
     | 
    	    /*  | 
    
    
    1007  | 
     | 
     | 
    	     * If we are at the end of the input buffer then we are going to  | 
    
    
    1008  | 
     | 
     | 
    	     * read fresh stuff. Otherwise, we are rereading input and don't  | 
    
    
    1009  | 
     | 
     | 
    	     * need or want to prompt.  | 
    
    
    1010  | 
     | 
     | 
    	     */  | 
    
    
    1011  | 
     | 
     | 
    	    needprompt = aret == F_SEEK && fseekp == feobp;  | 
    
    
    1012  | 
     | 
     | 
    	    if (!filec && needprompt)  | 
    
    
    1013  | 
     | 
     | 
    		printprompt();  | 
    
    
    1014  | 
     | 
     | 
    	    (void) fflush(cshout);  | 
    
    
    1015  | 
     | 
     | 
    	}  | 
    
    
    1016  | 
     | 
     | 
    	if (seterr) { | 
    
    
    1017  | 
     | 
     | 
    	    free(seterr);  | 
    
    
    1018  | 
     | 
     | 
    	    seterr = NULL;  | 
    
    
    1019  | 
     | 
     | 
    	}  | 
    
    
    1020  | 
     | 
     | 
     | 
    
    
    1021  | 
     | 
     | 
    	/*  | 
    
    
    1022  | 
     | 
     | 
    	 * Echo not only on VERBOSE, but also with history expansion. If there  | 
    
    
    1023  | 
     | 
     | 
    	 * is a lexical error then we forego history echo.  | 
    
    
    1024  | 
     | 
     | 
    	 */  | 
    
    
    1025  | 
     | 
     | 
    	if ((lex(¶ml) && !seterr && intty) || adrof(STRverbose)) { | 
    
    
    1026  | 
     | 
     | 
    	    prlex(csherr, ¶ml);  | 
    
    
    1027  | 
     | 
     | 
    	}  | 
    
    
    1028  | 
     | 
     | 
     | 
    
    
    1029  | 
     | 
     | 
    	/*  | 
    
    
    1030  | 
     | 
     | 
    	 * The parser may lose space if interrupted.  | 
    
    
    1031  | 
     | 
     | 
    	 */  | 
    
    
    1032  | 
     | 
     | 
    	if (setintr)  | 
    
    
    1033  | 
     | 
     | 
    	    sigprocmask(SIG_BLOCK, &sigset, NULL);  | 
    
    
    1034  | 
     | 
     | 
     | 
    
    
    1035  | 
     | 
     | 
    	/*  | 
    
    
    1036  | 
     | 
     | 
    	 * Save input text on the history list if reading in old history, or it  | 
    
    
    1037  | 
     | 
     | 
    	 * is from the terminal at the top level and not in a loop.  | 
    
    
    1038  | 
     | 
     | 
    	 *  | 
    
    
    1039  | 
     | 
     | 
    	 * PWP: entry of items in the history list while in a while loop is done  | 
    
    
    1040  | 
     | 
     | 
    	 * elsewhere...  | 
    
    
    1041  | 
     | 
     | 
    	 */  | 
    
    
    1042  | 
     | 
     | 
    	if (enterhist || (catch && intty && !whyles))  | 
    
    
    1043  | 
     | 
     | 
    	    savehist(¶ml);  | 
    
    
    1044  | 
     | 
     | 
     | 
    
    
    1045  | 
     | 
     | 
    	/*  | 
    
    
    1046  | 
     | 
     | 
    	 * Print lexical error messages, except when sourcing history lists.  | 
    
    
    1047  | 
     | 
     | 
    	 */  | 
    
    
    1048  | 
     | 
     | 
    	if (!enterhist && seterr)  | 
    
    
    1049  | 
     | 
     | 
    	    stderror(ERR_OLD);  | 
    
    
    1050  | 
     | 
     | 
     | 
    
    
    1051  | 
     | 
     | 
    	/*  | 
    
    
    1052  | 
     | 
     | 
    	 * If had a history command :p modifier then this is as far as we  | 
    
    
    1053  | 
     | 
     | 
    	 * should go  | 
    
    
    1054  | 
     | 
     | 
    	 */  | 
    
    
    1055  | 
     | 
     | 
    	if (justpr)  | 
    
    
    1056  | 
     | 
     | 
    	    reset();  | 
    
    
    1057  | 
     | 
     | 
     | 
    
    
    1058  | 
     | 
     | 
    	alias(¶ml);  | 
    
    
    1059  | 
     | 
     | 
     | 
    
    
    1060  | 
     | 
     | 
    	/*  | 
    
    
    1061  | 
     | 
     | 
    	 * Parse the words of the input into a parse tree.  | 
    
    
    1062  | 
     | 
     | 
    	 */  | 
    
    
    1063  | 
     | 
     | 
    	savet = syntax(paraml.next, ¶ml, 0);  | 
    
    
    1064  | 
     | 
     | 
    	if (seterr)  | 
    
    
    1065  | 
     | 
     | 
    	    stderror(ERR_OLD);  | 
    
    
    1066  | 
     | 
     | 
     | 
    
    
    1067  | 
     | 
     | 
    	execute(savet, (tpgrp > 0 ? tpgrp : -1), NULL, NULL);  | 
    
    
    1068  | 
     | 
     | 
     | 
    
    
    1069  | 
     | 
     | 
    	/*  | 
    
    
    1070  | 
     | 
     | 
    	 * Made it!  | 
    
    
    1071  | 
     | 
     | 
    	 */  | 
    
    
    1072  | 
     | 
     | 
    	freelex(¶ml);  | 
    
    
    1073  | 
     | 
     | 
    	freesyn((struct command *) savet), savet = NULL;  | 
    
    
    1074  | 
     | 
     | 
        }  | 
    
    
    1075  | 
     | 
     | 
        resexit(osetexit);  | 
    
    
    1076  | 
     | 
     | 
        savet = t;  | 
    
    
    1077  | 
     | 
     | 
    }  | 
    
    
    1078  | 
     | 
     | 
     | 
    
    
    1079  | 
     | 
     | 
    void  | 
    
    
    1080  | 
     | 
     | 
    /*ARGSUSED*/  | 
    
    
    1081  | 
     | 
     | 
    dosource(Char **v, struct command *t)  | 
    
    
    1082  | 
     | 
     | 
    { | 
    
    
    1083  | 
     | 
     | 
        Char *f;  | 
    
    
    1084  | 
     | 
     | 
        bool    hflg = 0;  | 
    
    
    1085  | 
     | 
     | 
        Char    buf[BUFSIZ];  | 
    
    
    1086  | 
     | 
     | 
        char    sbuf[BUFSIZ];  | 
    
    
    1087  | 
     | 
     | 
     | 
    
    
    1088  | 
     | 
     | 
        v++;  | 
    
    
    1089  | 
     | 
     | 
        if (*v && eq(*v, STRmh)) { | 
    
    
    1090  | 
     | 
     | 
    	if (*++v == NULL)  | 
    
    
    1091  | 
     | 
     | 
    	    stderror(ERR_NAME | ERR_HFLAG);  | 
    
    
    1092  | 
     | 
     | 
    	hflg++;  | 
    
    
    1093  | 
     | 
     | 
        }  | 
    
    
    1094  | 
     | 
     | 
        (void) Strlcpy(buf, *v, sizeof buf/sizeof(Char));  | 
    
    
    1095  | 
     | 
     | 
        f = globone(buf, G_ERROR);  | 
    
    
    1096  | 
     | 
     | 
        (void) strlcpy(sbuf, short2str(f), sizeof sbuf);  | 
    
    
    1097  | 
     | 
     | 
        free(f);  | 
    
    
    1098  | 
     | 
     | 
        if (!srcfile(sbuf, 0, hflg) && !hflg)  | 
    
    
    1099  | 
     | 
     | 
    	stderror(ERR_SYSTEM, sbuf, strerror(errno));  | 
    
    
    1100  | 
     | 
     | 
    }  | 
    
    
    1101  | 
     | 
     | 
     | 
    
    
    1102  | 
     | 
     | 
    /*  | 
    
    
    1103  | 
     | 
     | 
     * Check for mail.  | 
    
    
    1104  | 
     | 
     | 
     * If we are a login shell, then we don't want to tell  | 
    
    
    1105  | 
     | 
     | 
     * about any mail file unless its been modified  | 
    
    
    1106  | 
     | 
     | 
     * after the time we started.  | 
    
    
    1107  | 
     | 
     | 
     * This prevents us from telling the user things he already  | 
    
    
    1108  | 
     | 
     | 
     * knows, since the login program insists on saying  | 
    
    
    1109  | 
     | 
     | 
     * "You have mail."  | 
    
    
    1110  | 
     | 
     | 
     */  | 
    
    
    1111  | 
     | 
     | 
    static void  | 
    
    
    1112  | 
     | 
     | 
    mailchk(void)  | 
    
    
    1113  | 
     | 
     | 
    { | 
    
    
    1114  | 
     | 
     | 
        struct varent *v;  | 
    
    
    1115  | 
     | 
     | 
        Char **vp;  | 
    
    
    1116  | 
     | 
     | 
        time_t  t;  | 
    
    
    1117  | 
     | 
     | 
        int     intvl, cnt;  | 
    
    
    1118  | 
     | 
     | 
        struct stat stb;  | 
    
    
    1119  | 
     | 
     | 
        bool    new;  | 
    
    
    1120  | 
     | 
     | 
     | 
    
    
    1121  | 
     | 
     | 
        v = adrof(STRmail);  | 
    
    
    1122  | 
     | 
     | 
        if (v == 0)  | 
    
    
    1123  | 
     | 
     | 
    	return;  | 
    
    
    1124  | 
     | 
     | 
        (void) time(&t);  | 
    
    
    1125  | 
     | 
     | 
        vp = v->vec;  | 
    
    
    1126  | 
     | 
     | 
        cnt = blklen(vp);  | 
    
    
    1127  | 
     | 
     | 
        intvl = (cnt && number(*vp)) ? (--cnt, getn(*vp++)) : MAILINTVL;  | 
    
    
    1128  | 
     | 
     | 
        if (intvl < 1)  | 
    
    
    1129  | 
     | 
     | 
    	intvl = 1;  | 
    
    
    1130  | 
     | 
     | 
        if (chktim + intvl > t)  | 
    
    
    1131  | 
     | 
     | 
    	return;  | 
    
    
    1132  | 
     | 
     | 
        for (; *vp; vp++) { | 
    
    
    1133  | 
     | 
     | 
    	if (stat(short2str(*vp), &stb) < 0)  | 
    
    
    1134  | 
     | 
     | 
    	    continue;  | 
    
    
    1135  | 
     | 
     | 
    	new = stb.st_mtime > time0.tv_sec;  | 
    
    
    1136  | 
     | 
     | 
    	if (stb.st_size == 0 || stb.st_atime > stb.st_mtime ||  | 
    
    
    1137  | 
     | 
     | 
    	    (stb.st_atime < chktim && stb.st_mtime < chktim) ||  | 
    
    
    1138  | 
     | 
     | 
    	    (loginsh && !new))  | 
    
    
    1139  | 
     | 
     | 
    	    continue;  | 
    
    
    1140  | 
     | 
     | 
    	if (cnt == 1)  | 
    
    
    1141  | 
     | 
     | 
    	    (void) fprintf(cshout, "You have %smail.\n", new ? "new " : "");  | 
    
    
    1142  | 
     | 
     | 
    	else  | 
    
    
    1143  | 
     | 
     | 
    	    (void) fprintf(cshout, "%s in %s.\n", new ? "New mail" : "Mail",  | 
    
    
    1144  | 
     | 
     | 
    			   vis_str(*vp));  | 
    
    
    1145  | 
     | 
     | 
        }  | 
    
    
    1146  | 
     | 
     | 
        chktim = t;  | 
    
    
    1147  | 
     | 
     | 
    }  | 
    
    
    1148  | 
     | 
     | 
     | 
    
    
    1149  | 
     | 
     | 
    /*  | 
    
    
    1150  | 
     | 
     | 
     * Extract a home directory from the password file  | 
    
    
    1151  | 
     | 
     | 
     * The argument points to a buffer where the name of the  | 
    
    
    1152  | 
     | 
     | 
     * user whose home directory is sought is currently.  | 
    
    
    1153  | 
     | 
     | 
     * We write the home directory of the user back there.  | 
    
    
    1154  | 
     | 
     | 
     */  | 
    
    
    1155  | 
     | 
     | 
    int  | 
    
    
    1156  | 
     | 
     | 
    gethdir(Char *home, int len)  | 
    
    
    1157  | 
     | 
     | 
    { | 
    
    
    1158  | 
     | 
     | 
        Char   *h;  | 
    
    
    1159  | 
     | 
     | 
        struct passwd *pw;  | 
    
    
    1160  | 
     | 
     | 
     | 
    
    
    1161  | 
     | 
     | 
        /*  | 
    
    
    1162  | 
     | 
     | 
         * Is it us?  | 
    
    
    1163  | 
     | 
     | 
         */  | 
    
    
    1164  | 
     | 
     | 
        if (*home == '\0') { | 
    
    
    1165  | 
     | 
     | 
    	if ((h = value(STRhome)) != NULL) { | 
    
    
    1166  | 
     | 
     | 
    	    if (Strlcpy(home, h, len) >= len)  | 
    
    
    1167  | 
     | 
     | 
    		return 1;  | 
    
    
    1168  | 
     | 
     | 
    	    return 0;  | 
    
    
    1169  | 
     | 
     | 
    	}  | 
    
    
    1170  | 
     | 
     | 
    	else  | 
    
    
    1171  | 
     | 
     | 
    	    return 1;  | 
    
    
    1172  | 
     | 
     | 
        }  | 
    
    
    1173  | 
     | 
     | 
     | 
    
    
    1174  | 
     | 
     | 
        if ((pw = getpwnam(short2str(home))) != NULL) { | 
    
    
    1175  | 
     | 
     | 
    	if (Strlcpy(home, str2short(pw->pw_dir), len) >= len)  | 
    
    
    1176  | 
     | 
     | 
    	    return 1;  | 
    
    
    1177  | 
     | 
     | 
    	return 0;  | 
    
    
    1178  | 
     | 
     | 
        }  | 
    
    
    1179  | 
     | 
     | 
        else  | 
    
    
    1180  | 
     | 
     | 
    	return 1;  | 
    
    
    1181  | 
     | 
     | 
    }  | 
    
    
    1182  | 
     | 
     | 
     | 
    
    
    1183  | 
     | 
     | 
    /*  | 
    
    
    1184  | 
     | 
     | 
     * When didfds is set, we do I/O from 0, 1, 2 otherwise from 15, 16, 17  | 
    
    
    1185  | 
     | 
     | 
     * We also check if the shell has already changed the descriptor to point to  | 
    
    
    1186  | 
     | 
     | 
     * 0, 1, 2 when didfds is set.  | 
    
    
    1187  | 
     | 
     | 
     */  | 
    
    
    1188  | 
     | 
     | 
    #define DESC(a) (*((int *) (a)) - (didfds && *((int *) a) >= FSHIN ? FSHIN : 0))  | 
    
    
    1189  | 
     | 
     | 
     | 
    
    
    1190  | 
     | 
     | 
    static int  | 
    
    
    1191  | 
     | 
     | 
    readf(void *oreo, char *buf, int siz)  | 
    
    
    1192  | 
     | 
     | 
    { | 
    
    
    1193  | 
     | 
     | 
        return read(DESC(oreo), buf, siz);  | 
    
    
    1194  | 
     | 
     | 
    }  | 
    
    
    1195  | 
     | 
     | 
     | 
    
    
    1196  | 
     | 
     | 
     | 
    
    
    1197  | 
     | 
     | 
    static int  | 
    
    
    1198  | 
     | 
     | 
    writef(void *oreo, const char *buf, int siz)  | 
    
    
    1199  | 
     | 
     | 
    { | 
    
    
    1200  | 
     | 
     | 
        return write(DESC(oreo), buf, siz);  | 
    
    
    1201  | 
     | 
     | 
    }  | 
    
    
    1202  | 
     | 
     | 
     | 
    
    
    1203  | 
     | 
     | 
    static fpos_t  | 
    
    
    1204  | 
     | 
     | 
    seekf(void *oreo, fpos_t off, int whence)  | 
    
    
    1205  | 
     | 
     | 
    { | 
    
    
    1206  | 
     | 
     | 
        return lseek(DESC(oreo), off, whence);  | 
    
    
    1207  | 
     | 
     | 
    }  | 
    
    
    1208  | 
     | 
     | 
     | 
    
    
    1209  | 
     | 
     | 
     | 
    
    
    1210  | 
     | 
     | 
    static int  | 
    
    
    1211  | 
     | 
     | 
    closef(void *oreo)  | 
    
    
    1212  | 
     | 
     | 
    { | 
    
    
    1213  | 
     | 
     | 
        return close(DESC(oreo));  | 
    
    
    1214  | 
     | 
     | 
    }  | 
    
    
    1215  | 
     | 
     | 
     | 
    
    
    1216  | 
     | 
     | 
     | 
    
    
    1217  | 
     | 
     | 
    /*  | 
    
    
    1218  | 
     | 
     | 
     * Print the visible version of a string.  | 
    
    
    1219  | 
     | 
     | 
     */  | 
    
    
    1220  | 
     | 
     | 
    int  | 
    
    
    1221  | 
     | 
     | 
    vis_fputc(int ch, FILE *fp)  | 
    
    
    1222  | 
     | 
     | 
    { | 
    
    
    1223  | 
     | 
     | 
        char uenc[5];	/* 4 + NUL */  | 
    
    
    1224  | 
     | 
     | 
     | 
    
    
    1225  | 
     | 
     | 
        if (ch & QUOTE)  | 
    
    
    1226  | 
     | 
     | 
    	return fputc(ch & TRIM, fp);  | 
    
    
    1227  | 
     | 
     | 
        (void) vis(uenc, ch & TRIM, VIS_NOSLASH, 0);  | 
    
    
    1228  | 
     | 
     | 
        return fputs(uenc, fp);  | 
    
    
    1229  | 
     | 
     | 
    }  | 
    
    
    1230  | 
     | 
     | 
     | 
    
    
    1231  | 
     | 
     | 
    /*  | 
    
    
    1232  | 
     | 
     | 
     * Move the initial descriptors to their eventual  | 
    
    
    1233  | 
     | 
     | 
     * resting places, closing all other units.  | 
    
    
    1234  | 
     | 
     | 
     */  | 
    
    
    1235  | 
     | 
     | 
    void  | 
    
    
    1236  | 
     | 
     | 
    initdesc(void)  | 
    
    
    1237  | 
     | 
     | 
    { | 
    
    
    1238  | 
     | 
     | 
     | 
    
    
    1239  | 
     | 
     | 
        didfds = 0;			/* 0, 1, 2 aren't set up */  | 
    
    
    1240  | 
     | 
     | 
        (void) fcntl(SHIN = dcopy(0, FSHIN), F_SETFD, FD_CLOEXEC);  | 
    
    
    1241  | 
     | 
     | 
        (void) fcntl(SHOUT = dcopy(1, FSHOUT), F_SETFD, FD_CLOEXEC);  | 
    
    
    1242  | 
     | 
     | 
        (void) fcntl(SHERR = dcopy(2, FSHERR), F_SETFD, FD_CLOEXEC);  | 
    
    
    1243  | 
     | 
     | 
        (void) fcntl(OLDSTD = dcopy(SHIN, FOLDSTD), F_SETFD, FD_CLOEXEC);  | 
    
    
    1244  | 
     | 
     | 
        closem();  | 
    
    
    1245  | 
     | 
     | 
    }  | 
    
    
    1246  | 
     | 
     | 
     | 
    
    
    1247  | 
     | 
     | 
     | 
    
    
    1248  | 
     | 
     | 
    void  | 
    
    
    1249  | 
     | 
     | 
    xexit(int i)  | 
    
    
    1250  | 
     | 
     | 
    { | 
    
    
    1251  | 
     | 
     | 
        untty();  | 
    
    
    1252  | 
     | 
     | 
        _exit(i);  | 
    
    
    1253  | 
     | 
     | 
    }  | 
    
    
    1254  | 
     | 
     | 
     | 
    
    
    1255  | 
     | 
     | 
    static Char **  | 
    
    
    1256  | 
     | 
     | 
    defaultpath(void)  | 
    
    
    1257  | 
     | 
     | 
    { | 
    
    
    1258  | 
     | 
     | 
        char   *ptr;  | 
    
    
    1259  | 
     | 
     | 
        Char  **blk, **blkp;  | 
    
    
    1260  | 
     | 
     | 
        struct stat stb;  | 
    
    
    1261  | 
     | 
     | 
     | 
    
    
    1262  | 
     | 
     | 
        blkp = blk = xreallocarray(NULL, 10, sizeof(Char *));  | 
    
    
    1263  | 
     | 
     | 
     | 
    
    
    1264  | 
     | 
     | 
    #define DIRAPPEND(a)  \  | 
    
    
    1265  | 
     | 
     | 
    	if (stat(ptr = a, &stb) == 0 && S_ISDIR(stb.st_mode)) \  | 
    
    
    1266  | 
     | 
     | 
    		*blkp++ = SAVE(ptr)  | 
    
    
    1267  | 
     | 
     | 
     | 
    
    
    1268  | 
     | 
     | 
        DIRAPPEND(_PATH_BIN);  | 
    
    
    1269  | 
     | 
     | 
        DIRAPPEND(_PATH_USRBIN);  | 
    
    
    1270  | 
     | 
     | 
     | 
    
    
    1271  | 
     | 
     | 
    #undef DIRAPPEND  | 
    
    
    1272  | 
     | 
     | 
     | 
    
    
    1273  | 
     | 
     | 
        *blkp = NULL;  | 
    
    
    1274  | 
     | 
     | 
        return (blk);  | 
    
    
    1275  | 
     | 
     | 
    }  | 
    
    
    1276  | 
     | 
     | 
     | 
    
    
    1277  | 
     | 
     | 
    void  | 
    
    
    1278  | 
     | 
     | 
    printprompt(void)  | 
    
    
    1279  | 
     | 
     | 
    { | 
    
    
    1280  | 
     | 
     | 
        Char *cp;  | 
    
    
    1281  | 
     | 
     | 
     | 
    
    
    1282  | 
     | 
     | 
        if (!whyles) { | 
    
    
    1283  | 
     | 
     | 
    	for (cp = value(STRprompt); *cp; cp++)  | 
    
    
    1284  | 
     | 
     | 
    	    if (*cp == HIST)  | 
    
    
    1285  | 
     | 
     | 
    		(void) fprintf(cshout, "%d", eventno + 1);  | 
    
    
    1286  | 
     | 
     | 
    	    else { | 
    
    
    1287  | 
     | 
     | 
    		if (*cp == '\\' && cp[1] == HIST)  | 
    
    
    1288  | 
     | 
     | 
    		    cp++;  | 
    
    
    1289  | 
     | 
     | 
    		(void) vis_fputc(*cp | QUOTE, cshout);  | 
    
    
    1290  | 
     | 
     | 
    	    }  | 
    
    
    1291  | 
     | 
     | 
        }  | 
    
    
    1292  | 
     | 
     | 
        else  | 
    
    
    1293  | 
     | 
     | 
    	/*  | 
    
    
    1294  | 
     | 
     | 
    	 * Prompt for forward reading loop body content.  | 
    
    
    1295  | 
     | 
     | 
    	 */  | 
    
    
    1296  | 
     | 
     | 
    	(void) fprintf(cshout, "? ");  | 
    
    
    1297  | 
     | 
     | 
        (void) fflush(cshout);  | 
    
    
    1298  | 
     | 
     | 
    }  |