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

Annotation of src/bin/sh/exec.c, Revision 1.18

1.18    ! christos    1: /*     $NetBSD: exec.c,v 1.17 1995/06/09 01:53:50 christos Exp $       */
1.15      cgd         2:
1.1       cgd         3: /*-
1.8       jtc         4:  * Copyright (c) 1991, 1993
                      5:  *     The Regents of the University of California.  All rights reserved.
1.1       cgd         6:  *
                      7:  * This code is derived from software contributed to Berkeley by
                      8:  * Kenneth Almquist.
                      9:  *
                     10:  * Redistribution and use in source and binary forms, with or without
                     11:  * modification, are permitted provided that the following conditions
                     12:  * are met:
                     13:  * 1. Redistributions of source code must retain the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer.
                     15:  * 2. Redistributions in binary form must reproduce the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer in the
                     17:  *    documentation and/or other materials provided with the distribution.
                     18:  * 3. All advertising materials mentioning features or use of this software
                     19:  *    must display the following acknowledgement:
                     20:  *     This product includes software developed by the University of
                     21:  *     California, Berkeley and its contributors.
                     22:  * 4. Neither the name of the University nor the names of its contributors
                     23:  *    may be used to endorse or promote products derived from this software
                     24:  *    without specific prior written permission.
                     25:  *
                     26:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     27:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     28:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     29:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     30:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     31:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     32:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     33:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     34:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     35:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     36:  * SUCH DAMAGE.
                     37:  */
                     38:
                     39: #ifndef lint
1.15      cgd        40: #if 0
1.17      christos   41: static char sccsid[] = "@(#)exec.c     8.4 (Berkeley) 6/8/95";
1.15      cgd        42: #else
1.18    ! christos   43: static char rcsid[] = "$NetBSD: exec.c,v 1.17 1995/06/09 01:53:50 christos Exp $";
1.15      cgd        44: #endif
1.1       cgd        45: #endif /* not lint */
                     46:
1.16      christos   47: #include <sys/types.h>
                     48: #include <sys/stat.h>
                     49: #include <unistd.h>
                     50: #include <fcntl.h>
                     51: #include <errno.h>
                     52: #include <stdlib.h>
                     53:
1.1       cgd        54: /*
                     55:  * When commands are first encountered, they are entered in a hash table.
                     56:  * This ensures that a full path search will not have to be done for them
                     57:  * on each invocation.
                     58:  *
                     59:  * We should investigate converting to a linear search, even though that
                     60:  * would make the command name "hash" a misnomer.
                     61:  */
                     62:
                     63: #include "shell.h"
                     64: #include "main.h"
                     65: #include "nodes.h"
                     66: #include "parser.h"
                     67: #include "redir.h"
                     68: #include "eval.h"
                     69: #include "exec.h"
                     70: #include "builtins.h"
                     71: #include "var.h"
                     72: #include "options.h"
                     73: #include "input.h"
                     74: #include "output.h"
                     75: #include "syntax.h"
                     76: #include "memalloc.h"
                     77: #include "error.h"
                     78: #include "init.h"
                     79: #include "mystring.h"
1.16      christos   80: #include "show.h"
1.8       jtc        81: #include "jobs.h"
1.1       cgd        82:
                     83:
                     84: #define CMDTABLESIZE 31                /* should be prime */
                     85: #define ARB 1                  /* actual size determined at run time */
                     86:
                     87:
                     88:
                     89: struct tblentry {
                     90:        struct tblentry *next;  /* next entry in hash chain */
                     91:        union param param;      /* definition of builtin function */
                     92:        short cmdtype;          /* index identifying command */
                     93:        char rehash;            /* if set, cd done since entry created */
                     94:        char cmdname[ARB];      /* name of command */
                     95: };
                     96:
                     97:
                     98: STATIC struct tblentry *cmdtable[CMDTABLESIZE];
                     99: STATIC int builtinloc = -1;            /* index in path of %builtin, or -1 */
                    100:
                    101:
1.16      christos  102: STATIC void tryexec __P((char *, char **, char **));
                    103: STATIC void execinterp __P((char **, char **));
                    104: STATIC void printentry __P((struct tblentry *, int));
                    105: STATIC void clearcmdentry __P((int));
                    106: STATIC struct tblentry *cmdlookup __P((char *, int));
                    107: STATIC void delete_cmd_entry __P((void));
