Annotation of 43BSD/bin/csh/sh.exec.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1980 Regents of the University of California.
                      3:  * All rights reserved.  The Berkeley Software License Agreement
                      4:  * specifies the terms and conditions for redistribution.
                      5:  */
                      6: 
                      7: #ifndef lint
                      8: static char *sccsid = "@(#)sh.exec.c   5.2 (Berkeley) 6/6/85";
                      9: #endif
                     10: 
                     11: #include "sh.h"
                     12: #include <sys/dir.h>
                     13: 
                     14: /*
                     15:  * C shell
                     16:  */
                     17: 
                     18: /*
                     19:  * System level search and execute of a command.
                     20:  * We look in each directory for the specified command name.
                     21:  * If the name contains a '/' then we execute only the full path name.
                     22:  * If there is no search path then we execute only full path names.
                     23:  */
                     24: 
                     25: /* 
                     26:  * As we search for the command we note the first non-trivial error
                     27:  * message for presentation to the user.  This allows us often
                     28:  * to show that a file has the wrong mode/no access when the file
                     29:  * is not in the last component of the search path, so we must
                     30:  * go on after first detecting the error.
                     31:  */
                     32: char   *exerr;                 /* Execution error message */
                     33: char   *expath;                /* Path for exerr */
                     34: 
                     35: /*
                     36:  * Xhash is an array of HSHSIZ bits (HSHSIZ / 8 chars), which are used
                     37:  * to hash execs.  If it is allocated (havhash true), then to tell
                     38:  * whether ``name'' is (possibly) present in the i'th component
                     39:  * of the variable path, you look at the bit in xhash indexed by
                     40:  * hash(hashname("name"), i).  This is setup automatically
                     41:  * after .login is executed, and recomputed whenever ``path'' is
                     42:  * changed.
                     43:  * The two part hash function is designed to let texec() call the
                     44:  * more expensive hashname() only once and the simple hash() several
                     45:  * times (once for each path component checked).
                     46:  * Byte size is assumed to be 8.
                     47:  */
                     48: #define        HSHSIZ          8192                    /* 1k bytes */
                     49: #define HSHMASK                (HSHSIZ - 1)
                     50: #define HSHMUL         243
                     51: char   xhash[HSHSIZ / 8];
                     52: #define hash(a, b)     ((a) * HSHMUL + (b) & HSHMASK)
                     53: #define bit(h, b)      ((h)[(b) >> 3] & 1 << ((b) & 7))        /* bit test */
                     54: #define bis(h, b)      ((h)[(b) >> 3] |= 1 << ((b) & 7))       /* bit set */
                     55: #ifdef VFORK
                     56: int    hits, misses;
                     57: #endif
                     58: 
                     59: /* Dummy search path for just absolute search when no path */
                     60: char   *justabs[] =    { "", 0 };
                     61: 
                     62: doexec(t)
                     63:        register struct command *t;
                     64: {
                     65:        char *sav;
                     66:        register char *dp, **pv, **av;
                     67:        register struct varent *v;
                     68:        bool slash = any('/', t->t_dcom[0]);
                     69:        int hashval, hashval1, i;
                     70:        char *blk[2];
                     71: 
                     72:        /*
                     73:         * Glob the command name.  If this does anything, then we
                     74:         * will execute the command only relative to ".".  One special
                     75:         * case: if there is no PATH, then we execute only commands
                     76:         * which start with '/'.
                     77:         */
                     78:        dp = globone(t->t_dcom[0]);
                     79:        sav = t->t_dcom[0];
                     80:        exerr = 0; expath = t->t_dcom[0] = dp;
                     81:        xfree(sav);
                     82:        v = adrof("path");
                     83:        if (v == 0 && expath[0] != '/')
                     84:                pexerr();
                     85:        slash |= gflag;
                     86: 
                     87:        /*
                     88:         * Glob the argument list, if necessary.
                     89:         * Otherwise trim off the quote bits.
                     90:         */
                     91:        gflag = 0; av = &t->t_dcom[1];
                     92:        tglob(av);
                     93:        if (gflag) {
                     94:                av = glob(av);
                     95:                if (av == 0)
                     96:                        error("No match");
                     97:        }
                     98:        blk[0] = t->t_dcom[0];
                     99:        blk[1] = 0;
                    100:        av = blkspl(blk, av);
                    101: #ifdef VFORK
                    102:        Vav = av;
                    103: #endif
                    104:        trim(av);
                    105: 
                    106:        xechoit(av);            /* Echo command if -x */
                    107:        /*
                    108:         * Since all internal file descriptors are set to close on exec,
                    109:         * we don't need to close them explicitly here.  Just reorient
                    110:         * ourselves for error messages.
                    111:         */
                    112:        SHIN = 0; SHOUT = 1; SHDIAG = 2; OLDSTD = 0;
                    113: 
                    114:        /*
                    115:         * We must do this AFTER any possible forking (like `foo`
                    116:         * in glob) so that this shell can still do subprocesses.
                    117:         */
                    118:        (void) sigsetmask(0);
                    119: 
                    120:        /*
                    121:         * If no path, no words in path, or a / in the filename
                    122:         * then restrict the command search.
                    123:         */
                    124:        if (v == 0 || v->vec[0] == 0 || slash)
                    125:                pv = justabs;
                    126:        else
                    127:                pv = v->vec;
                    128:        sav = strspl("/", *av);         /* / command name for postpending */
                    129: #ifdef VFORK
                    130:        Vsav = sav;
                    131: #endif
                    132:        if (havhash)
                    133:                hashval = hashname(*av);
                    134:        i = 0;
                    135: #ifdef VFORK
                    136:        hits++;
                    137: #endif
                    138:        do {
                    139:                if (!slash && pv[0][0] == '/' && havhash) {
                    140:                        hashval1 = hash(hashval, i);
                    141:                        if (!bit(xhash, hashval1))
                    142:                                goto cont;
                    143:                }
                    144:                if (pv[0][0] == 0 || eq(pv[0], "."))    /* don't make ./xxx */
                    145:                        texec(*av, av);
                    146:                else {
                    147:                        dp = strspl(*pv, sav);
                    148: #ifdef VFORK
                    149:                        Vdp = dp;
                    150: #endif
                    151:                        texec(dp, av);
                    152: #ifdef VFORK
                    153:                        Vdp = 0;
                    154: #endif
                    155:                        xfree(dp);
                    156:                }
                    157: #ifdef VFORK
                    158:                misses++;
                    159: #endif
                    160: cont:
                    161:                pv++;
                    162:                i++;
                    163:        } while (*pv);
                    164: #ifdef VFORK
                    165:        hits--;
                    166: #endif
                    167: #ifdef VFORK
                    168:        Vsav = 0;
                    169:        Vav = 0;
                    170: #endif
                    171:        xfree(sav);
                    172:        xfree((char *)av);
                    173:        pexerr();
                    174: }
                    175: 
                    176: pexerr()
                    177: {
                    178: 
                    179:        /* Couldn't find the damn thing */
                    180:        setname(expath);
                    181:        /* xfree(expath); */
                    182:        if (exerr)
                    183:                bferr(exerr);
                    184:        bferr("Command not found");
                    185: }
                    186: 
                    187: /*
                    188:  * Execute command f, arg list t.
                    189:  * Record error message if not found.
                    190:  * Also do shell scripts here.
                    191:  */
                    192: texec(f, t)
                    193:        char *f;
                    194:        register char **t;
                    195: {
                    196:        register struct varent *v;
                    197:        register char **vp;
                    198:        extern char *sys_errlist[];
                    199:        char *lastsh[2];
                    200: 
                    201:        execv(f, t);
                    202:        switch (errno) {
                    203: 
                    204:        case ENOEXEC:
                    205:                /*
                    206:                 * If there is an alias for shell, then
                    207:                 * put the words of the alias in front of the
                    208:                 * argument list replacing the command name.
                    209:                 * Note no interpretation of the words at this point.
                    210:                 */
                    211:                v = adrof1("shell", &aliases);
                    212:                if (v == 0) {
                    213: #ifdef OTHERSH
                    214:                        register int ff = open(f, 0);
                    215:                        char ch;
                    216: #endif
                    217: 
                    218:                        vp = lastsh;
                    219:                        vp[0] = adrof("shell") ? value("shell") : SHELLPATH;
                    220:                        vp[1] = (char *) NULL;
                    221: #ifdef OTHERSH
                    222:                        if (ff != -1 && read(ff, &ch, 1) == 1 && ch != '#')
                    223:                                vp[0] = OTHERSH;
                    224:                        (void) close(ff);
                    225: #endif
                    226:                } else
                    227:                        vp = v->vec;
                    228:                t[0] = f;
                    229:                t = blkspl(vp, t);              /* Splice up the new arglst */
                    230:                f = *t;
                    231:                execv(f, t);
                    232:                xfree((char *)t);
                    233:                /* The sky is falling, the sky is falling! */
                    234: 
                    235:        case ENOMEM:
                    236:                Perror(f);
                    237: 
                    238:        case ENOENT:
                    239:                break;
                    240: 
                    241:        default:
                    242:                if (exerr == 0) {
                    243:                        exerr = sys_errlist[errno];
                    244:                        expath = savestr(f);
                    245:                }
                    246:        }
                    247: }
                    248: 
                    249: /*ARGSUSED*/
                    250: execash(t, kp)
                    251:        char **t;
                    252:        register struct command *kp;
                    253: {
                    254: 
                    255:        rechist();
                    256:        (void) signal(SIGINT, parintr);
                    257:        (void) signal(SIGQUIT, parintr);
                    258:        (void) signal(SIGTERM, parterm);        /* if doexec loses, screw */
                    259:        lshift(kp->t_dcom, 1);
                    260:        exiterr++;
                    261:        doexec(kp);
                    262:        /*NOTREACHED*/
                    263: }
                    264: 
                    265: xechoit(t)
                    266:        char **t;
                    267: {
                    268: 
                    269:        if (adrof("echo")) {
                    270:                flush();
                    271:                haderr = 1;
                    272:                blkpr(t), putchar('\n');
                    273:                haderr = 0;
                    274:        }
                    275: }
                    276: 
                    277: /*VARARGS0*//*ARGSUSED*/
                    278: dohash(v)
                    279:        char **v;
                    280: {
                    281:        struct stat stb;
                    282:        DIR *dirp;
                    283:        register struct direct *dp;
                    284:        register int cnt;
                    285:        int i = 0;
                    286:        struct varent *v = adrof("path");
                    287:        char **pv;
                    288:        int hashval;
                    289: 
                    290:        havhash = 1;
                    291:        for (cnt = 0; cnt < sizeof xhash; cnt++)
                    292:                xhash[cnt] = 0;
                    293:        if (v == 0)
                    294:                return;
                    295:        for (pv = v->vec; *pv; pv++, i++) {
                    296:                if (pv[0][0] != '/')
                    297:                        continue;
                    298:                dirp = opendir(*pv);
                    299:                if (dirp == NULL)
                    300:                        continue;
                    301:                if (fstat(dirp->dd_fd, &stb) < 0 || !isdir(stb)) {
                    302:                        closedir(dirp);
                    303:                        continue;
                    304:                }
                    305:                while ((dp = readdir(dirp)) != NULL) {
                    306:                        if (dp->d_ino == 0)
                    307:                                continue;
                    308:                        if (dp->d_name[0] == '.' &&
                    309:                            (dp->d_name[1] == '\0' ||
                    310:                             dp->d_name[1] == '.' && dp->d_name[2] == '\0'))
                    311:                                continue;
                    312:                        hashval = hash(hashname(dp->d_name), i);
                    313:                        bis(xhash, hashval);
                    314:                }
                    315:                closedir(dirp);
                    316:        }
                    317: }
                    318: 
                    319: dounhash()
                    320: {
                    321: 
                    322:        havhash = 0;
                    323: }
                    324: 
                    325: #ifdef VFORK
                    326: hashstat()
                    327: {
                    328: 
                    329:        if (hits+misses)
                    330:                printf("%d hits, %d misses, %d%%\n",
                    331:                        hits, misses, 100 * hits / (hits + misses));
                    332: }
                    333: #endif
                    334: 
                    335: /*
                    336:  * Hash a command name.
                    337:  */
                    338: hashname(cp)
                    339:        register char *cp;
                    340: {
                    341:        register long h = 0;
                    342: 
                    343:        while (*cp)
                    344:                h = hash(h, *cp++);
                    345:        return ((int) h);
                    346: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.