[BACK]Return to csh.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / bin / csh

Annotation of src/bin/csh/csh.c, Revision 1.30

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

CVSweb <webmaster@jp.NetBSD.org>