date and time created 80/10/09 12:40:50 by bill
authorBill Joy <bill@ucbvax.Berkeley.EDU>
Fri, 10 Oct 1980 04:40:50 +0000 (20:40 -0800)
committerBill Joy <bill@ucbvax.Berkeley.EDU>
Fri, 10 Oct 1980 04:40:50 +0000 (20:40 -0800)
SCCS-vsn: bin/csh/exec.c 4.1

usr/src/bin/csh/exec.c [new file with mode: 0644]

diff --git a/usr/src/bin/csh/exec.c b/usr/src/bin/csh/exec.c
new file mode 100644 (file)
index 0000000..ba3f3aa
--- /dev/null
@@ -0,0 +1,316 @@
+static char *sccsid = "@(#)exec.c 4.1 %G%";
+
+#include "sh.h"
+
+/*
+ * C shell
+ */
+
+/*
+ * System level search and execute of a command.
+ * We look in each directory for the specified command name.
+ * If the name contains a '/' then we execute only the full path name.
+ * If there is no search path then we execute only full path names.
+ */
+
+/* 
+ * As we search for the command we note the first non-trivial error
+ * message for presentation to the user.  This allows us often
+ * to show that a file has the wrong mode/no access when the file
+ * is not in the last component of the search path, so we must
+ * go on after first detecting the error.
+ */
+char   *exerr;                 /* Execution error message */
+char   *expath;                /* Path for exerr */
+
+/*
+ * Xhash is an array of HSHSIZ chars, which are used to hash execs.
+ * If it is allocated, then to tell whether ``name'' is (possibly)
+ * present in the i'th component of the variable path, you look at
+ * the i'th bit of xhash[hash("name")].  This is setup automatically
+ * after .login is executed, and recomputed whenever ``path'' is
+ * changed.
+ */
+int    havhash;
+#define        HSHSIZ  511
+char   xhash[HSHSIZ];
+#ifdef VFORK
+int    hits, misses;
+#endif
+
+/* Dummy search path for just absolute search when no path */
+char   *justabs[] =    { "", 0 };
+
+doexec(t)
+       register struct command *t;
+{
+       char *sav;
+       register char *dp, **pv, **av;
+       register struct varent *v;
+       bool slash = any('/', t->t_dcom[0]);
+       int hashval, i;
+       char *blk[2];
+
+       /*
+        * Glob the command name.  If this does anything, then we
+        * will execute the command only relative to ".".  One special
+        * case: if there is no PATH, then we execute only commands
+        * which start with '/'.
+        */
+       dp = globone(t->t_dcom[0]);
+       sav = t->t_dcom[0];
+       exerr = 0; expath = t->t_dcom[0] = dp;
+       xfree(sav);
+       v = adrof("path");
+       if (v == 0 && expath[0] != '/')
+               pexerr();
+       slash |= gflag;
+
+       /*
+        * Glob the argument list, if necessary.
+        * Otherwise trim off the quote bits.
+        */
+       gflag = 0; av = &t->t_dcom[1];
+       rscan(av, tglob);
+       if (gflag) {
+               av = glob(av);
+               if (av == 0)
+                       error("No match");
+       }
+       blk[0] = t->t_dcom[0];
+       blk[1] = 0;
+       av = blkspl(blk, av);
+#ifdef VFORK
+       Vav = av;
+#endif
+       scan(av, trim);
+
+       xechoit(av);            /* Echo command if -x */
+       closech();              /* Close random fd's */
+
+       /*
+        * We must do this after any possible forking (like `foo`
+        * in glob) so that this shell can still do subprocesses.
+        */
+       sigsys(SIGCHLD, SIG_IGN);       /* sigsys for vforks sake */
+
+       /*
+        * If no path, no words in path, or a / in the filename
+        * then restrict the command search.
+        */
+       if (v == 0 || v->vec[0] == 0 || slash)
+               pv = justabs;
+       else
+               pv = v->vec;
+       sav = strspl("/", *av);         /* / command name for postpending */
+#ifdef VFORK
+       Vsav = sav;
+#endif
+       if (havhash)
+               hashval = xhash[hash(*av)];
+       i = 0;
+#ifdef VFORK
+       hits++;
+#endif
+       do {
+               if (!slash && pv[0][0] == '/' && havhash && (hashval & (1 << (i % 8))) == 0)
+                       goto cont;
+               if (pv[0][0] == 0 || eq(pv[0], "."))    /* don't make ./xxx */
+                       texec(*av, av);
+               else {
+                       dp = strspl(*pv, sav);
+#ifdef VFORK
+                       Vdp = dp;
+#endif
+                       texec(dp, av);
+#ifdef VFORK
+                       Vdp = 0;
+#endif
+                       xfree(dp);
+               }
+#ifdef VFORK
+               misses++;
+#endif
+cont:
+               pv++;
+               i++;
+       } while (*pv);
+#ifdef VFORK
+       hits--;
+#endif
+#ifdef VFORK
+       Vsav = 0;
+       Vav = 0;
+#endif
+       xfree(sav);
+       xfree(av);
+       pexerr();
+}
+
+pexerr()
+{
+
+       /* Couldn't find the damn thing */
+       setname(expath);
+       /* xfree(expath); */
+       if (exerr)
+               bferr(exerr);
+       bferr("Command not found");
+}
+
+/* Last resort shell */
+char   *lastsh[] =     { SHELLPATH, 0 };
+
+/*
+ * Execute command f, arg list t.
+ * Record error message if not found.
+ * Also do shell scripts here.
+ */
+texec(f, t)
+       char *f;
+       register char **t;
+{
+       register struct varent *v;
+       register char **vp;
+       extern char *sys_errlist[];
+
+       execv(f, t);
+       switch (errno) {
+
+       case ENOEXEC:
+               /*
+                * If there is an alias for shell, then
+                * put the words of the alias in front of the
+                * argument list replacing the command name.
+                * Note no interpretation of the words at this point.
+                */
+               v = adrof1("shell", &aliases);
+               if (v == 0) {
+#ifdef OTHERSH
+                       register int ff = open(f, 0);
+                       char ch;
+#endif
+
+                       vp = lastsh;
+                       vp[0] = adrof("shell") ? value("shell") : SHELLPATH;
+#ifdef OTHERSH
+                       if (ff != -1 && read(ff, &ch, 1) == 1 && ch != '#')
+                               vp[0] = OTHERSH;
+                       close(ff);
+#endif
+               } else
+                       vp = v->vec;
+               t[0] = f;
+               t = blkspl(vp, t);              /* Splice up the new arglst */
+               f = *t;
+               execv(f, t);
+               xfree((char *)t);
+               /* The sky is falling, the sky is falling! */
+
+       case ENOMEM:
+               Perror(f);
+
+       case ENOENT:
+               break;
+
+       default:
+               if (exerr == 0) {
+                       exerr = sys_errlist[errno];
+                       expath = savestr(f);
+               }
+       }
+}
+
+execash(t, kp)
+       register struct command *kp;
+{
+
+       didcch++;
+       signal(SIGINT, parintr);
+       signal(SIGQUIT, parintr);
+       signal(SIGTERM, parterm);               /* if doexec loses, screw */
+       lshift(kp->t_dcom, 1);
+       exiterr++;
+       doexec(kp);
+       /*NOTREACHED*/
+}
+
+xechoit(t)
+       char **t;
+{
+
+       if (adrof("echo")) {
+               flush();
+               haderr = 1;
+               blkpr(t), printf("\n");
+               haderr = 0;
+       }
+}
+
+dohash()
+{
+       struct stat stb;
+       struct direct dirbuf[BUFSIZ / sizeof (struct direct)];
+       char d_name[DIRSIZ + 1];
+       register int dirf, cnt;
+       int i = 0;
+       struct varent *v = adrof("path");
+       char **pv;
+
+       havhash = 1;
+       for (cnt = 0; cnt < HSHSIZ; cnt++)
+               xhash[cnt] = 0;
+       if (v == 0)
+               return;
+       for (pv = v->vec; *pv; pv++, i = (i + 1) % 8) {
+               if (pv[0][0] != '/')
+                       continue;
+               dirf = open(*pv, 0);
+               if (dirf < 0)
+                       continue;
+               if (fstat(dirf, &stb) < 0 || !isdir(stb)) {
+                       close(dirf);
+                       continue;
+               }
+               while ((cnt = read(dirf, (char *) dirbuf, sizeof dirbuf)) >= sizeof dirbuf[0]) {
+                       register struct direct *ep = dirbuf;
+
+                       for (cnt /= sizeof(struct direct); cnt > 0; cnt--, ep++) {
+                               if (ep->d_ino == 0)
+                                       continue;
+                               copdent(d_name, ep->d_name);
+                               xhash[hash(d_name)] |= (1 << i);
+                       }
+               }
+               close(dirf);
+       }
+}
+
+dounhash()
+{
+
+       havhash = 0;
+}
+
+#ifdef VFORK
+hashstat()
+{
+
+       if (hits+misses)
+       printf("%d hits, %d misses, %2d%%\n", hits, misses, 100 * hits / (hits + misses));
+}
+#endif
+
+hash(cp)
+       register char *cp;
+{
+       register long hash = 0;
+       int retval;
+
+       while (*cp)
+               hash += hash + *cp++;
+       if (hash < 0)
+               hash = -hash;
+       retval = hash % HSHSIZ;
+       return (retval);
+}