1.1       cgd       108:
                    109:
                    110:
                    111: /*
                    112:  * Exec a program.  Never returns.  If you change this routine, you may
                    113:  * have to change the find_command routine as well.
                    114:  */
                    115:
                    116: void
                    117: shellexec(argv, envp, path, index)
                    118:        char **argv, **envp;
                    119:        char *path;
1.12      cgd       120:        int index;
                    121: {
1.1       cgd       122:        char *cmdname;
                    123:        int e;
                    124:
                    125:        if (strchr(argv[0], '/') != NULL) {
                    126:                tryexec(argv[0], argv, envp);
                    127:                e = errno;
                    128:        } else {
                    129:                e = ENOENT;
                    130:                while ((cmdname = padvance(&path, argv[0])) != NULL) {
                    131:                        if (--index < 0 && pathopt == NULL) {
                    132:                                tryexec(cmdname, argv, envp);
                    133:                                if (errno != ENOENT && errno != ENOTDIR)
                    134:                                        e = errno;
                    135:                        }
                    136:                        stunalloc(cmdname);
                    137:                }
                    138:        }
                    139:        error2(argv[0], errmsg(e, E_EXEC));
                    140: }
                    141:
                    142:
                    143: STATIC void
                    144: tryexec(cmd, argv, envp)
                    145:        char *cmd;
                    146:        char **argv;
                    147:        char **envp;
                    148:        {
                    149:        int e;
1.16      christos  150: #ifndef BSD
1.1       cgd       151:        char *p;
1.16      christos  152: #endif
1.1       cgd       153:
                    154: #ifdef SYSV
                    155:        do {
                    156:                execve(cmd, argv, envp);
                    157:        } while (errno == EINTR);
                    158: #else
                    159:        execve(cmd, argv, envp);
                    160: #endif
                    161:        e = errno;
                    162:        if (e == ENOEXEC) {
                    163:                initshellproc();
                    164:                setinputfile(cmd, 0);
                    165:                commandname = arg0 = savestr(argv[0]);
                    166: #ifndef BSD
                    167:                pgetc(); pungetc();             /* fill up input buffer */
                    168:                p = parsenextc;
                    169:                if (parsenleft > 2 && p[0] == '#' && p[1] == '!') {
                    170:                        argv[0] = cmd;
                    171:                        execinterp(argv, envp);
                    172:                }
                    173: #endif
                    174:                setparam(argv + 1);
                    175:                exraise(EXSHELLPROC);
                    176:                /*NOTREACHED*/
                    177:        }
                    178:        errno = e;
                    179: }
                    180:
                    181:
                    182: #ifndef BSD
                    183: /*
                    184:  * Execute an interpreter introduced by "#!", for systems where this
                    185:  * feature has not been built into the kernel.  If the interpreter is
                    186:  * the shell, return (effectively ignoring the "#!").  If the execution
                    187:  * of the interpreter fails, exit.
                    188:  *
                    189:  * This code peeks inside the input buffer in order to avoid actually
                    190:  * reading any input.  It would benefit from a rewrite.
                    191:  */
                    192:
                    193: #define NEWARGS 5
                    194:
                    195: STATIC void
                    196: execinterp(argv, envp)
                    197:        char **argv, **envp;
                    198:        {
                    199:        int n;
                    200:        char *inp;
                    201:        char *outp;
                    202:        char c;
                    203:        char *p;
                    204:        char **ap;
                    205:        char *newargs[NEWARGS];
                    206:        int i;
                    207:        char **ap2;
                    208:        char **new;
                    209:
                    210:        n = parsenleft - 2;
                    211:        inp = parsenextc + 2;
                    212:        ap = newargs;
                    213:        for (;;) {
                    214:                while (--n >= 0 && (*inp == ' ' || *inp == '\t'))
                    215:                        inp++;
                    216:                if (n < 0)
                    217:                        goto bad;
                    218:                if ((c = *inp++) == '\n')
                    219:                        break;
                    220:                if (ap == &newargs[NEWARGS])
                    221: bad:             error("Bad #! line");
                    222:                STARTSTACKSTR(outp);
                    223:                do {
                    224:                        STPUTC(c, outp);
                    225:                } while (--n >= 0 && (c = *inp++) != ' ' && c != '\t' && c != '\n');
                    226:                STPUTC('\0', outp);
                    227:                n++, inp--;
                    228:                *ap++ = grabstackstr(outp);
                    229:        }
                    230:        if (ap == newargs + 1) {        /* if no args, maybe no exec is needed */
                    231:                p = newargs[0];
                    232:                for (;;) {
                    233:                        if (equal(p, "sh") || equal(p, "ash")) {
                    234:                                return;
                    235:                        }
                    236:                        while (*p != '/') {
                    237:                                if (*p == '\0')
                    238:                                        goto break2;
                    239:                                p++;
                    240:                        }
                    241:                        p++;
                    242:                }
                    243: break2:;
                    244:        }
                    245:        i = (char *)ap - (char *)newargs;               /* size in bytes */
                    246:        if (i == 0)
                    247:                error("Bad #! line");
                    248:        for (ap2 = argv ; *ap2++ != NULL ; );
                    249:        new = ckmalloc(i + ((char *)ap2 - (char *)argv));
                    250:        ap = newargs, ap2 = new;
                    251:        while ((i -= sizeof (char **)) >= 0)
                    252:                *ap2++ = *ap++;
                    253:        ap = argv;
                    254:        while (*ap2++ = *ap++);
                    255:        shellexec(new, envp, pathval(), 0);
                    256: }
                    257: #endif
                    258:
                    259:
                    260:
                    261: /*
                    262:  * Do a path search.  The variable path (passed by reference) should be
                    263:  * set to the start of the path before the first call; padvance will update
                    264:  * this value as it proceeds.  Successive calls to padvance will return
                    265:  * the possible path expansions in sequence.  If an option (indicated by
                    266:  * a percent sign) appears in the path entry then the global variable
                    267:  * pathopt will be set to point to it; otherwise pathopt will be set to
                    268:  * NULL.
                    269:  */
                    270:
                    271: char *pathopt;
                    272:
                    273: char *
                    274: padvance(path, name)
                    275:        char **path;
                    276:        char *name;
                    277:        {
                    278:        register char *p, *q;
                    279:        char *start;
                    280:        int len;
                    281:
                    282:        if (*path == NULL)
                    283:                return NULL;
                    284:        start = *path;
                    285:        for (p = start ; *p && *p != ':' && *p != '%' ; p++);
                    286:        len = p - start + strlen(name) + 2;     /* "2" is for '/' and '\0' */
                    287:        while (stackblocksize() < len)
                    288:                growstackblock();
                    289:        q = stackblock();
                    290:        if (p != start) {
1.11      mycroft   291:                memcpy(q, start, p - start);
1.1       cgd       292:                q += p - start;
                    293:                *q++ = '/';
                    294:        }
                    295:        strcpy(q, name);
                    296:        pathopt = NULL;
                    297:        if (*p == '%') {
                    298:                pathopt = ++p;
                    299:                while (*p && *p != ':')  p++;
                    300:        }
                    301:        if (*p == ':')
                    302:                *path = p + 1;
                    303:        else
                    304:                *path = NULL;
                    305:        return stalloc(len);
                    306: }
                    307:
                    308:
                    309:
                    310: /*** Command hashing code ***/
                    311:
                    312:
