[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.15

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

CVSweb <webmaster@jp.NetBSD.org>