summaryrefslogtreecommitdiff
path: root/usr/src/cmd/csh/sh.exec.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd/csh/sh.exec.c')
-rw-r--r--usr/src/cmd/csh/sh.exec.c466
1 files changed, 466 insertions, 0 deletions
diff --git a/usr/src/cmd/csh/sh.exec.c b/usr/src/cmd/csh/sh.exec.c
new file mode 100644
index 0000000000..d0dd6dea7f
--- /dev/null
+++ b/usr/src/cmd/csh/sh.exec.c
@@ -0,0 +1,466 @@
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved. The Berkeley Software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "sh.h"
+#include <dirent.h>
+#include <string.h>
+#include "sh.tconst.h"
+#include "sh_policy.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 */
+
+
+extern DIR *opendir_();
+
+
+doexec(t)
+ register struct command *t;
+{
+ tchar *sav;
+ register tchar *dp, **pv, **av;
+ register struct varent *v;
+ bool slash;
+ int hashval, hashval1, i;
+ tchar *blk[2];
+#ifdef TRACE
+ tprintf("TRACE- doexec()\n");
+#endif
+
+ /*
+ * 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; t->t_dcom[0] = dp;
+ setname(dp);
+ xfree(sav);
+ v = adrof(S_path /*"path"*/);
+ if (v == 0 && dp[0] != '/') {
+ pexerr();
+ }
+ slash = gflag;
+
+ /*
+ * Glob the argument list, if necessary.
+ * Otherwise trim off the quote bits.
+ */
+ gflag = 0; av = &t->t_dcom[1];
+ tglob(av);
+ 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
+ trim(av);
+ slash |= any('/', av[0]);
+
+ xechoit(av); /* Echo command if -x */
+ /*
+ * Since all internal file descriptors are set to close on exec,
+ * we don't need to close them explicitly here. Just reorient
+ * ourselves for error messages.
+ */
+ SHIN = 0; SHOUT = 1; SHDIAG = 2; OLDSTD = 0;
+
+ /*
+ * We must do this AFTER any possible forking (like `foo`
+ * in glob) so that this shell can still do subprocesses.
+ */
+ (void) sigsetmask(0);
+
+ /*
+ * 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(S_SLASH /* "/" */, *av); /* / command name for postpending */
+#ifdef VFORK
+ Vsav = sav;
+#endif
+ if (havhash)
+ hashval = hashname(*av);
+ i = 0;
+#ifdef VFORK
+ hits++;
+#endif
+ do {
+ if (!slash && pv[0][0] == '/' && havhash) {
+ hashval1 = hash(hashval, i);
+ if (!bit(xhash, hashval1))
+ goto cont;
+ }
+
+ if (pv[0][0] == 0 || eq(pv[0], S_DOT/*"."*/)) { /* don't make ./xxx */
+ texec(t, *av, av);
+ } else {
+ dp = strspl(*pv, sav);
+#ifdef VFORK
+ Vdp = dp;
+#endif
+ texec(t, 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( (char *)av);
+ pexerr();
+}
+
+pexerr()
+{
+
+#ifdef TRACE
+ tprintf("TRACE- pexerr()\n");
+#endif
+ /* Couldn't find the damn thing */
+ if (exerr)
+ bferr(exerr);
+ bferr("Command not found");
+}
+
+/*
+ * Execute command f, arg list t.
+ * Record error message if not found.
+ * Also do shell scripts here.
+ */
+texec(cmd, f, t)
+ register struct command *cmd;
+ tchar *f;
+ register tchar **t;
+{
+ register int pfstatus = 0;
+ register struct varent *v;
+ register tchar **vp;
+ tchar *lastsh[2];
+
+#ifdef TRACE
+ tprintf("TRACE- texec()\n");
+#endif
+ /* convert cfname and cargs from tchar to char */
+ tconvert(cmd, f, t);
+
+ if (pfcshflag == 1) {
+ pfstatus = secpolicy_pfexec((const char *)(cmd->cfname),
+ cmd->cargs, (const char **)NULL);
+ if (pfstatus != NOATTRS) {
+ errno = pfstatus;
+ }
+ }
+ if ((pfcshflag == 0) || (pfstatus == NOATTRS)) {
+ execv(cmd->cfname, cmd->cargs);
+ }
+
+ /*
+ * exec returned, free up allocations from above
+ * tconvert(), zero cfname and cargs to prevent
+ * duplicate free() in freesyn()
+ */
+ xfree(cmd->cfname);
+ chr_blkfree(cmd->cargs);
+ cmd->cfname = (char *) 0;
+ cmd->cargs = (char **) 0;
+
+ switch (errno) {
+ case ENOEXEC:
+ /* check that this is not a binary file */
+ {
+ register int ff = open_(f, 0);
+ tchar ch;
+
+ if (ff != -1 && read_(ff, &ch, 1) == 1 && !isprint(ch)
+ && !isspace(ch)) {
+ printf("Cannot execute binary file.\n");
+ Perror(f);
+ (void) close(ff);
+ unsetfd(ff);
+ return;
+ }
+ (void) close(ff);
+ unsetfd(ff);
+ }
+ /*
+ * 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(S_shell /*"shell"*/, &aliases);
+ if (v == 0) {
+#ifdef OTHERSH
+ register int ff = open_(f, 0);
+ tchar ch;
+#endif
+
+ vp = lastsh;
+ vp[0] = adrof(S_shell /*"shell"*/) ? value(S_shell /*"shell"*/) : S_SHELLPATH/*SHELLPATH*/;
+ vp[1] = (tchar *) NULL;
+#ifdef OTHERSH
+ if (ff != -1 && read_(ff, &ch, 1) == 1 && ch != '#')
+ vp[0] = S_OTHERSH/*OTHERSH*/;
+ (void) close(ff);
+ unsetfd(ff);
+#endif
+ } else
+ vp = v->vec;
+ t[0] = f;
+ t = blkspl(vp, t); /* Splice up the new arglst */
+ f = *t;
+
+ tconvert(cmd, f, t); /* convert tchar to char */
+
+ /*
+ * now done with tchar arg list t,
+ * free the space calloc'd by above blkspl()
+ */
+ xfree((char *) t);
+
+ execv(cmd->cfname, cmd->cargs); /* exec the command */
+
+ /* exec returned, same free'ing as above */
+ xfree(cmd->cfname);
+ chr_blkfree(cmd->cargs);
+ cmd->cfname = (char *) 0;
+ cmd->cargs = (char **) 0;
+
+ /* The sky is falling, the sky is falling! */
+
+ case ENOMEM:
+ Perror(f);
+
+ case ENOENT:
+ break;
+
+ default:
+ if (exerr == 0) {
+ exerr = strerror(errno);
+ setname(f);
+ }
+ }
+}
+
+
+static
+tconvert(cmd, fname, list)
+register struct command *cmd;
+register tchar *fname, **list;
+{
+ register char **rc;
+ register int len;
+
+ cmd->cfname = tstostr(NULL, fname);
+
+ len = blklen(list);
+ rc = cmd->cargs = (char **)
+ calloc((u_int) (len + 1), sizeof(char **));
+ while (len--)
+ *rc++ = tstostr(NULL, *list++);
+ *rc = NULL;
+}
+
+
+/*ARGSUSED*/
+execash(t, kp)
+ tchar **t;
+ register struct command *kp;
+{
+#ifdef TRACE
+ tprintf("TRACE- execash()\n");
+#endif
+
+ rechist();
+ (void) signal(SIGINT, parintr);
+ (void) signal(SIGQUIT, parintr);
+ (void) signal(SIGTERM, parterm); /* if doexec loses, screw */
+ lshift(kp->t_dcom, 1);
+ exiterr++;
+ doexec(kp);
+ /*NOTREACHED*/
+}
+
+xechoit(t)
+ tchar **t;
+{
+#ifdef TRACE
+ tprintf("TRACE- xechoit()\n");
+#endif
+
+ if (adrof(S_echo /*"echo"*/)) {
+ flush();
+ haderr = 1;
+ blkpr(t), Putchar('\n');
+ haderr = 0;
+ }
+}
+
+/*
+ * This routine called when user enters "rehash".
+ * Both the path and cdpath caching arrays will
+ * be rehashed, via calling dohash. If either
+ * variable is not set with a value, then dohash
+ * just exits.
+ */
+
+dorehash()
+{
+ dohash(xhash);
+ dohash(xhash2);
+}
+
+/*
+ * Fill up caching arrays for path and cdpath
+ */
+dohash(cachearray)
+char cachearray[];
+{
+ struct stat stb;
+ DIR *dirp;
+ register struct dirent *dp;
+ register int cnt;
+ int i = 0;
+ struct varent *v;
+ tchar **pv;
+ int hashval;
+ tchar curdir_[MAXNAMLEN+1];
+
+#ifdef TRACE
+ tprintf("TRACE- dohash()\n");
+#endif
+ /* Caching $path */
+ if ( cachearray == xhash ) {
+ havhash = 1;
+ v = adrof(S_path /*"path"*/);
+ }else { /* Caching $cdpath */
+ havhash2 = 1;
+ v = adrof(S_cdpath /*"cdpath"*/);
+ }
+
+ for (cnt = 0; cnt < ( HSHSIZ / 8 ); cnt++)
+ cachearray[cnt] = 0;
+ if (v == 0)
+ {
+ return;
+ }
+ for (pv = v->vec; *pv; pv++, i++) {
+ if (pv[0][0] != '/')
+ continue;
+ dirp = opendir_(*pv);
+ if (dirp == NULL)
+ continue;
+ if (fstat(dirp->dd_fd, &stb) < 0 || !isdir(stb)) {
+ unsetfd(dirp->dd_fd);
+ closedir_(dirp);
+ continue;
+ }
+ while ((dp = readdir(dirp)) != NULL) {
+ if (dp->d_ino == 0)
+ continue;
+ if (dp->d_name[0] == '.' &&
+ (dp->d_name[1] == '\0' ||
+ dp->d_name[1] == '.' && dp->d_name[2] == '\0'))
+ continue;
+ hashval = hash(hashname(strtots(curdir_,dp->d_name)), i);
+ bis(cachearray, hashval);
+ }
+ unsetfd(dirp->dd_fd);
+ closedir_(dirp);
+ }
+}
+
+dounhash()
+{
+
+#ifdef TRACE
+ tprintf("TRACE- dounhash()\n");
+#endif
+ havhash = 0;
+ havhash2 = 0;
+}
+
+#ifdef VFORK
+hashstat()
+{
+#ifdef TRACE
+ tprintf("TRACE- hashstat_()\n");
+#endif
+
+ if (hits+misses)
+ printf("%d hits, %d misses, %d%%\n",
+ hits, misses, 100 * hits / (hits + misses));
+}
+#endif
+
+/*
+ * Hash a command name.
+ */
+hashname(cp)
+ register tchar *cp;
+{
+ register long h = 0;
+
+#ifdef TRACE
+ tprintf("TRACE- hashname()\n");
+#endif
+ while (*cp)
+ h = hash(h, *cp++);
+ return ((int) h);
+}