1.12      cgd       313: int
                    314: hashcmd(argc, argv)
                    315:        int argc;
                    316:        char **argv;
                    317: {
1.1       cgd       318:        struct tblentry **pp;
                    319:        struct tblentry *cmdp;
                    320:        int c;
                    321:        int verbose;
                    322:        struct cmdentry entry;
                    323:        char *name;
                    324:
                    325:        verbose = 0;
                    326:        while ((c = nextopt("rv")) != '\0') {
                    327:                if (c == 'r') {
                    328:                        clearcmdentry(0);
                    329:                } else if (c == 'v') {
                    330:                        verbose++;
                    331:                }
                    332:        }
1.8       jtc       333:        if (*argptr == NULL) {
                    334:                for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
                    335:                        for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
                    336:                                printentry(cmdp, verbose);
                    337:                        }
                    338:                }
                    339:                return 0;
                    340:        }
1.1       cgd       341:        while ((name = *argptr) != NULL) {
                    342:                if ((cmdp = cmdlookup(name, 0)) != NULL
                    343:                 && (cmdp->cmdtype == CMDNORMAL
1.16      christos  344:                     || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
1.1       cgd       345:                        delete_cmd_entry();
1.17      christos  346:                find_command(name, &entry, 1, pathval());
1.1       cgd       347:                if (verbose) {
                    348:                        if (entry.cmdtype != CMDUNKNOWN) {      /* if no error msg */
                    349:                                cmdp = cmdlookup(name, 0);
1.8       jtc       350:                                printentry(cmdp, verbose);
1.1       cgd       351:                        }
                    352:                        flushall();
                    353:                }
                    354:                argptr++;
                    355:        }
                    356:        return 0;
                    357: }
                    358:
                    359:
                    360: STATIC void
1.8       jtc       361: printentry(cmdp, verbose)
1.1       cgd       362:        struct tblentry *cmdp;
1.8       jtc       363:        int verbose;
1.1       cgd       364:        {
                    365:        int index;
                    366:        char *path;
                    367:        char *name;
                    368:
                    369:        if (cmdp->cmdtype == CMDNORMAL) {
                    370:                index = cmdp->param.index;
                    371:                path = pathval();
                    372:                do {
                    373:                        name = padvance(&path, cmdp->cmdname);
                    374:                        stunalloc(name);
                    375:                } while (--index >= 0);
                    376:                out1str(name);
                    377:        } else if (cmdp->cmdtype == CMDBUILTIN) {
                    378:                out1fmt("builtin %s", cmdp->cmdname);
                    379:        } else if (cmdp->cmdtype == CMDFUNCTION) {
                    380:                out1fmt("function %s", cmdp->cmdname);
1.8       jtc       381:                if (verbose) {
                    382:                        INTOFF;
                    383:                        name = commandtext(cmdp->param.func);
                    384:                        out1c(' ');
                    385:                        out1str(name);
                    386:                        ckfree(name);
                    387:                        INTON;
                    388:                }
1.1       cgd       389: #ifdef DEBUG
                    390:        } else {
                    391:                error("internal error: cmdtype %d", cmdp->cmdtype);
                    392: #endif
                    393:        }
                    394:        if (cmdp->rehash)
                    395:                out1c('*');
                    396:        out1c('\n');
                    397: }
                    398:
                    399:
                    400:
                    401: /*
                    402:  * Resolve a command name.  If you change this routine, you may have to
                    403:  * change the shellexec routine as well.
                    404:  */
                    405:
                    406: void
1.17      christos  407: find_command(name, entry, printerr, path)
1.1       cgd       408:        char *name;
                    409:        struct cmdentry *entry;
1.12      cgd       410:        int printerr;
1.17      christos  411:        char *path;
1.12      cgd       412: {
1.1       cgd       413:        struct tblentry *cmdp;
                    414:        int index;
                    415:        int prev;
                    416:        char *fullname;
                    417:        struct stat statb;
                    418:        int e;
                    419:        int i;
                    420:
                    421:        /* If name contains a slash, don't use the hash table */
                    422:        if (strchr(name, '/') != NULL) {
                    423:                entry->cmdtype = CMDNORMAL;
                    424:                entry->u.index = 0;
                    425:                return;
                    426:        }
                    427:
                    428:        /* If name is in the table, and not invalidated by cd, we're done */
                    429:        if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0)
                    430:                goto success;
                    431:
                    432:        /* If %builtin not in path, check for builtin next */
                    433:        if (builtinloc < 0 && (i = find_builtin(name)) >= 0) {
                    434:                INTOFF;
                    435:                cmdp = cmdlookup(name, 1);
                    436:                cmdp->cmdtype = CMDBUILTIN;
                    437:                cmdp->param.index = i;
                    438:                INTON;
                    439:                goto success;
                    440:        }
                    441:
                    442:        /* We have to search path. */
                    443:        prev = -1;              /* where to start */
                    444:        if (cmdp) {             /* doing a rehash */
                    445:                if (cmdp->cmdtype == CMDBUILTIN)
                    446:                        prev = builtinloc;
                    447:                else
                    448:                        prev = cmdp->param.index;
                    449:        }
                    450:
                    451:        e = ENOENT;
                    452:        index = -1;
                    453: loop:
                    454:        while ((fullname = padvance(&path, name)) != NULL) {
                    455:                stunalloc(fullname);
                    456:                index++;
                    457:                if (pathopt) {
                    458:                        if (prefix("builtin", pathopt)) {
                    459:                                if ((i = find_builtin(name)) < 0)
                    460:                                        goto loop;
                    461:                                INTOFF;
                    462:                                cmdp = cmdlookup(name, 1);
                    463:                                cmdp->cmdtype = CMDBUILTIN;
                    464:                                cmdp->param.index = i;
                    465:                                INTON;
                    466:                                goto success;
                    467:                        } else if (prefix("func", pathopt)) {
                    468:                                /* handled below */
                    469:                        } else {
                    470:                                goto loop;      /* ignore unimplemented options */
                    471:                        }
                    472:                }
                    473:                /* if rehash, don't redo absolute path names */
                    474:                if (fullname[0] == '/' && index <= prev) {
                    475:                        if (index < prev)
                    476:                                goto loop;
                    477:                        TRACE(("searchexec \"%s\": no change\n", name));
                    478:                        goto success;
                    479:                }
                    480:                while (stat(fullname, &statb) < 0) {
                    481: #ifdef SYSV
                    482:                        if (errno == EINTR)
                    483:                                continue;
                    484: #endif
                    485:                        if (errno != ENOENT && errno != ENOTDIR)
                    486:                                e = errno;
                    487:                        goto loop;
                    488:                }
                    489:                e = EACCES;     /* if we fail, this will be the error */
1.14      mycroft   490:                if (!S_ISREG(statb.st_mode))
1.1       cgd       491:                        goto loop;
                    492:                if (pathopt) {          /* this is a %func directory */
                    493:                        stalloc(strlen(fullname) + 1);
                    494:                        readcmdfile(fullname);
                    495:                        if ((cmdp = cmdlookup(name, 0)) == NULL || cmdp->cmdtype != CMDFUNCTION)
                    496:                                error("%s not defined in %s", name, fullname);
                    497:                        stunalloc(fullname);
                    498:                        goto success;
                    499:                }
1.8       jtc       500: #ifdef notdef
                    501:                if (statb.st_uid == geteuid()) {
1.1       cgd       502:                        if ((statb.st_mode & 0100) == 0)
                    503:                                goto loop;
                    504:                } else if (statb.st_gid == getegid()) {
                    505:                        if ((statb.st_mode & 010) == 0)
                    506:                                goto loop;
                    507:                } else {
1.8       jtc       508:                        if ((statb.st_mode & 01) == 0)
1.1       cgd       509:                                goto loop;
                    510:                }
1.4       cgd       511: #endif
1.1       cgd       512:                TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
                    513:                INTOFF;
                    514:                cmdp = cmdlookup(name, 1);
                    515:                cmdp->cmdtype = CMDNORMAL;
                    516:                cmdp->param.index = index;
                    517:                INTON;
                    518:                goto success;
                    519:        }
                    520:
                    521:        /* We failed.  If there was an entry for this command, delete it */
                    522:        if (cmdp)
                    523:                delete_cmd_entry();
                    524:        if (printerr)
                    525:                outfmt(out2, "%s: %s\n", name, errmsg(e, E_EXEC));
                    526:        entry->cmdtype = CMDUNKNOWN;
                    527:        return;
                    528:
                    529: success:
                    530:        cmdp->rehash = 0;
                    531:        entry->cmdtype = cmdp->cmdtype;
                    532:        entry->u = cmdp->param;
                    533: }
                    534:
                    535:
                    536:
                    537: /*
                    538:  * Search the table of builtin commands.
                    539:  */
                    540:
                    541: int
                    542: find_builtin(name)
                    543:        char *name;
