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 #ifndef lint
00034 #if 0
00035 static char sccsid[] = "@(#)exec.c 8.4 (Berkeley) 6/8/95";
00036 #endif
00037 #endif
00038
00039
00040
00041
00042
00043 #include <sys/types.h>
00044 #include <sys/stat.h>
00045 #include <unistd.h>
00046 #include <fcntl.h>
00047 #include <errno.h>
00048 #include <stdlib.h>
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059 #include "shell.h"
00060 #include "main.h"
00061 #include "nodes.h"
00062 #include "parser.h"
00063 #include "redir.h"
00064 #include "eval.h"
00065 #include "exec.h"
00066 #include "builtins.h"
00067 #include "var.h"
00068 #include "options.h"
00069 #include "input.h"
00070 #include "output.h"
00071 #include "syntax.h"
00072 #include "memalloc.h"
00073 #include "error.h"
00074 #include "init.h"
00075 #include "mystring.h"
00076 #include "show.h"
00077 #include "jobs.h"
00078 #include "alias.h"
00079
00080
00081 #define CMDTABLESIZE 31
00082 #define ARB 1
00083
00084
00085
00086 struct tblentry {
00087 struct tblentry *next;
00088 union param param;
00089 short cmdtype;
00090 char rehash;
00091 char cmdname[ARB];
00092 };
00093
00094
00095 STATIC struct tblentry *cmdtable[CMDTABLESIZE];
00096 STATIC int builtinloc = -1;
00097 int exerrno = 0;
00098
00099
00100 STATIC void tryexec(char *, char **, char **);
00101 STATIC void printentry(struct tblentry *, int);
00102 STATIC struct tblentry *cmdlookup(char *, int);
00103 STATIC void delete_cmd_entry(void);
00104 STATIC void addcmdentry(char *, struct cmdentry *);
00105
00106
00107
00108
00109
00110
00111
00112
00113 void
00114 shellexec(char **argv, char **envp, char *path, int index)
00115 {
00116 char *cmdname;
00117 int e;
00118
00119 if (strchr(argv[0], '/') != NULL) {
00120 tryexec(argv[0], argv, envp);
00121 e = errno;
00122 } else {
00123 e = ENOENT;
00124 while ((cmdname = padvance(&path, argv[0])) != NULL) {
00125 if (--index < 0 && pathopt == NULL) {
00126 tryexec(cmdname, argv, envp);
00127 if (errno != ENOENT && errno != ENOTDIR)
00128 e = errno;
00129 }
00130 stunalloc(cmdname);
00131 }
00132 }
00133
00134
00135 switch (e) {
00136 case EACCES:
00137 exerrno = 126;
00138 break;
00139 case ENOENT:
00140 exerrno = 127;
00141 break;
00142 default:
00143 exerrno = 2;
00144 break;
00145 }
00146 if (e == ENOENT || e == ENOTDIR)
00147 exerror(EXEXEC, "%s: not found", argv[0]);
00148 exerror(EXEXEC, "%s: %s", argv[0], strerror(e));
00149 }
00150
00151
00152 STATIC void
00153 tryexec(char *cmd, char **argv, char **envp)
00154 {
00155 int e;
00156
00157 execve(cmd, argv, envp);
00158 #if !__minix_vmd
00159 e = errno;
00160 if (e == ENOEXEC) {
00161 initshellproc();
00162 setinputfile(cmd, 0);
00163 commandname = arg0 = savestr(argv[0]);
00164 setparam(argv + 1);
00165 exraise(EXSHELLPROC);
00166
00167 }
00168 errno = e;
00169 #endif
00170 }
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182 char *pathopt;
00183
00184 char *
00185 padvance(char **path, char *name)
00186 {
00187 char *p, *q;
00188 char *start;
00189 int len;
00190
00191 if (*path == NULL)
00192 return NULL;
00193 start = *path;
00194 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
00195 len = p - start + strlen(name) + 2;
00196 while (stackblocksize() < len)
00197 growstackblock();
00198 q = stackblock();
00199 if (p != start) {
00200 memcpy(q, start, p - start);
00201 q += p - start;
00202 *q++ = '/';
00203 }
00204 strcpy(q, name);
00205 pathopt = NULL;
00206 if (*p == '%') {
00207 pathopt = ++p;
00208 while (*p && *p != ':') p++;
00209 }
00210 if (*p == ':')
00211 *path = p + 1;
00212 else
00213 *path = NULL;
00214 return stalloc(len);
00215 }
00216
00217
00218
00219
00220
00221
00222 int
00223 hashcmd(int argc __unused, char **argv __unused)
00224 {
00225 struct tblentry **pp;
00226 struct tblentry *cmdp;
00227 int c;
00228 int verbose;
00229 struct cmdentry entry;
00230 char *name;
00231
00232 verbose = 0;
00233 while ((c = nextopt("rv")) != '\0') {
00234 if (c == 'r') {
00235 clearcmdentry(0);
00236 } else if (c == 'v') {
00237 verbose++;
00238 }
00239 }
00240 if (*argptr == NULL) {
00241 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
00242 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
00243 if (cmdp->cmdtype == CMDNORMAL)
00244 printentry(cmdp, verbose);
00245 }
00246 }
00247 return 0;
00248 }
00249 while ((name = *argptr) != NULL) {
00250 if ((cmdp = cmdlookup(name, 0)) != NULL
00251 && (cmdp->cmdtype == CMDNORMAL
00252 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
00253 delete_cmd_entry();
00254 find_command(name, &entry, 1, pathval());
00255 if (verbose) {
00256 if (entry.cmdtype != CMDUNKNOWN) {
00257 cmdp = cmdlookup(name, 0);
00258 if (cmdp != NULL)
00259 printentry(cmdp, verbose);
00260 else
00261 outfmt(&errout, "%s: not found\n", name);
00262 }
00263 flushall();
00264 }
00265 argptr++;
00266 }
00267 return 0;
00268 }
00269
00270
00271 STATIC void
00272 printentry(struct tblentry *cmdp, int verbose)
00273 {
00274 int index;
00275 char *path;
00276 char *name;
00277
00278 if (cmdp->cmdtype == CMDNORMAL) {
00279 index = cmdp->param.index;
00280 path = pathval();
00281 do {
00282 name = padvance(&path, cmdp->cmdname);
00283 stunalloc(name);
00284 } while (--index >= 0);
00285 out1str(name);
00286 } else if (cmdp->cmdtype == CMDBUILTIN) {
00287 out1fmt("builtin %s", cmdp->cmdname);
00288 } else if (cmdp->cmdtype == CMDFUNCTION) {
00289 out1fmt("function %s", cmdp->cmdname);
00290 if (verbose) {
00291 INTOFF;
00292 name = commandtext(cmdp->param.func);
00293 out1c(' ');
00294 out1str(name);
00295 ckfree(name);
00296 INTON;
00297 }
00298 #if DEBUG
00299 } else {
00300 error("internal error: cmdtype %d", cmdp->cmdtype);
00301 #endif
00302 }
00303 if (cmdp->rehash)
00304 out1c('*');
00305 out1c('\n');
00306 }
00307
00308
00309
00310
00311
00312
00313
00314
00315 void
00316 find_command(char *name, struct cmdentry *entry, int printerr, char *path)
00317 {
00318 struct tblentry *cmdp;
00319 int index;
00320 int prev;
00321 char *fullname;
00322 struct stat statb;
00323 int e;
00324 int i;
00325
00326
00327 if (strchr(name, '/') != NULL) {
00328 entry->cmdtype = CMDNORMAL;
00329 entry->u.index = 0;
00330 return;
00331 }
00332
00333
00334 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0)
00335 goto success;
00336
00337
00338 if (builtinloc < 0 && (i = find_builtin(name)) >= 0) {
00339 INTOFF;
00340 cmdp = cmdlookup(name, 1);
00341 cmdp->cmdtype = CMDBUILTIN;
00342 cmdp->param.index = i;
00343 INTON;
00344 goto success;
00345 }
00346
00347
00348 prev = -1;
00349 if (cmdp) {
00350 if (cmdp->cmdtype == CMDBUILTIN)
00351 prev = builtinloc;
00352 else
00353 prev = cmdp->param.index;
00354 }
00355
00356 e = ENOENT;
00357 index = -1;
00358 loop:
00359 while ((fullname = padvance(&path, name)) != NULL) {
00360 stunalloc(fullname);
00361 index++;
00362 if (pathopt) {
00363 if (prefix("builtin", pathopt)) {
00364 if ((i = find_builtin(name)) < 0)
00365 goto loop;
00366 INTOFF;
00367 cmdp = cmdlookup(name, 1);
00368 cmdp->cmdtype = CMDBUILTIN;
00369 cmdp->param.index = i;
00370 INTON;
00371 goto success;
00372 } else if (prefix("func", pathopt)) {
00373
00374 } else {
00375 goto loop;
00376 }
00377 }
00378
00379 if (fullname[0] == '/' && index <= prev) {
00380 if (index < prev)
00381 goto loop;
00382 TRACE(("searchexec \"%s\": no change\n", name));
00383 goto success;
00384 }
00385 if (stat(fullname, &statb) < 0) {
00386 if (errno != ENOENT && errno != ENOTDIR)
00387 e = errno;
00388 goto loop;
00389 }
00390 e = EACCES;
00391 if (!S_ISREG(statb.st_mode))
00392 goto loop;
00393 if (pathopt) {
00394 stalloc(strlen(fullname) + 1);
00395 readcmdfile(fullname);
00396 if ((cmdp = cmdlookup(name, 0)) == NULL || cmdp->cmdtype != CMDFUNCTION)
00397 error("%s not defined in %s", name, fullname);
00398 stunalloc(fullname);
00399 goto success;
00400 }
00401 #ifdef notdef
00402 if (statb.st_uid == geteuid()) {
00403 if ((statb.st_mode & 0100) == 0)
00404 goto loop;
00405 } else if (statb.st_gid == getegid()) {
00406 if ((statb.st_mode & 010) == 0)
00407 goto loop;
00408 } else {
00409 if ((statb.st_mode & 01) == 0)
00410 goto loop;
00411 }
00412 #endif
00413 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
00414 INTOFF;
00415 cmdp = cmdlookup(name, 1);
00416 cmdp->cmdtype = CMDNORMAL;
00417 cmdp->param.index = index;
00418 INTON;
00419 goto success;
00420 }
00421
00422
00423 if (cmdp)
00424 delete_cmd_entry();
00425 if (printerr) {
00426 if (e == ENOENT || e == ENOTDIR)
00427 outfmt(out2, "%s: not found\n", name);
00428 else
00429 outfmt(out2, "%s: %s\n", name, strerror(e));
00430 }
00431 entry->cmdtype = CMDUNKNOWN;
00432 return;
00433
00434 success:
00435 cmdp->rehash = 0;
00436 entry->cmdtype = cmdp->cmdtype;
00437 entry->u = cmdp->param;
00438 }
00439
00440
00441
00442
00443
00444
00445
00446 int
00447 find_builtin(char *name)
00448 {
00449 const struct builtincmd *bp;
00450
00451 for (bp = builtincmd ; bp->name ; bp++) {
00452 if (*bp->name == *name && equal(bp->name, name))
00453 return bp->code;
00454 }
00455 return -1;
00456 }
00457
00458
00459
00460
00461
00462
00463
00464
00465 void
00466 hashcd(void)
00467 {
00468 struct tblentry **pp;
00469 struct tblentry *cmdp;
00470
00471 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
00472 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
00473 if (cmdp->cmdtype == CMDNORMAL
00474 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
00475 cmdp->rehash = 1;
00476 }
00477 }
00478 }
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488 void
00489 changepath(const char *newval)
00490 {
00491 const char *old, *new;
00492 int index;
00493 int firstchange;
00494 int bltin;
00495
00496 old = pathval();
00497 new = newval;
00498 firstchange = 9999;
00499 index = 0;
00500 bltin = -1;
00501 for (;;) {
00502 if (*old != *new) {
00503 firstchange = index;
00504 if ((*old == '\0' && *new == ':')
00505 || (*old == ':' && *new == '\0'))
00506 firstchange++;
00507 old = new;
00508 }
00509 if (*new == '\0')
00510 break;
00511 if (*new == '%' && bltin < 0 && prefix("builtin", new + 1))
00512 bltin = index;
00513 if (*new == ':') {
00514 index++;
00515 }
00516 new++, old++;
00517 }
00518 if (builtinloc < 0 && bltin >= 0)
00519 builtinloc = bltin;
00520 if (builtinloc >= 0 && bltin < 0)
00521 firstchange = 0;
00522 clearcmdentry(firstchange);
00523 builtinloc = bltin;
00524 }
00525
00526
00527
00528
00529
00530
00531
00532 void
00533 clearcmdentry(int firstchange)
00534 {
00535 struct tblentry **tblp;
00536 struct tblentry **pp;
00537 struct tblentry *cmdp;
00538
00539 INTOFF;
00540 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
00541 pp = tblp;
00542 while ((cmdp = *pp) != NULL) {
00543 if ((cmdp->cmdtype == CMDNORMAL &&
00544 cmdp->param.index >= firstchange)
00545 || (cmdp->cmdtype == CMDBUILTIN &&
00546 builtinloc >= firstchange)) {
00547 *pp = cmdp->next;
00548 ckfree(cmdp);
00549 } else {
00550 pp = &cmdp->next;
00551 }
00552 }
00553 }
00554 INTON;
00555 }
00556
00557
00558
00559
00560
00561
00562 #ifdef mkinit
00563 INCLUDE "exec.h"
00564 SHELLPROC {
00565 deletefuncs();
00566 }
00567 #endif
00568
00569 void
00570 deletefuncs(void)
00571 {
00572 struct tblentry **tblp;
00573 struct tblentry **pp;
00574 struct tblentry *cmdp;
00575
00576 INTOFF;
00577 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
00578 pp = tblp;
00579 while ((cmdp = *pp) != NULL) {
00580 if (cmdp->cmdtype == CMDFUNCTION) {
00581 *pp = cmdp->next;
00582 freefunc(cmdp->param.func);
00583 ckfree(cmdp);
00584 } else {
00585 pp = &cmdp->next;
00586 }
00587 }
00588 }
00589 INTON;
00590 }
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602 STATIC struct tblentry **lastcmdentry;
00603
00604
00605 STATIC struct tblentry *
00606 cmdlookup(char *name, int add)
00607 {
00608 int hashval;
00609 char *p;
00610 struct tblentry *cmdp;
00611 struct tblentry **pp;
00612
00613 p = name;
00614 hashval = *p << 4;
00615 while (*p)
00616 hashval += *p++;
00617 hashval &= 0x7FFF;
00618 pp = &cmdtable[hashval % CMDTABLESIZE];
00619 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
00620 if (equal(cmdp->cmdname, name))
00621 break;
00622 pp = &cmdp->next;
00623 }
00624 if (add && cmdp == NULL) {
00625 INTOFF;
00626 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
00627 + strlen(name) + 1);
00628 cmdp->next = NULL;
00629 cmdp->cmdtype = CMDUNKNOWN;
00630 cmdp->rehash = 0;
00631 strcpy(cmdp->cmdname, name);
00632 INTON;
00633 }
00634 lastcmdentry = pp;
00635 return cmdp;
00636 }
00637
00638
00639
00640
00641
00642 STATIC void
00643 delete_cmd_entry(void)
00644 {
00645 struct tblentry *cmdp;
00646
00647 INTOFF;
00648 cmdp = *lastcmdentry;
00649 *lastcmdentry = cmdp->next;
00650 ckfree(cmdp);
00651 INTON;
00652 }
00653
00654
00655
00656
00657
00658
00659
00660
00661 static void
00662 addcmdentry(char *name, struct cmdentry *entry)
00663 {
00664 struct tblentry *cmdp;
00665
00666 INTOFF;
00667 cmdp = cmdlookup(name, 1);
00668 if (cmdp->cmdtype == CMDFUNCTION) {
00669 freefunc(cmdp->param.func);
00670 }
00671 cmdp->cmdtype = entry->cmdtype;
00672 cmdp->param = entry->u;
00673 INTON;
00674 }
00675
00676
00677
00678
00679
00680
00681 void
00682 defun(char *name, union node *func)
00683 {
00684 struct cmdentry entry;
00685
00686 INTOFF;
00687 entry.cmdtype = CMDFUNCTION;
00688 entry.u.func = copyfunc(func);
00689 addcmdentry(name, &entry);
00690 INTON;
00691 }
00692
00693
00694
00695
00696
00697
00698 int
00699 unsetfunc(char *name)
00700 {
00701 struct tblentry *cmdp;
00702
00703 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) {
00704 freefunc(cmdp->param.func);
00705 delete_cmd_entry();
00706 return (0);
00707 }
00708 return (0);
00709 }
00710
00711
00712
00713
00714
00715 int
00716 typecmd(int argc, char **argv)
00717 {
00718 struct cmdentry entry;
00719 struct tblentry *cmdp;
00720 char **pp;
00721 struct alias *ap;
00722 int i;
00723 int error = 0;
00724 extern char *const parsekwd[];
00725
00726 for (i = 1; i < argc; i++) {
00727 out1str(argv[i]);
00728
00729 for (pp = (char **)parsekwd; *pp; pp++)
00730 if (**pp == *argv[i] && equal(*pp, argv[i]))
00731 break;
00732
00733 if (*pp) {
00734 out1str(" is a shell keyword\n");
00735 continue;
00736 }
00737
00738
00739 if ((ap = lookupalias(argv[i], 1)) != NULL) {
00740 out1fmt(" is an alias for %s\n", ap->val);
00741 continue;
00742 }
00743
00744
00745 if ((cmdp = cmdlookup(argv[i], 0)) != NULL) {
00746 entry.cmdtype = cmdp->cmdtype;
00747 entry.u = cmdp->param;
00748 }
00749 else {
00750
00751 find_command(argv[i], &entry, 0, pathval());
00752 }
00753
00754 switch (entry.cmdtype) {
00755 case CMDNORMAL: {
00756 if (strchr(argv[i], '/') == NULL) {
00757 char *path = pathval(), *name;
00758 int j = entry.u.index;
00759 do {
00760 name = padvance(&path, argv[i]);
00761 stunalloc(name);
00762 } while (--j >= 0);
00763 out1fmt(" is%s %s\n",
00764 cmdp ? " a tracked alias for" : "", name);
00765 } else {
00766 if (access(argv[i], X_OK) == 0)
00767 out1fmt(" is %s\n", argv[i]);
00768 else
00769 out1fmt(": %s\n", strerror(errno));
00770 }
00771 break;
00772 }
00773 case CMDFUNCTION:
00774 out1str(" is a shell function\n");
00775 break;
00776
00777 case CMDBUILTIN:
00778 out1str(" is a shell builtin\n");
00779 break;
00780
00781 default:
00782 out1str(": not found\n");
00783 error |= 127;
00784 break;
00785 }
00786 }
00787 return error;
00788 }
00789
00790
00791
00792