Files
Arquivotheca.AIX-4.1.3/bos/usr/bin/csh/exec.c
seta75D d6fe8fe829 Init
2021-10-11 22:19:34 -03:00

367 lines
8.0 KiB
C

static char sccsid[] = "@(#)21 1.14 src/bos/usr/bin/csh/exec.c, cmdcsh, bos411, 9428A410j 11/12/92 13:32:35";
/*
* COMPONENT_NAME: CMDCSH c shell(csh)
*
* FUNCTIONS: doexec pexerr texec execash xechoit dohash dounhash hashstat
* hashname
*
* ORIGINS: 10,26,27,18,71
*
* This module contains IBM CONFIDENTIAL code. -- (IBM
* Confidential Restricted when combined with the aggregated
* modules for this product)
* SOURCE MATERIALS
* (C) COPYRIGHT International Business Machines Corp. 1985,1992
* All Rights Reserved
*
* US Government Users Restricted Rights - Use, duplication or
* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
*
* (c) Copyright 1990, 1991, 1992 OPEN SOFTWARE FOUNDATION, INC.
* ALL RIGHTS RESERVED
*
* OSF/1 1.1
*/
#include "sh.h"
#include <dirent.h>
#include <string.h>
#include <fcntl.h>
#include "pathnames.h"
/*
* 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.
*/
uchar_t *exerr; /* Execution error message */
uchar_t *expath; /* Path for exerr */
/*
* Xhash is an array of HSHSIZ uchar_ts, 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.
* The two part hash function is designed to let texec() call the
* more expensive hashname() only once and the simple hash() several
* times (once for each path component checked).
* Byte size is assumed to be 8.
*/
#define HSHSIZ 8192 /* 1k bytes */
#define HSHMASK (HSHSIZ - 1)
#define HSHMUL 243
char xhash[HSHSIZ / 8];
#define hash(a, b) ((a) * HSHMUL + (b) & HSHMASK)
#define bit(h, b) ((h)[(b) >> 3] & 1 << ((b) & 7)) /* bit test */
#define bis(h, b) ((h)[(b) >> 3] |= 1 << ((b) & 7)) /* bit set */
int havhash;
static int hits, misses;
/* Dummy search path for just absolute search when no path */
static uchar_t *justabs[] = { (uchar_t *)"", 0 };
static void pexerr(void);
static void texec(uchar_t *,uchar_t **);
static int hashname(uchar_t *);
void
doexec(struct command *t)
{
uchar_t *sav;
register uchar_t *dp, **pv, **av;
register struct varent *v;
bool slash = (any('/', t->t_dcom[0]) != NULL);
int hashval, hashval1, i;
uchar_t *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 '/'.
*/
sav = t->t_dcom[0];
dp = globone(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(MSGSTR(M_NOMATCH, "No match"));
}
scan(av, trim);
blk[0] = t->t_dcom[0];
blk[1] = 0;
av = blkspl(blk, av);
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.
*/
(void) sigsetmask(0L);
/*
* 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
{
#ifdef DEBUG
uchar_t **P;
#endif
pv = v->vec;
#ifdef DEBUG
for (P=pv; P&&*P&&**P;P++)
printf("doexec: pv=%s\n", *P);
#endif
}
/* command name for postpending */
sav = (uchar_t *)strspl((uchar_t *)"/", *av);
if (havhash) {
hashval = hashname(*av);
#ifdef DEBUG
printf("doexec: *av=%s, hashname(*av)=%d, xhash[hashname(*av)]=%d\n",
*av, hashname(*av), xhash[hashname(*av)]);
#endif
}
hits++;
i = 0;
do {
#ifdef DEBUG
printf("doexec: slash=%d, havhash=%d, *pv=%s, hashval=%d, i=%d\n",
slash, havhash, *pv, hashval, i);
#endif
if (!slash && pv[0][0] == '/' && havhash) {
hashval1 = hash(hashval, i);
if (!bit(xhash, hashval1))
goto cont;
}
if (pv[0][0] == 0 || EQ((char *)pv[0], ".")) /* don't make ./xxx */
{
#ifdef DEBUG
printf("doexec: *av=%s\n", *av);
#endif
texec(*av, av);
}
else {
dp = (uchar_t *)strspl(*pv, sav);
texec(dp, av);
xfree(dp);
}
cont:
pv++;
i++;
misses++;
} while (*pv);
hits--;
xfree(sav);
xfree((uchar_t *)av);
pexerr();
}
static void
pexerr(void)
{
/* Couldn't find it */
setname(expath);
/* xfree(expath); */
if (exerr)
bferr((char *)exerr);
bferr(MSGSTR(M_NOTFOUND, "Command not found"));
}
/*
* Execute command f, arg list t.
* Record error message if not found.
* Also do shell scripts here.
*/
static void
texec(uchar_t *f,uchar_t **t)
{
register struct varent *v;
register uchar_t **vp;
uchar_t *lastsh[2];
#ifdef DEBUG
printf("texec: %s\n", f);
#endif
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) {
register int ff = open((char *)f, O_RDONLY);
char ch;
vp = lastsh;
vp[0] = adrof("shell") ?
value("shell") : (uchar_t *)_PATH_CSHELL;
vp[1] = (uchar_t *)NULL;
if (ff != -1 && read(ff, &ch, 1) == 1 && ch != '#')
vp[0] = (uchar_t *)_PATH_BSHELL;
(void)close(ff);
} else
vp = v->vec;
t[0] = f;
t = blkspl(vp, t); /* Splice up the new arglst */
f = *t;
execv(f, t);
xfree((uchar_t *)t);
/* The sky is falling, the sky is falling! */
/* FALL THROUGH */
case ENOMEM:
Perror((char *)f);
break;
case E2BIG: /* arg list too big, it'll never work */
Perror((char *)t[0]); /* use basename of command */
break;
case ENOENT:
break;
default:
if (exerr == 0) {
exerr = (uchar_t *)strerror(errno);
expath = savestr(f);
}
}
}
void
execash(int t, struct command *kp)
{
struct sigvec nsv;
didcch++;
nsv.sv_handler = parintr;
nsv.sv_mask = 0;
nsv.sv_onstack = 0;
(void)sigvec(SIGINT, &nsv, (struct sigvec *)NULL);
(void)sigvec(SIGQUIT, &nsv, (struct sigvec *)NULL);
/* if doexec loses, screw */
nsv.sv_handler = parterm;
(void)sigvec(SIGTERM, &nsv, (struct sigvec *)NULL);
lshift(kp->t_dcom, 1);
exiterr++;
#ifdef DEBUG
printf("debug: execash calls doexec\n");
#endif
doexec(kp);
/*NOTREACHED*/
}
void
xechoit(uchar_t **t)
{
if (adrof("echo")) {
flush();
haderr = 1;
blkpr(t);
printf("\n");
haderr = 0;
}
}
/*VARARGS0*//*ARGSUSED*/
void
dohash(void)
{
struct stat stb;
DIR *dirp;
register struct dirent *dp;
register int cnt;
int i = 0;
struct varent *v = adrof("path");
uchar_t **pv;
int hashval;
havhash = 1;
for (cnt = 0; cnt < sizeof xhash; cnt++)
xhash[cnt] = 0;
if (v == 0)
return;
for (pv = v->vec; *pv; pv++, i++) {
if (pv[0][0] != '/')
continue;
dirp = opendir((char *)*pv);
if (dirp == NULL)
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((uchar_t*)dp->d_name), i);
bis(xhash, hashval);
}
closedir(dirp);
}
}
void
dounhash(void)
{
havhash = 0;
}
void
hashstat(void)
{
if (hits+misses)
printf(MSGSTR(M_HITMISS,"%d hits, %d misses, %d%%\n"),
hits, misses, 100 * hits / (hits + misses));
}
static int
hashname(uchar_t *cp)
{
register long h = 0;
while (*cp)
h = hash(h, *cp++);
return ((int) h);
}