1.12      cgd       544: {
                    545:        register const struct builtincmd *bp;
1.1       cgd       546:
                    547:        for (bp = builtincmd ; bp->name ; bp++) {
                    548:                if (*bp->name == *name && equal(bp->name, name))
                    549:                        return bp->code;
                    550:        }
                    551:        return -1;
                    552: }
                    553:
                    554:
                    555:
                    556: /*
                    557:  * Called when a cd is done.  Marks all commands so the next time they
                    558:  * are executed they will be rehashed.
                    559:  */
                    560:
                    561: void
                    562: hashcd() {
                    563:        struct tblentry **pp;
                    564:        struct tblentry *cmdp;
                    565:
                    566:        for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
                    567:                for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
                    568:                        if (cmdp->cmdtype == CMDNORMAL
1.16      christos  569:                         || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
1.1       cgd       570:                                cmdp->rehash = 1;
                    571:                }
                    572:        }
                    573: }
                    574:
                    575:
                    576:
                    577: /*
                    578:  * Called before PATH is changed.  The argument is the new value of PATH;
                    579:  * pathval() still returns the old value at this point.  Called with
                    580:  * interrupts off.
                    581:  */
                    582:
                    583: void
                    584: changepath(newval)
1.18    ! christos  585:        const char *newval;
1.13      mycroft   586: {
1.18    ! christos  587:        const char *old, *new;
1.1       cgd       588:        int index;
                    589:        int firstchange;
                    590:        int bltin;
                    591:
                    592:        old = pathval();
                    593:        new = newval;
                    594:        firstchange = 9999;     /* assume no change */
1.13      mycroft   595:        index = 0;
1.1       cgd       596:        bltin = -1;
                    597:        for (;;) {
                    598:                if (*old != *new) {
                    599:                        firstchange = index;
1.16      christos  600:                        if ((*old == '\0' && *new == ':')
                    601:                         || (*old == ':' && *new == '\0'))
1.1       cgd       602:                                firstchange++;
                    603:                        old = new;      /* ignore subsequent differences */
                    604:                }
                    605:                if (*new == '\0')
                    606:                        break;
                    607:                if (*new == '%' && bltin < 0 && prefix("builtin", new + 1))
                    608:                        bltin = index;
                    609:                if (*new == ':') {
                    610:                        index++;
                    611:                }
                    612:                new++, old++;
                    613:        }
                    614:        if (builtinloc < 0 && bltin >= 0)
                    615:                builtinloc = bltin;             /* zap builtins */
                    616:        if (builtinloc >= 0 && bltin < 0)
                    617:                firstchange = 0;
                    618:        clearcmdentry(firstchange);
                    619:        builtinloc = bltin;
                    620: }
                    621:
                    622:
                    623: /*
                    624:  * Clear out command entries.  The argument specifies the first entry in
                    625:  * PATH which has changed.
                    626:  */
                    627:
                    628: STATIC void
