00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 #ifndef lint
00038 static char sccsid[] = "@(#)exec.c 5.2 (Berkeley) 3/13/91";
00039 #endif
00040
00041
00042
00043
00044
00045
00046
00047
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
00075 #define ARB 1
00076
00077
00078
00079 struct tblentry {
00080 struct tblentry *next;
00081 union param param;
00082 short cmdtype;
00083 char rehash;
00084 char cmdname[ARB];
00085 };
00086
00087
00088 STATIC struct tblentry *cmdtable[CMDTABLESIZE];
00089 STATIC int builtinloc = -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
00112
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();
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
00174 }
00175 errno = e;
00176 #endif
00177 }
00178
00179
00180 #if !defined(BSD) && HASHBANG
00181
00182
00183
00184
00185
00186
00187
00188
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) {
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;
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
00263
00264
00265
00266
00267
00268
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;
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
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) {
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
00390
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
00408 if (strchr(name, '/') != NULL) {
00409 entry->cmdtype = CMDNORMAL;
00410 entry->u.index = 0;
00411 return;
00412 }
00413
00414
00415 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0)
00416 goto success;
00417
00418
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
00429 prev = -1;
00430 if (cmdp) {
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
00456 } else {
00457 goto loop;
00458 }
00459 }
00460
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;
00477 if ((statb.st_mode & S_IFMT) != S_IFREG)
00478 goto loop;
00479 if (pathopt) {
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
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
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
00557
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
00578
00579
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;
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;
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;
00615 if (builtinloc >= 0 && bltin < 0)
00616 firstchange = 0;
00617 clearcmdentry(firstchange);
00618 builtinloc = bltin;
00619 }
00620
00621
00622
00623
00624
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
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
00688
00689
00690
00691
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
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
00770
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
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
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 }