exec.c

Go to the documentation of this file.
00001 /*-
00002  * Copyright (c) 1991 The Regents of the University of California.
00003  * All rights reserved.
00004  *
00005  * This code is derived from software contributed to Berkeley by
00006  * Kenneth Almquist.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions
00010  * are met:
00011  * 1. Redistributions of source code must retain the above copyright
00012  *    notice, this list of conditions and the following disclaimer.
00013  * 2. Redistributions in binary form must reproduce the above copyright
00014  *    notice, this list of conditions and the following disclaimer in the
00015  *    documentation and/or other materials provided with the distribution.
00016  * 3. All advertising materials mentioning features or use of this software
00017  *    must display the following acknowledgement:
00018  *      This product includes software developed by the University of
00019  *      California, Berkeley and its contributors.
00020  * 4. Neither the name of the University nor the names of its contributors
00021  *    may be used to endorse or promote products derived from this software
00022  *    without specific prior written permission.
00023  *
00024  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00025  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00026  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00027  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00028  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00029  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00030  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00031  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00032  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00033  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00034  * SUCH DAMAGE.
00035  */
00036 
00037 #ifndef lint
00038 static char sccsid[] = "@(#)exec.c      5.2 (Berkeley) 3/13/91";
00039 #endif /* not lint */
00040 
00041 /*
00042  * When commands are first encountered, they are entered in a hash table.
00043  * This ensures that a full path search will not have to be done for them
00044  * on each invocation.
00045  *
00046  * We should investigate converting to a linear search, even though that
00047  * would make the command name "hash" a misnomer.
00048  */
00049 
00050 #include "shell.h"
00051 #include "main.h"
00052 #include "nodes.h"
00053 #include "parser.h"
00054 #include "redir.h"
00055 #include "eval.h"
00056 #include "exec.h"
00057 #include "builtins.h"
00058 #include "var.h"
00059 #include "options.h"
00060 #include "input.h"
00061 #include "output.h"
00062 #include "syntax.h"
00063 #include "memalloc.h"
00064 #include "error.h"
00065 #include "init.h"
00066 #include "mystring.h"
00067 #include <sys/types.h>
00068 #include <sys/stat.h>
00069 #include <fcntl.h>
00070 #include <errno.h>
00071 #include <limits.h>
00072 
00073 
00074 #define CMDTABLESIZE 31         /* should be prime */
00075 #define ARB 1                   /* actual size determined at run time */
00076 
00077 
00078 
00079 struct tblentry {
00080         struct tblentry *next;  /* next entry in hash chain */
00081         union param param;      /* definition of builtin function */
00082         short cmdtype;          /* index identifying command */
00083         char rehash;            /* if set, cd done since entry created */
00084         char cmdname[ARB];      /* name of command */
00085 };
00086 
00087 
00088 STATIC struct tblentry *cmdtable[CMDTABLESIZE];
00089 STATIC int builtinloc = -1;             /* index in path of %builtin, or -1 */
00090 
00091 
00092 #ifdef __STDC__
00093 STATIC void tryexec(char *, char **, char **);
00094 STATIC void execinterp(char **, char **);
00095 STATIC void printentry(struct tblentry *);
00096 STATIC void clearcmdentry(int);
00097 STATIC struct tblentry *cmdlookup(char *, int);
00098 STATIC void delete_cmd_entry(void);
00099 #else
00100 STATIC void tryexec();
00101 STATIC void execinterp();
00102 STATIC void printentry();
00103 STATIC void clearcmdentry();
00104 STATIC struct tblentry *cmdlookup();
00105 STATIC void delete_cmd_entry();
00106 #endif
00107 
00108 
00109 
00110 /*
00111  * Exec a program.  Never returns.  If you change this routine, you may
00112  * have to change the find_command routine as well.
00113  */
00114 
00115 void
00116 shellexec(argv, envp, path, index)
00117         char **argv, **envp;
00118         char *path;
00119         {
00120         char *cmdname;
00121         int e;
00122 
00123         if (strchr(argv[0], '/') != NULL) {
00124                 tryexec(argv[0], argv, envp);
00125                 e = errno;
00126         } else {
00127                 e = ENOENT;
00128                 while ((cmdname = padvance(&path, argv[0])) != NULL) {
00129                         if (--index < 0 && pathopt == NULL) {
00130                                 tryexec(cmdname, argv, envp);
00131                                 if (errno != ENOENT && errno != ENOTDIR)
00132                                         e = errno;
00133                         }
00134                         stunalloc(cmdname);
00135                 }
00136         }
00137         error2(argv[0], errmsg(e, E_EXEC));
00138 }
00139 
00140 
00141 STATIC void
00142 tryexec(cmd, argv, envp)
00143         char *cmd;
00144         char **argv;
00145         char **envp;
00146         {
00147         int e;
00148         char *p;
00149 
00150 #ifdef SYSV
00151         do {
00152                 execve(cmd, argv, envp);
00153         } while (errno == EINTR);
00154 #else
00155         execve(cmd, argv, envp);
00156 #endif
00157 #if HASHBANG
00158         e = errno;
00159         if (e == ENOEXEC) {
00160                 initshellproc();
00161                 setinputfile(cmd, 0);
00162                 commandname = arg0 = savestr(argv[0]);
00163 #ifndef BSD
00164                 pgetc(); pungetc();             /* fill up input buffer */
00165                 p = parsenextc;
00166                 if (parsenleft > 2 && p[0] == '#' && p[1] == '!') {
00167                         argv[0] = cmd;
00168                         execinterp(argv, envp);
00169                 }
00170 #endif
00171                 setparam(argv + 1);
00172                 exraise(EXSHELLPROC);
00173                 /*NOTREACHED*/
00174         }
00175         errno = e;
00176 #endif
00177 }
00178 
00179 
00180 #if !defined(BSD) && HASHBANG
00181 /*
00182  * Execute an interpreter introduced by "#!", for systems where this
00183  * feature has not been built into the kernel.  If the interpreter is
00184  * the shell, return (effectively ignoring the "#!").  If the execution
00185  * of the interpreter fails, exit.
00186  *
00187  * This code peeks inside the input buffer in order to avoid actually
00188  * reading any input.  It would benefit from a rewrite.
00189  */
00190 
00191 #define NEWARGS 5
00192 
00193 STATIC void
00194 execinterp(argv, envp)
00195         char **argv, **envp;
00196         {
00197         int n;
00198         char *inp;
00199         char *outp;
00200         char c;
00201         char *p;
00202         char **ap;
00203         char *newargs[NEWARGS];
00204         int i;
00205         char **ap2;
00206         char **new;
00207 
00208         n = parsenleft - 2;
00209         inp = parsenextc + 2;
00210         ap = newargs;
00211         for (;;) {
00212                 while (--n >= 0 && (*inp == ' ' || *inp == '\t'))
00213                         inp++;
00214                 if (n < 0)
00215                         goto bad;
00216                 if ((c = *inp++) == '\n')
00217                         break;
00218                 if (ap == &newargs[NEWARGS])
00219 bad:              error("Bad #! line");
00220                 STARTSTACKSTR(outp);
00221                 do {
00222                         STPUTC(c, outp);
00223                 } while (--n >= 0 && (c = *inp++) != ' ' && c != '\t' && c != '\n');
00224                 STPUTC('\0', outp);
00225                 n++, inp--;
00226                 *ap++ = grabstackstr(outp);
00227         }
00228 #if !__minix
00229         if (ap == newargs + 1) {        /* if no args, maybe no exec is needed */
00230                 p = newargs[0];
00231                 for (;;) {
00232                         if (equal(p, "sh") || equal(p, "ash")) {
00233                                 return;
00234                         }
00235                         while (*p != '/') {
00236                                 if (*p == '\0')
00237                                         goto break2;
00238                                 p++;
00239                         }
00240                         p++;
00241                 }
00242 break2:;
00243         }
00244 #endif
00245         i = (char *)ap - (char *)newargs;               /* size in bytes */
00246         if (i == 0)
00247                 error("Bad #! line");
00248         for (ap2 = argv ; *ap2++ != NULL ; );
00249         new = ckmalloc(i + ((char *)ap2 - (char *)argv));
00250         ap = newargs, ap2 = new;
00251         while ((i -= sizeof (char **)) >= 0)
00252                 *ap2++ = *ap++;
00253         ap = argv;
00254         while (*ap2++ = *ap++);
00255         shellexec(new, envp, pathval(), 0);
00256 }
00257 #endif
00258 
00259 
00260 
00261 /*
00262  * Do a path search.  The variable path (passed by reference) should be
00263  * set to the start of the path before the first call; padvance will update
00264  * this value as it proceeds.  Successive calls to padvance will return
00265  * the possible path expansions in sequence.  If an option (indicated by
00266  * a percent sign) appears in the path entry then the global variable
00267  * pathopt will be set to point to it; otherwise pathopt will be set to
00268  * NULL.
00269  */
00270 
00271 char *pathopt;
00272 
00273 char *
00274 padvance(path, name)
00275         char **path;
00276         char *name;
00277         {
00278         register char *p, *q;
00279         char *start;
00280         int len;
00281 
00282         if (*path == NULL)
00283                 return NULL;
00284         start = *path;
00285         for (p = start ; *p && *p != ':' && *p != '%' ; p++);
00286         len = p - start + strlen(name) + 2;     /* "2" is for '/' and '\0' */
00287         while (stackblocksize() < len)
00288                 growstackblock();
00289         q = stackblock();
00290         if (p != start) {
00291                 bcopy(start, q, p - start);
00292                 q += p - start;
00293                 *q++ = '/';
00294         }
00295         strcpy(q, name);
00296         pathopt = NULL;
00297         if (*p == '%') {
00298                 pathopt = ++p;
00299                 while (*p && *p != ':')  p++;
00300         }
00301         if (*p == ':')
00302                 *path = p + 1;
00303         else
00304                 *path = NULL;
00305         return stalloc(len);
00306 }
00307 
00308 
00309 
00310 /*** Command hashing code ***/
00311 
00312 
00313 hashcmd(argc, argv)  char **argv; {
00314         struct tblentry **pp;
00315         struct tblentry *cmdp;
00316         int c;
00317         int verbose;
00318         struct cmdentry entry;
00319         char *name;
00320 
00321         if (argc <= 1) {
00322                 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
00323                         for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
00324                                 printentry(cmdp);
00325                         }
00326                 }
00327                 return 0;
00328         }
00329         verbose = 0;
00330         while ((c = nextopt("rv")) != '\0') {
00331                 if (c == 'r') {
00332                         clearcmdentry(0);
00333                 } else if (c == 'v') {
00334                         verbose++;
00335                 }
00336         }
00337         while ((name = *argptr) != NULL) {
00338                 if ((cmdp = cmdlookup(name, 0)) != NULL
00339                  && (cmdp->cmdtype == CMDNORMAL
00340                      || cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
00341                         delete_cmd_entry();
00342                 find_command(name, &entry, 1);
00343                 if (verbose) {
00344                         if (entry.cmdtype != CMDUNKNOWN) {      /* if no error msg */
00345                                 cmdp = cmdlookup(name, 0);
00346                                 printentry(cmdp);
00347                         }
00348                         flushall();
00349                 }
00350                 argptr++;
00351         }
00352         return 0;
00353 }
00354 
00355 
00356 STATIC void
00357 printentry(cmdp)
00358         struct tblentry *cmdp;
00359         {
00360         int index;
00361         char *path;
00362         char *name;
00363 
00364         if (cmdp->cmdtype == CMDNORMAL) {
00365                 index = cmdp->param.index;
00366                 path = pathval();
00367                 do {
00368                         name = padvance(&path, cmdp->cmdname);
00369                         stunalloc(name);
00370                 } while (--index >= 0);
00371                 out1str(name);
00372         } else if (cmdp->cmdtype == CMDBUILTIN) {
00373                 out1fmt("builtin %s", cmdp->cmdname);
00374         } else if (cmdp->cmdtype == CMDFUNCTION) {
00375                 out1fmt("function %s", cmdp->cmdname);
00376 #if DEBUG
00377         } else {
00378                 error("internal error: cmdtype %d", cmdp->cmdtype);
00379 #endif
00380         }
00381         if (cmdp->rehash)
00382                 out1c('*');
00383         out1c('\n');
00384 }
00385 
00386 
00387 
00388 /*
00389  * Resolve a command name.  If you change this routine, you may have to
00390  * change the shellexec routine as well.
00391  */
00392 
00393 void
00394 find_command(name, entry, printerr)
00395         char *name;
00396         struct cmdentry *entry;
00397         {
00398         struct tblentry *cmdp;
00399         int index;
00400         int prev;
00401         char *path;
00402         char *fullname;
00403         struct stat statb;
00404         int e;
00405         int i;
00406 
00407         /* If name contains a slash, don't use the hash table */
00408         if (strchr(name, '/') != NULL) {
00409                 entry->cmdtype = CMDNORMAL;
00410                 entry->u.index = 0;
00411                 return;
00412         }
00413 
00414         /* If name is in the table, and not invalidated by cd, we're done */
00415         if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0)
00416                 goto success;
00417 
00418         /* If %builtin not in path, check for builtin next */
00419         if (builtinloc < 0 && (i = find_builtin(name)) >= 0) {
00420                 INTOFF;
00421                 cmdp = cmdlookup(name, 1);
00422                 cmdp->cmdtype = CMDBUILTIN;
00423                 cmdp->param.index = i;
00424                 INTON;
00425                 goto success;
00426         }
00427 
00428         /* We have to search path. */
00429         prev = -1;              /* where to start */
00430         if (cmdp) {             /* doing a rehash */
00431                 if (cmdp->cmdtype == CMDBUILTIN)
00432                         prev = builtinloc;
00433                 else
00434                         prev = cmdp->param.index;
00435         }
00436 
00437         path = pathval();
00438         e = ENOENT;
00439         index = -1;
00440 loop:
00441         while ((fullname = padvance(&path, name)) != NULL) {
00442                 stunalloc(fullname);
00443                 index++;
00444                 if (pathopt) {
00445                         if (prefix("builtin", pathopt)) {
00446                                 if ((i = find_builtin(name)) < 0)
00447                                         goto loop;
00448                                 INTOFF;
00449                                 cmdp = cmdlookup(name, 1);
00450                                 cmdp->cmdtype = CMDBUILTIN;
00451                                 cmdp->param.index = i;
00452                                 INTON;
00453                                 goto success;
00454                         } else if (prefix("func", pathopt)) {
00455                                 /* handled below */
00456                         } else {
00457                                 goto loop;      /* ignore unimplemented options */
00458                         }
00459                 }
00460                 /* if rehash, don't redo absolute path names */
00461                 if (fullname[0] == '/' && index <= prev) {
00462                         if (index < prev)
00463                                 goto loop;
00464                         TRACE(("searchexec \"%s\": no change\n", name));
00465                         goto success;
00466                 }
00467                 while (stat(fullname, &statb) < 0) {
00468 #ifdef SYSV
00469                         if (errno == EINTR)
00470                                 continue;
00471 #endif
00472                         if (errno != ENOENT && errno != ENOTDIR)
00473                                 e = errno;
00474                         goto loop;
00475                 }
00476                 e = EACCES;     /* if we fail, this will be the error */
00477                 if ((statb.st_mode & S_IFMT) != S_IFREG)
00478                         goto loop;
00479                 if (pathopt) {          /* this is a %func directory */
00480                         stalloc(strlen(fullname) + 1);
00481                         readcmdfile(fullname);
00482                         if ((cmdp = cmdlookup(name, 0)) == NULL || cmdp->cmdtype != CMDFUNCTION)
00483                                 error("%s not defined in %s", name, fullname);
00484                         stunalloc(fullname);
00485                         goto success;
00486                 }
00487                 if (statb.st_uid == geteuid()) {
00488                         if ((statb.st_mode & 0100) == 0)
00489                                 goto loop;
00490                 } else if (statb.st_gid == getegid()) {
00491                         if ((statb.st_mode & 010) == 0)
00492                                 goto loop;
00493                 } else {
00494 #if __minix_vmd || defined(BSD)
00495                         gid_t group_list[NGROUPS_MAX];
00496                         int ngroups, i;
00497 
00498                         ngroups = getgroups(NGROUPS_MAX, group_list);
00499 
00500                         for (i = 0; i < ngroups; i++) {
00501                                 if (statb.st_gid == group_list[i]) break;
00502                         }
00503                         if (i < ngroups) {
00504                                 if ((statb.st_mode & 010) == 0)
00505                                         goto loop;
00506                         } else
00507 #endif
00508                         if ((statb.st_mode & 01) == 0)
00509                                 goto loop;
00510                 }
00511                 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
00512                 INTOFF;
00513                 cmdp = cmdlookup(name, 1);
00514                 cmdp->cmdtype = CMDNORMAL;
00515                 cmdp->param.index = index;
00516                 INTON;
00517                 goto success;
00518         }
00519 
00520         /* We failed.  If there was an entry for this command, delete it */
00521         if (cmdp)
00522                 delete_cmd_entry();
00523         if (printerr)
00524                 outfmt(out2, "%s: %s\n", name, errmsg(e, E_EXEC));
00525         entry->cmdtype = CMDUNKNOWN;
00526         return;
00527 
00528 success:
00529         cmdp->rehash = 0;
00530         entry->cmdtype = cmdp->cmdtype;
00531         entry->u = cmdp->param;
00532 }
00533 
00534 
00535 
00536 /*
00537  * Search the table of builtin commands.
00538  */
00539 
00540 int
00541 find_builtin(name)
00542         char *name;
00543         {
00544         const register struct builtincmd *bp;
00545 
00546         for (bp = builtincmd ; bp->name ; bp++) {
00547                 if (*bp->name == *name && equal(bp->name, name))
00548                         return bp->code;
00549         }
00550         return -1;
00551 }
00552 
00553 
00554 
00555 /*
00556  * Called when a cd is done.  Marks all commands so the next time they
00557  * are executed they will be rehashed.
00558  */
00559 
00560 void
00561 hashcd() {
00562         struct tblentry **pp;
00563         struct tblentry *cmdp;
00564 
00565         for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
00566                 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
00567                         if (cmdp->cmdtype == CMDNORMAL
00568                          || cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)
00569                                 cmdp->rehash = 1;
00570                 }
00571         }
00572 }
00573 
00574 
00575 
00576 /*
00577  * Called before PATH is changed.  The argument is the new value of PATH;
00578  * pathval() still returns the old value at this point.  Called with
00579  * interrupts off.
00580  */
00581 
00582 void
00583 changepath(newval)
00584         char *newval;
00585         {
00586         char *old, *new;
00587         int index;
00588         int firstchange;
00589         int bltin;
00590 
00591         old = pathval();
00592         new = newval;
00593         firstchange = 9999;     /* assume no change */
00594         index = 0;
00595         bltin = -1;
00596         for (;;) {
00597                 if (*old != *new) {
00598                         firstchange = index;
00599                         if (*old == '\0' && *new == ':'
00600                          || *old == ':' && *new == '\0')
00601                                 firstchange++;
00602                         old = new;      /* ignore subsequent differences */
00603                 }
00604                 if (*new == '\0')
00605                         break;
00606                 if (*new == '%' && bltin < 0 && prefix("builtin", new + 1))
00607                         bltin = index;
00608                 if (*new == ':') {
00609                         index++;
00610                 }
00611                 new++, old++;
00612         }
00613         if (builtinloc < 0 && bltin >= 0)
00614                 builtinloc = bltin;             /* zap builtins */
00615         if (builtinloc >= 0 && bltin < 0)
00616                 firstchange = 0;
00617         clearcmdentry(firstchange);
00618         builtinloc = bltin;
00619 }
00620 
00621 
00622 /*
00623  * Clear out command entries.  The argument specifies the first entry in
00624  * PATH which has changed.
00625  */
00626 
00627 STATIC void
00628 clearcmdentry(firstchange) {
00629         struct tblentry **tblp;
00630         struct tblentry **pp;
00631         struct tblentry *cmdp;
00632 
00633         INTOFF;
00634         for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
00635                 pp = tblp;
00636                 while ((cmdp = *pp) != NULL) {
00637                         if (cmdp->cmdtype == CMDNORMAL && cmdp->param.index >= firstchange
00638                          || cmdp->cmdtype == CMDBUILTIN && builtinloc >= firstchange) {
00639                                 *pp = cmdp->next;
00640                                 ckfree(cmdp);
00641                         } else {
00642                                 pp = &cmdp->next;
00643                         }
00644                 }
00645         }
00646         INTON;
00647 }
00648 
00649 
00650 /*
00651  * Delete all functions.
00652  */
00653 
00654 #ifdef mkinit
00655 MKINIT void deletefuncs();
00656 
00657 SHELLPROC {
00658         deletefuncs();
00659 }
00660 #endif
00661 
00662 void
00663 deletefuncs() {
00664         struct tblentry **tblp;
00665         struct tblentry **pp;
00666         struct tblentry *cmdp;
00667 
00668         INTOFF;
00669         for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
00670                 pp = tblp;
00671                 while ((cmdp = *pp) != NULL) {
00672                         if (cmdp->cmdtype == CMDFUNCTION) {
00673                                 *pp = cmdp->next;
00674                                 freefunc(cmdp->param.func);
00675                                 ckfree(cmdp);
00676                         } else {
00677                                 pp = &cmdp->next;
00678                         }
00679                 }
00680         }
00681         INTON;
00682 }
00683 
00684 
00685 
00686 /*
00687  * Locate a command in the command hash table.  If "add" is nonzero,
00688  * add the command to the table if it is not already present.  The
00689  * variable "lastcmdentry" is set to point to the address of the link
00690  * pointing to the entry, so that delete_cmd_entry can delete the
00691  * entry.
00692  */
00693 
00694 struct tblentry **lastcmdentry;
00695 
00696 
00697 STATIC struct tblentry *
00698 cmdlookup(name, add)
00699         char *name;
00700         {
00701         int hashval;
00702         register char *p;
00703         struct tblentry *cmdp;
00704         struct tblentry **pp;
00705 
00706         p = name;
00707         hashval = *p << 4;
00708         while (*p)
00709                 hashval += *p++;
00710         hashval &= 0x7FFF;
00711         pp = &cmdtable[hashval % CMDTABLESIZE];
00712         for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
00713                 if (equal(cmdp->cmdname, name))
00714                         break;
00715                 pp = &cmdp->next;
00716         }
00717         if (add && cmdp == NULL) {
00718                 INTOFF;
00719                 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
00720                                         + strlen(name) + 1);
00721                 cmdp->next = NULL;
00722                 cmdp->cmdtype = CMDUNKNOWN;
00723                 cmdp->rehash = 0;
00724                 strcpy(cmdp->cmdname, name);
00725                 INTON;
00726         }
00727         lastcmdentry = pp;
00728         return cmdp;
00729 }
00730 
00731 
00732 /*
00733  * Delete the command entry returned on the last lookup.
00734  */
00735 
00736 STATIC void
00737 delete_cmd_entry() {
00738         struct tblentry *cmdp;
00739 
00740         INTOFF;
00741         cmdp = *lastcmdentry;
00742         *lastcmdentry = cmdp->next;
00743         ckfree(cmdp);
00744         INTON;
00745 }
00746 
00747 
00748 
00749 #ifdef notdef
00750 void
00751 getcmdentry(name, entry)
00752         char *name;
00753         struct cmdentry *entry; 
00754         {
00755         struct tblentry *cmdp = cmdlookup(name, 0);
00756 
00757         if (cmdp) {
00758                 entry->u = cmdp->param;
00759                 entry->cmdtype = cmdp->cmdtype;
00760         } else {
00761                 entry->cmdtype = CMDUNKNOWN;
00762                 entry->u.index = 0;
00763         }
00764 }
00765 #endif
00766 
00767 
00768 /*
00769  * Add a new command entry, replacing any existing command entry for
00770  * the same name.
00771  */
00772 
00773 void
00774 addcmdentry(name, entry)
00775         char *name;
00776         struct cmdentry *entry;
00777         {
00778         struct tblentry *cmdp;
00779 
00780         INTOFF;
00781         cmdp = cmdlookup(name, 1);
00782         if (cmdp->cmdtype == CMDFUNCTION) {
00783                 freefunc(cmdp->param.func);
00784         }
00785         cmdp->cmdtype = entry->cmdtype;
00786         cmdp->param = entry->u;
00787         INTON;
00788 }
00789 
00790 
00791 /*
00792  * Define a shell function.
00793  */
00794 
00795 void
00796 defun(name, func)
00797         char *name;
00798         union node *func;
00799         {
00800         struct cmdentry entry;
00801 
00802         INTOFF;
00803         entry.cmdtype = CMDFUNCTION;
00804         entry.u.func = copyfunc(func);
00805         addcmdentry(name, &entry);
00806         INTON;
00807 }
00808 
00809 
00810 /*
00811  * Delete a function if it exists.
00812  */
00813 
00814 void
00815 unsetfunc(name)
00816         char *name;
00817         {
00818         struct tblentry *cmdp;
00819 
00820         if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) {
00821                 freefunc(cmdp->param.func);
00822                 delete_cmd_entry();
00823         }
00824 }

Generated on Fri Apr 14 22:56:40 2006 for minix by  doxygen 1.4.6