1.12      cgd       629: clearcmdentry(firstchange)
                    630:        int firstchange;
                    631: {
1.1       cgd       632:        struct tblentry **tblp;
                    633:        struct tblentry **pp;
                    634:        struct tblentry *cmdp;
                    635:
                    636:        INTOFF;
                    637:        for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
                    638:                pp = tblp;
                    639:                while ((cmdp = *pp) != NULL) {
1.16      christos  640:                        if ((cmdp->cmdtype == CMDNORMAL &&
                    641:                             cmdp->param.index >= firstchange)
                    642:                         || (cmdp->cmdtype == CMDBUILTIN &&
                    643:                             builtinloc >= firstchange)) {
1.1       cgd       644:                                *pp = cmdp->next;
                    645:                                ckfree(cmdp);
                    646:                        } else {
                    647:                                pp = &cmdp->next;
                    648:                        }
                    649:                }
                    650:        }
                    651:        INTON;
                    652: }
                    653:
                    654:
                    655: /*
                    656:  * Delete all functions.
                    657:  */
                    658:
                    659: #ifdef mkinit
                    660: MKINIT void deletefuncs();
                    661:
                    662: SHELLPROC {
                    663:        deletefuncs();
                    664: }
                    665: #endif
                    666:
                    667: void
                    668: deletefuncs() {
                    669:        struct tblentry **tblp;
                    670:        struct tblentry **pp;
                    671:        struct tblentry *cmdp;
                    672:
                    673:        INTOFF;
                    674:        for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
                    675:                pp = tblp;
                    676:                while ((cmdp = *pp) != NULL) {
                    677:                        if (cmdp->cmdtype == CMDFUNCTION) {
                    678:                                *pp = cmdp->next;
                    679:                                freefunc(cmdp->param.func);
                    680:                                ckfree(cmdp);
                    681:                        } else {
                    682:                                pp = &cmdp->next;
                    683:                        }
                    684:                }
                    685:        }
                    686:        INTON;
                    687: }
                    688:
                    689:
                    690:
                    691: /*
                    692:  * Locate a command in the command hash table.  If "add" is nonzero,
                    693:  * add the command to the table if it is not already present.  The
                    694:  * variable "lastcmdentry" is set to point to the address of the link
                    695:  * pointing to the entry, so that delete_cmd_entry can delete the
                    696:  * entry.
                    697:  */
                    698:
                    699: struct tblentry **lastcmdentry;
                    700:
                    701:
                    702: STATIC struct tblentry *
                    703: cmdlookup(name, add)
                    704:        char *name;
