Home | History | Annotate | Download | only in csh
      1    0   stevel /*
      2  356   muffin  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
      3    0   stevel  * Use is subject to license terms.
      4    0   stevel  */
      5    0   stevel 
      6    0   stevel /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
      7    0   stevel /*	  All Rights Reserved  	*/
      8    0   stevel 
      9    0   stevel /*
     10    0   stevel  * Copyright (c) 1980 Regents of the University of California.
     11    0   stevel  * All rights reserved.  The Berkeley Software License Agreement
     12    0   stevel  * specifies the terms and conditions for redistribution.
     13    0   stevel  */
     14    0   stevel 
     15    0   stevel #pragma ident	"%Z%%M%	%I%	%E% SMI"
     16    0   stevel 
     17    0   stevel #include "sh.h"
     18    0   stevel #include <dirent.h>
     19    0   stevel #include <string.h>
     20    0   stevel #include "sh.tconst.h"
     21    0   stevel #include "sh_policy.h"
     22    0   stevel 
     23    0   stevel 
     24    0   stevel /*
     25    0   stevel  * C shell
     26    0   stevel  */
     27    0   stevel 
     28    0   stevel /*
     29    0   stevel  * System level search and execute of a command.
     30    0   stevel  * We look in each directory for the specified command name.
     31    0   stevel  * If the name contains a '/' then we execute only the full path name.
     32    0   stevel  * If there is no search path then we execute only full path names.
     33    0   stevel  */
     34    0   stevel 
     35  559  nakanon /*
     36    0   stevel  * As we search for the command we note the first non-trivial error
     37    0   stevel  * message for presentation to the user.  This allows us often
     38    0   stevel  * to show that a file has the wrong mode/no access when the file
     39    0   stevel  * is not in the last component of the search path, so we must
     40    0   stevel  * go on after first detecting the error.
     41    0   stevel  */
     42    0   stevel char *exerr;			/* Execution error message */
     43    0   stevel 
     44  356   muffin void	pexerr(void);
     45  356   muffin void	texec(struct command *, tchar *, tchar **);
     46  356   muffin void	xechoit(tchar **);
     47  356   muffin void	dohash(char []);
     48    0   stevel 
     49  356   muffin static void	tconvert(struct command *, tchar *, tchar **);
     50    0   stevel 
     51    0   stevel 
     52  356   muffin extern DIR *opendir_(tchar *);
     53  356   muffin 
     54  356   muffin void
     55  356   muffin doexec(struct command *t)
     56    0   stevel {
     57    0   stevel 	tchar *sav;
     58  356   muffin 	tchar *dp, **pv, **av;
     59  356   muffin 	struct varent *v;
     60    0   stevel 	bool slash;
     61    0   stevel 	int hashval, hashval1, i;
     62    0   stevel 	tchar *blk[2];
     63    0   stevel #ifdef TRACE
     64    0   stevel 	tprintf("TRACE- doexec()\n");
     65    0   stevel #endif
     66    0   stevel 
     67    0   stevel 	/*
     68    0   stevel 	 * Glob the command name.  If this does anything, then we
     69    0   stevel 	 * will execute the command only relative to ".".  One special
     70    0   stevel 	 * case: if there is no PATH, then we execute only commands
     71    0   stevel 	 * which start with '/'.
     72    0   stevel 	 */
     73    0   stevel 	dp = globone(t->t_dcom[0]);
     74    0   stevel 	sav = t->t_dcom[0];
     75    0   stevel 	exerr = 0; t->t_dcom[0] = dp;
     76    0   stevel 	setname(dp);
     77    0   stevel 	xfree(sav);
     78  559  nakanon 	v = adrof(S_path /* "path" */);
     79    0   stevel 	if (v == 0 && dp[0] != '/') {
     80    0   stevel 		pexerr();
     81    0   stevel 	}
     82    0   stevel 	slash = gflag;
     83    0   stevel 
     84    0   stevel 	/*
     85    0   stevel 	 * Glob the argument list, if necessary.
     86    0   stevel 	 * Otherwise trim off the quote bits.
     87    0   stevel 	 */
     88    0   stevel 	gflag = 0; av = &t->t_dcom[1];
     89    0   stevel 	tglob(av);
     90    0   stevel 	if (gflag) {
     91    0   stevel 		av = glob(av);
     92    0   stevel 		if (av == 0)
     93    0   stevel 			error("No match");
     94    0   stevel 	}
     95    0   stevel 	blk[0] = t->t_dcom[0];
     96    0   stevel 	blk[1] = 0;
     97    0   stevel 	av = blkspl(blk, av);
     98    0   stevel #ifdef VFORK
     99    0   stevel 	Vav = av;
    100    0   stevel #endif
    101    0   stevel 	trim(av);
    102    0   stevel 	slash |= any('/', av[0]);
    103    0   stevel 
    104    0   stevel 	xechoit(av);		/* Echo command if -x */
    105    0   stevel 	/*
    106    0   stevel 	 * Since all internal file descriptors are set to close on exec,
    107    0   stevel 	 * we don't need to close them explicitly here.  Just reorient
    108    0   stevel 	 * ourselves for error messages.
    109    0   stevel 	 */
    110    0   stevel 	SHIN = 0; SHOUT = 1; SHDIAG = 2; OLDSTD = 0;
    111    0   stevel 
    112    0   stevel 	/*
    113    0   stevel 	 * We must do this AFTER any possible forking (like `foo`
    114    0   stevel 	 * in glob) so that this shell can still do subprocesses.
    115    0   stevel 	 */
    116    0   stevel 	(void) sigsetmask(0);
    117    0   stevel 
    118    0   stevel 	/*
    119    0   stevel 	 * If no path, no words in path, or a / in the filename
    120    0   stevel 	 * then restrict the command search.
    121    0   stevel 	 */
    122    0   stevel 	if (v == 0 || v->vec[0] == 0 || slash)
    123    0   stevel 		pv = justabs;
    124    0   stevel 	else
    125    0   stevel 		pv = v->vec;
    126  559  nakanon 	sav = strspl(S_SLASH /* "/" */, *av); /* / command name for postpending */
    127    0   stevel #ifdef VFORK
    128    0   stevel 	Vsav = sav;
    129    0   stevel #endif
    130    0   stevel 	if (havhash)
    131    0   stevel 		hashval = hashname(*av);
    132    0   stevel 	i = 0;
    133    0   stevel #ifdef VFORK
    134    0   stevel 	hits++;
    135    0   stevel #endif
    136    0   stevel 	do {
    137    0   stevel 		if (!slash && pv[0][0] == '/' && havhash) {
    138    0   stevel 			hashval1 = hash(hashval, i);
    139    0   stevel 			if (!bit(xhash, hashval1))
    140    0   stevel 				goto cont;
    141    0   stevel 		}
    142    0   stevel 
    143  559  nakanon 		if (pv[0][0] == 0 || eq(pv[0], S_DOT /* "." */)) { /* don't make ./xxx */
    144    0   stevel 			texec(t, *av, av);
    145    0   stevel 		} else {
    146    0   stevel 			dp = strspl(*pv, sav);
    147    0   stevel #ifdef VFORK
    148    0   stevel 			Vdp = dp;
    149    0   stevel #endif
    150    0   stevel 			texec(t, dp, av);
    151    0   stevel #ifdef VFORK
    152    0   stevel 			Vdp = 0;
    153    0   stevel #endif
    154    0   stevel 			xfree(dp);
    155    0   stevel 		}
    156    0   stevel #ifdef VFORK
    157    0   stevel 		misses++;
    158    0   stevel #endif
    159    0   stevel cont:
    160    0   stevel 		pv++;
    161    0   stevel 		i++;
    162    0   stevel 	} while (*pv);
    163    0   stevel #ifdef VFORK
    164    0   stevel 	hits--;
    165    0   stevel #endif
    166    0   stevel #ifdef VFORK
    167    0   stevel 	Vsav = 0;
    168    0   stevel 	Vav = 0;
    169    0   stevel #endif
    170    0   stevel 	xfree(sav);
    171  559  nakanon 	xfree((char *)av);
    172    0   stevel 	pexerr();
    173    0   stevel }
    174    0   stevel 
    175  356   muffin void
    176  356   muffin pexerr(void)
    177    0   stevel {
    178    0   stevel 
    179    0   stevel #ifdef TRACE
    180    0   stevel 	tprintf("TRACE- pexerr()\n");
    181    0   stevel #endif
    182    0   stevel 	/* Couldn't find the damn thing */
    183    0   stevel 	if (exerr)
    184    0   stevel 		bferr(exerr);
    185    0   stevel 	bferr("Command not found");
    186    0   stevel }
    187    0   stevel 
    188    0   stevel /*
    189    0   stevel  * Execute command f, arg list t.
    190    0   stevel  * Record error message if not found.
    191    0   stevel  * Also do shell scripts here.
    192    0   stevel  */
    193  356   muffin void
    194  356   muffin texec(struct command *cmd, tchar *f, tchar **t)
    195    0   stevel {
    196  356   muffin 	int	pfstatus = 0;
    197  356   muffin 	struct	varent *v;
    198  356   muffin 	tchar	**vp;
    199    0   stevel 	tchar		*lastsh[2];
    200  559  nakanon 
    201    0   stevel #ifdef TRACE
    202    0   stevel 	tprintf("TRACE- texec()\n");
    203    0   stevel #endif
    204    0   stevel 	/* convert cfname and cargs from tchar to char */
    205    0   stevel 	tconvert(cmd, f, t);
    206    0   stevel 
    207    0   stevel 	if (pfcshflag == 1) {
    208    0   stevel 		pfstatus = secpolicy_pfexec((const char *)(cmd->cfname),
    209    0   stevel 		    cmd->cargs, (const char **)NULL);
    210    0   stevel 		if (pfstatus != NOATTRS) {
    211    0   stevel 			errno = pfstatus;
    212    0   stevel 		}
    213    0   stevel 	}
    214    0   stevel 	if ((pfcshflag == 0) || (pfstatus == NOATTRS)) {
    215    0   stevel 		execv(cmd->cfname, cmd->cargs);
    216    0   stevel 	}
    217    0   stevel 
    218    0   stevel 	/*
    219    0   stevel 	 * exec returned, free up allocations from above
    220    0   stevel 	 * tconvert(), zero cfname and cargs to prevent
    221    0   stevel 	 * duplicate free() in freesyn()
    222    0   stevel 	 */
    223    0   stevel 	xfree(cmd->cfname);
    224    0   stevel 	chr_blkfree(cmd->cargs);
    225  559  nakanon 	cmd->cfname = (char *)0;
    226  559  nakanon 	cmd->cargs = (char **)0;
    227    0   stevel 
    228    0   stevel 	switch (errno) {
    229    0   stevel 	case ENOEXEC:
    230    0   stevel 		/* check that this is not a binary file */
    231  559  nakanon 		{
    232  356   muffin 			int ff = open_(f, 0);
    233  559  nakanon 			tchar ch[MB_LEN_MAX];
    234    0   stevel 
    235  559  nakanon 			if (ff != -1 && read_(ff, ch, 1) == 1 &&
    236  559  nakanon 			    !isprint(ch[0]) && !isspace(ch[0])) {
    237    0   stevel 				printf("Cannot execute binary file.\n");
    238    0   stevel 				Perror(f);
    239    0   stevel 				(void) close(ff);
    240    0   stevel 				unsetfd(ff);
    241    0   stevel 				return;
    242  559  nakanon 			}
    243    0   stevel 			(void) close(ff);
    244    0   stevel 			unsetfd(ff);
    245  559  nakanon 		}
    246    0   stevel 		/*
    247    0   stevel 		 * If there is an alias for shell, then
    248    0   stevel 		 * put the words of the alias in front of the
    249    0   stevel 		 * argument list replacing the command name.
    250    0   stevel 		 * Note no interpretation of the words at this point.
    251    0   stevel 		 */
    252  559  nakanon 		v = adrof1(S_shell /* "shell" */, &aliases);
    253    0   stevel 		if (v == 0) {
    254    0   stevel #ifdef OTHERSH
    255  356   muffin 			int ff = open_(f, 0);
    256  559  nakanon 			tchar ch[MB_LEN_MAX];
    257    0   stevel #endif
    258    0   stevel 
    259    0   stevel 			vp = lastsh;
    260  559  nakanon 			vp[0] = adrof(S_shell /* "shell" */) ? value(S_shell /* "shell" */) : S_SHELLPATH /* SHELLPATH */;
    261    0   stevel 			vp[1] =  (tchar *) NULL;
    262    0   stevel #ifdef OTHERSH
    263  559  nakanon 			if (ff != -1 && read_(ff, ch, 1) == 1 && ch[0] != '#')
    264  559  nakanon 				vp[0] = S_OTHERSH /* OTHERSH */;
    265    0   stevel 			(void) close(ff);
    266    0   stevel 			unsetfd(ff);
    267    0   stevel #endif
    268    0   stevel 		} else
    269    0   stevel 			vp = v->vec;
    270    0   stevel 		t[0] = f;
    271    0   stevel 		t = blkspl(vp, t);		/* Splice up the new arglst */
    272    0   stevel 		f = *t;
    273    0   stevel 
    274    0   stevel 		tconvert(cmd, f, t);		/* convert tchar to char */
    275    0   stevel 
    276    0   stevel 		/*
    277    0   stevel 		 * now done with tchar arg list t,
    278    0   stevel 		 * free the space calloc'd by above blkspl()
    279    0   stevel 		 */
    280  559  nakanon 		xfree((char *)t);
    281    0   stevel 
    282    0   stevel 		execv(cmd->cfname, cmd->cargs);	/* exec the command */
    283    0   stevel 
    284    0   stevel 		/* exec returned, same free'ing as above */
    285    0   stevel 		xfree(cmd->cfname);
    286    0   stevel 		chr_blkfree(cmd->cargs);
    287  559  nakanon 		cmd->cfname = (char *)0;
    288  559  nakanon 		cmd->cargs = (char **)0;
    289    0   stevel 
    290    0   stevel 		/* The sky is falling, the sky is falling! */
    291    0   stevel 
    292    0   stevel 	case ENOMEM:
    293    0   stevel 		Perror(f);
    294    0   stevel 
    295    0   stevel 	case ENOENT:
    296    0   stevel 		break;
    297    0   stevel 
    298    0   stevel 	default:
    299    0   stevel 		if (exerr == 0) {
    300    0   stevel 			exerr = strerror(errno);
    301    0   stevel 			setname(f);
    302    0   stevel 		}
    303    0   stevel 	}
    304    0   stevel }
    305    0   stevel 
    306    0   stevel 
    307  356   muffin static void
    308  356   muffin tconvert(struct command *cmd, tchar *fname, tchar **list)
    309    0   stevel {
    310  356   muffin 	char **rc;
    311  356   muffin 	int len;
    312    0   stevel 
    313    0   stevel 	cmd->cfname = tstostr(NULL, fname);
    314    0   stevel 
    315    0   stevel 	len = blklen(list);
    316    0   stevel 	rc = cmd->cargs = (char **)
    317  559  nakanon 		xcalloc((uint_t)(len + 1), sizeof (char **));
    318    0   stevel 	while (len--)
    319    0   stevel 		*rc++ = tstostr(NULL, *list++);
    320    0   stevel 	*rc = NULL;
    321    0   stevel }
    322    0   stevel 
    323    0   stevel 
    324    0   stevel /*ARGSUSED*/
    325  356   muffin void
    326  356   muffin execash(tchar **t, struct command *kp)
    327    0   stevel {
    328    0   stevel #ifdef TRACE
    329    0   stevel 	tprintf("TRACE- execash()\n");
    330    0   stevel #endif
    331    0   stevel 
    332    0   stevel 	rechist();
    333    0   stevel 	(void) signal(SIGINT, parintr);
    334    0   stevel 	(void) signal(SIGQUIT, parintr);
    335    0   stevel 	(void) signal(SIGTERM, parterm);	/* if doexec loses, screw */
    336    0   stevel 	lshift(kp->t_dcom, 1);
    337    0   stevel 	exiterr++;
    338    0   stevel 	doexec(kp);
    339    0   stevel 	/*NOTREACHED*/
    340    0   stevel }
    341    0   stevel 
    342  356   muffin void
    343  356   muffin xechoit(tchar **t)
    344    0   stevel {
    345    0   stevel #ifdef TRACE
    346    0   stevel 	tprintf("TRACE- xechoit()\n");
    347    0   stevel #endif
    348    0   stevel 
    349  559  nakanon 	if (adrof(S_echo /* "echo" */)) {
    350    0   stevel 		flush();
    351    0   stevel 		haderr = 1;
    352    0   stevel 		blkpr(t), Putchar('\n');
    353    0   stevel 		haderr = 0;
    354    0   stevel 	}
    355    0   stevel }
    356    0   stevel 
    357  559  nakanon /*
    358    0   stevel  * This routine called when user enters "rehash".
    359    0   stevel  * Both the path and cdpath caching arrays will
    360    0   stevel  * be rehashed, via calling dohash.  If either
    361    0   stevel  * variable is not set with a value, then dohash
    362    0   stevel  * just exits.
    363    0   stevel  */
    364  356   muffin void
    365  356   muffin dorehash(void)
    366    0   stevel {
    367    0   stevel 	dohash(xhash);
    368    0   stevel 	dohash(xhash2);
    369    0   stevel }
    370    0   stevel 
    371    0   stevel /*
    372    0   stevel  * Fill up caching arrays for path and cdpath
    373    0   stevel  */
    374  356   muffin void
    375  356   muffin dohash(char cachearray[])
    376    0   stevel {
    377    0   stevel 	struct stat stb;
    378    0   stevel 	DIR *dirp;
    379  356   muffin 	struct dirent *dp;
    380  356   muffin 	int cnt;
    381    0   stevel 	int i = 0;
    382    0   stevel 	struct varent *v;
    383    0   stevel 	tchar **pv;
    384    0   stevel 	int hashval;
    385    0   stevel 	tchar curdir_[MAXNAMLEN+1];
    386    0   stevel 
    387    0   stevel #ifdef TRACE
    388    0   stevel 	tprintf("TRACE- dohash()\n");
    389    0   stevel #endif
    390    0   stevel 	/* Caching $path */
    391  559  nakanon 	if (cachearray == xhash) {
    392    0   stevel 		havhash = 1;
    393  559  nakanon 		v = adrof(S_path /* "path" */);
    394  559  nakanon 	} else {    /* Caching $cdpath */
    395    0   stevel 		havhash2 = 1;
    396  559  nakanon 		v = adrof(S_cdpath /* "cdpath" */);
    397    0   stevel 	}
    398    0   stevel 
    399  559  nakanon 	for (cnt = 0; cnt < (HSHSIZ / 8); cnt++)
    400    0   stevel 		cachearray[cnt] = 0;
    401    0   stevel 	if (v == 0)
    402    0   stevel 		{
    403    0   stevel 		return;
    404    0   stevel 		}
    405    0   stevel 	for (pv = v->vec; *pv; pv++, i++) {
    406    0   stevel 		if (pv[0][0] != '/')
    407    0   stevel 			continue;
    408    0   stevel 		dirp = opendir_(*pv);
    409    0   stevel 		if (dirp == NULL)
    410    0   stevel 			continue;
    411    0   stevel 		if (fstat(dirp->dd_fd, &stb) < 0 || !isdir(stb)) {
    412    0   stevel 			unsetfd(dirp->dd_fd);
    413    0   stevel 			closedir_(dirp);
    414    0   stevel 			continue;
    415    0   stevel 		}
    416    0   stevel 		while ((dp = readdir(dirp)) != NULL) {
    417    0   stevel 			if (dp->d_ino == 0)
    418    0   stevel 				continue;
    419    0   stevel 			if (dp->d_name[0] == '.' &&
    420    0   stevel 			    (dp->d_name[1] == '\0' ||
    421  559  nakanon 			    dp->d_name[1] == '.' && dp->d_name[2] == '\0'))
    422    0   stevel 				continue;
    423  559  nakanon 			hashval = hash(hashname(strtots(curdir_, dp->d_name)), i);
    424    0   stevel 			bis(cachearray, hashval);
    425    0   stevel 		}
    426    0   stevel 		unsetfd(dirp->dd_fd);
    427    0   stevel 		closedir_(dirp);
    428    0   stevel 	}
    429    0   stevel }
    430    0   stevel 
    431  356   muffin void
    432  356   muffin dounhash(void)
    433    0   stevel {
    434    0   stevel 
    435    0   stevel #ifdef TRACE
    436    0   stevel 	tprintf("TRACE- dounhash()\n");
    437    0   stevel #endif
    438    0   stevel 	havhash = 0;
    439    0   stevel 	havhash2 = 0;
    440    0   stevel }
    441    0   stevel 
    442    0   stevel #ifdef VFORK
    443  356   muffin void
    444  356   muffin hashstat(void)
    445    0   stevel {
    446    0   stevel #ifdef TRACE
    447    0   stevel 	tprintf("TRACE- hashstat_()\n");
    448    0   stevel #endif
    449    0   stevel 
    450    0   stevel 	if (hits+misses)
    451    0   stevel 		printf("%d hits, %d misses, %d%%\n",
    452    0   stevel 			hits, misses, 100 * hits / (hits + misses));
    453    0   stevel }
    454    0   stevel #endif
    455    0   stevel 
    456    0   stevel /*
    457    0   stevel  * Hash a command name.
    458    0   stevel  */
    459  356   muffin int
    460  356   muffin hashname(tchar *cp)
    461    0   stevel {
    462  356   muffin 	long h = 0;
    463    0   stevel 
    464    0   stevel #ifdef TRACE
    465    0   stevel 	tprintf("TRACE- hashname()\n");
    466    0   stevel #endif
    467    0   stevel 	while (*cp)
    468    0   stevel 		h = hash(h, *cp++);
    469  559  nakanon 	return ((int)h);
    470    0   stevel }
    471