1.12      cgd       705:        int add;
                    706: {
1.1       cgd       707:        int hashval;
                    708:        register char *p;
                    709:        struct tblentry *cmdp;
                    710:        struct tblentry **pp;
                    711:
                    712:        p = name;
                    713:        hashval = *p << 4;
                    714:        while (*p)
                    715:                hashval += *p++;
                    716:        hashval &= 0x7FFF;
                    717:        pp = &cmdtable[hashval % CMDTABLESIZE];
                    718:        for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
                    719:                if (equal(cmdp->cmdname, name))
                    720:                        break;
                    721:                pp = &cmdp->next;
                    722:        }
                    723:        if (add && cmdp == NULL) {
                    724:                INTOFF;
                    725:                cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
                    726:                                        + strlen(name) + 1);
                    727:                cmdp->next = NULL;
                    728:                cmdp->cmdtype = CMDUNKNOWN;
                    729:                cmdp->rehash = 0;
                    730:                strcpy(cmdp->cmdname, name);
                    731:                INTON;
                    732:        }
                    733:        lastcmdentry = pp;
                    734:        return cmdp;
                    735: }
                    736:
                    737: /*
                    738:  * Delete the command entry returned on the last lookup.
                    739:  */
                    740:
                    741: STATIC void
                    742: delete_cmd_entry() {
                    743:        struct tblentry *cmdp;
                    744:
                    745:        INTOFF;
                    746:        cmdp = *lastcmdentry;
                    747:        *lastcmdentry = cmdp->next;
                    748:        ckfree(cmdp);
                    749:        INTON;
                    750: }
                    751:
                    752:
                    753:
                    754: #ifdef notdef
                    755: void
                    756: getcmdentry(name, entry)
                    757:        char *name;
                    758:        struct cmdentry *entry;
                    759:        {
                    760:        struct tblentry *cmdp = cmdlookup(name, 0);
                    761:
                    762:        if (cmdp) {
                    763:                entry->u = cmdp->param;
                    764:                entry->cmdtype = cmdp->cmdtype;
                    765:        } else {
                    766:                entry->cmdtype = CMDUNKNOWN;
                    767:                entry->u.index = 0;
                    768:        }
                    769: }
                    770: #endif
                    771:
                    772:
                    773: /*
                    774:  * Add a new command entry, replacing any existing command entry for
                    775:  * the same name.
                    776:  */
                    777:
                    778: void
                    779: addcmdentry(name, entry)
                    780:        char *name;
                    781:        struct cmdentry *entry;
                    782:        {
                    783:        struct tblentry *cmdp;
                    784:
                    785:        INTOFF;
                    786:        cmdp = cmdlookup(name, 1);
                    787:        if (cmdp->cmdtype == CMDFUNCTION) {
                    788:                freefunc(cmdp->param.func);
                    789:        }
                    790:        cmdp->cmdtype = entry->cmdtype;
                    791:        cmdp->param = entry->u;
                    792:        INTON;
                    793: }
                    794:
                    795:
                    796: /*
                    797:  * Define a shell function.
                    798:  */
                    799:
                    800: void
                    801: defun(name, func)
                    802:        char *name;
                    803:        union node *func;
                    804:        {
                    805:        struct cmdentry entry;
                    806:
                    807:        INTOFF;
                    808:        entry.cmdtype = CMDFUNCTION;
                    809:        entry.u.func = copyfunc(func);
                    810:        addcmdentry(name, &entry);
                    811:        INTON;
                    812: }
                    813:
                    814:
                    815: /*
                    816:  * Delete a function if it exists.
                    817:  */
                    818:
1.8       jtc       819: int
1.1       cgd       820: unsetfunc(name)
                    821:        char *name;
                    822:        {
                    823:        struct tblentry *cmdp;
                    824:
                    825:        if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) {
                    826:                freefunc(cmdp->param.func);
                    827:                delete_cmd_entry();
1.8       jtc       828:                return (0);
1.1       cgd       829:        }
1.8       jtc       830:        return (1);
1.1       cgd       831: }

CVSweb <webmaster@jp.NetBSD.org>