Home | History | Annotate | Download | only in sh
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
     28 /*	  All Rights Reserved  	*/
     29 
     30 /*
     31  *	UNIX shell
     32  */
     33 
     34 #include	"hash.h"
     35 #include	"defs.h"
     36 #include	<sys/types.h>
     37 #include	<sys/stat.h>
     38 #include	<errno.h>
     39 
     40 #define		EXECUTE		01
     41 
     42 static unsigned char	cost;
     43 static int	dotpath;
     44 static int	multrel;
     45 static struct entry	relcmd;
     46 
     47 static int	argpath();
     48 static void pr_path(unsigned char *, int);
     49 
     50 short
     51 pathlook(com, flg, arg)
     52 	unsigned char	*com;
     53 	int		flg;
     54 	struct argnod	*arg;
     55 {
     56 	unsigned char	*name = com;
     57 	ENTRY		*h;
     58 
     59 	ENTRY		hentry;
     60 	int		count = 0;
     61 	int		i;
     62 	int		pathset = 0;
     63 	int		oldpath = 0;
     64 	struct namnod	*n;
     65 
     66 
     67 
     68 	hentry.data = 0;
     69 
     70 	if (any('/', name))
     71 		return(COMMAND);
     72 
     73 	h = hfind(name);
     74 
     75 
     76 	if (h)
     77 	{
     78 		if (h->data & (BUILTIN | FUNCTION))
     79 		{
     80 			if (flg)
     81 				h->hits++;
     82 			return(h->data);
     83 		}
     84 
     85 		if (arg && (pathset = argpath(arg)))
     86 			return(PATH_COMMAND);
     87 
     88 		if ((h->data & DOT_COMMAND) == DOT_COMMAND)
     89 		{
     90 			if (multrel == 0 && hashdata(h->data) > dotpath)
     91 				oldpath = hashdata(h->data);
     92 			else
     93 				oldpath = dotpath;
     94 
     95 			h->data = 0;
     96 			goto pathsrch;
     97 		}
     98 
     99 		if (h->data & (COMMAND | REL_COMMAND))
    100 		{
    101 			if (flg)
    102 				h->hits++;
    103 			return(h->data);
    104 		}
    105 
    106 		h->data = 0;
    107 		h->cost = 0;
    108 	}
    109 
    110 	if (i = syslook(name, commands, no_commands))
    111 	{
    112 		hentry.data = (BUILTIN | i);
    113 		count = 1;
    114 	}
    115 	else
    116 	{
    117 		if (arg && (pathset = argpath(arg)))
    118 			return(PATH_COMMAND);
    119 pathsrch:
    120 			count = findpath(name, oldpath);
    121 	}
    122 
    123 	if (count > 0)
    124 	{
    125 		if (h == 0)
    126 		{
    127 			hentry.cost = 0;
    128 			hentry.key = make(name);
    129 			h = henter(hentry);
    130 		}
    131 
    132 		if (h->data == 0)
    133 		{
    134 			if (count < dotpath)
    135 				h->data = COMMAND | count;
    136 			else
    137 			{
    138 				h->data = REL_COMMAND | count;
    139 				h->next = relcmd.next;
    140 				relcmd.next = h;
    141 			}
    142 		}
    143 
    144 
    145 		h->hits = flg;
    146 		h->cost += cost;
    147 		return(h->data);
    148 	}
    149 	else
    150 	{
    151 		return(-count);
    152 	}
    153 }
    154 
    155 
    156 static void
    157 zapentry(h)
    158 	ENTRY *h;
    159 {
    160 	h->data &= HASHZAP;
    161 }
    162 
    163 void
    164 zaphash()
    165 {
    166 	hscan(zapentry);
    167 	relcmd.next = 0;
    168 }
    169 
    170 void
    171 zapcd()
    172 {
    173 	ENTRY *ptr = relcmd.next;
    174 
    175 	while (ptr)
    176 	{
    177 		ptr->data |= CDMARK;
    178 		ptr = ptr->next;
    179 	}
    180 	relcmd.next = 0;
    181 }
    182 
    183 
    184 static void
    185 hashout(h)
    186 	ENTRY *h;
    187 {
    188 	sigchk();
    189 
    190 	if (hashtype(h->data) == NOTFOUND)
    191 		return;
    192 
    193 	if (h->data & (BUILTIN | FUNCTION))
    194 		return;
    195 
    196 	prn_buff(h->hits);
    197 
    198 	if (h->data & REL_COMMAND)
    199 		prc_buff('*');
    200 
    201 
    202 	prc_buff(TAB);
    203 	prn_buff(h->cost);
    204 	prc_buff(TAB);
    205 
    206 	pr_path(h->key, hashdata(h->data));
    207 	prc_buff(NL);
    208 }
    209 
    210 void
    211 hashpr()
    212 {
    213 	prs_buff(_gettext("hits	cost	command\n"));
    214 	hscan(hashout);
    215 }
    216 
    217 void
    218 set_dotpath(void)
    219 {
    220 	unsigned char	*path;
    221 	int		cnt = 1;
    222 
    223 	dotpath = 10000;
    224 	path = getpath("");
    225 
    226 	while (path && *path)
    227 	{
    228 		if (*path == '/')
    229 			cnt++;
    230 		else
    231 		{
    232 			if (dotpath == 10000)
    233 				dotpath = cnt;
    234 			else
    235 			{
    236 				multrel = 1;
    237 				return;
    238 			}
    239 		}
    240 
    241 		path = nextpath(path);
    242 	}
    243 
    244 	multrel = 0;
    245 }
    246 
    247 void
    248 hash_func(unsigned char *name)
    249 {
    250 	ENTRY	*h;
    251 	ENTRY	hentry;
    252 
    253 	h = hfind(name);
    254 
    255 	if (h)
    256 		h->data = FUNCTION;
    257 	else
    258 	{
    259 		hentry.data = FUNCTION;
    260 		hentry.key = make(name);
    261 		hentry.cost = 0;
    262 		hentry.hits = 0;
    263 		henter(hentry);
    264 	}
    265 }
    266 
    267 void
    268 func_unhash(unsigned char *name)
    269 {
    270 	ENTRY 	*h;
    271 	int i;
    272 
    273 	h = hfind(name);
    274 
    275 	if (h && (h->data & FUNCTION)) {
    276 		if(i = syslook(name, commands, no_commands))
    277 			h->data = (BUILTIN|i);
    278 		else
    279 			h->data = NOTFOUND;
    280 	}
    281 }
    282 
    283 
    284 short
    285 hash_cmd(name)
    286 	unsigned char *name;
    287 {
    288 	ENTRY	*h;
    289 
    290 	if (any('/', name))
    291 		return(COMMAND);
    292 
    293 	h = hfind(name);
    294 
    295 	if (h)
    296 	{
    297 		if (h->data & (BUILTIN | FUNCTION))
    298 			return(h->data);
    299 		else if ((h->data & REL_COMMAND) == REL_COMMAND)
    300 		{ /* unlink h from relative command list */
    301 			ENTRY *ptr = &relcmd;
    302 			while(ptr-> next != h)
    303 				ptr = ptr->next;
    304 			ptr->next = h->next;
    305 		}
    306 		zapentry(h);
    307 	}
    308 
    309 	return(pathlook(name, 0, 0));
    310 }
    311 
    312 
    313 /*
    314  * Return 0 if found, 1 if not.
    315  */
    316 int
    317 what_is_path(unsigned char *name)
    318 {
    319 	ENTRY	*h;
    320 	int	cnt;
    321 	short	hashval;
    322 
    323 	h = hfind(name);
    324 
    325 	prs_buff(name);
    326 	if (h)
    327 	{
    328 		hashval = hashdata(h->data);
    329 
    330 		switch (hashtype(h->data))
    331 		{
    332 			case BUILTIN:
    333 				prs_buff(_gettext(" is a shell builtin\n"));
    334 				return (0);
    335 
    336 			case FUNCTION:
    337 			{
    338 				struct namnod *n = lookup(name);
    339 				struct fndnod *f = fndptr(n->namenv);
    340 
    341 				prs_buff(_gettext(" is a function\n"));
    342 				prs_buff(name);
    343 				prs_buff("(){\n");
    344 				if (f != NULL)
    345 					prf(f->fndval);
    346 				prs_buff("\n}\n");
    347 				return (0);
    348 			}
    349 
    350 			case REL_COMMAND:
    351 			{
    352 				short hash;
    353 
    354 				if ((h->data & DOT_COMMAND) == DOT_COMMAND)
    355 				{
    356 					hash = pathlook(name, 0, 0);
    357 					if (hashtype(hash) == NOTFOUND)
    358 					{
    359 						prs_buff(_gettext(" not"
    360 						    " found\n"));
    361 						return (1);
    362 					}
    363 					else
    364 						hashval = hashdata(hash);
    365 				}
    366 			}
    367 
    368 			case COMMAND:
    369 				prs_buff(_gettext(" is hashed ("));
    370 				pr_path(name, hashval);
    371 				prs_buff(")\n");
    372 				return (0);
    373 		}
    374 	}
    375 
    376 	if (syslook(name, commands, no_commands))
    377 	{
    378 		prs_buff(_gettext(" is a shell builtin\n"));
    379 		return (0);
    380 	}
    381 
    382 	if ((cnt = findpath(name, 0)) > 0)
    383 	{
    384 		prs_buff(_gettext(" is "));
    385 		pr_path(name, cnt);
    386 		prc_buff(NL);
    387 		return (0);
    388 	}
    389 	else
    390 	{
    391 		prs_buff(_gettext(" not found\n"));
    392 		return (1);
    393 	}
    394 }
    395 
    396 int
    397 findpath(unsigned char *name, int oldpath)
    398 {
    399 	unsigned char 	*path;
    400 	int	count = 1;
    401 
    402 	unsigned char	*p;
    403 	int	ok = 1;
    404 	int 	e_code = 1;
    405 
    406 	cost = 0;
    407 	path = getpath(name);
    408 
    409 	if (oldpath)
    410 	{
    411 		count = dotpath;
    412 		while (--count)
    413 			path = nextpath(path);
    414 
    415 		if (oldpath > dotpath)
    416 		{
    417 			catpath(path, name);
    418 			p = curstak();
    419 			cost = 1;
    420 
    421 			if ((ok = chk_access(p, S_IEXEC, 1)) == 0)
    422 				return(dotpath);
    423 			else
    424 				return(oldpath);
    425 		}
    426 		else
    427 			count = dotpath;
    428 	}
    429 
    430 	while (path)
    431 	{
    432 		path = catpath(path, name);
    433 		cost++;
    434 		p = curstak();
    435 
    436 		if ((ok = chk_access(p, S_IEXEC, 1)) == 0)
    437 			break;
    438 		else
    439 			e_code = max(e_code, ok);
    440 
    441 		count++;
    442 	}
    443 
    444 	return(ok ? -e_code : count);
    445 }
    446 
    447 /*
    448  * Determine if file given by name is accessible with permissions
    449  * given by mode.
    450  * Regflag argument non-zero means not to consider
    451  * a non-regular file as executable.
    452  */
    453 
    454 int
    455 chk_access(unsigned char *name, mode_t mode, int regflag)
    456 {
    457 	static int flag;
    458 	static uid_t euid;
    459 	struct stat statb;
    460 	mode_t ftype;
    461 
    462 	if(flag == 0) {
    463 		euid = geteuid();
    464 		flag = 1;
    465 	}
    466 	ftype = statb.st_mode & S_IFMT;
    467 	if (stat((char *)name, &statb) == 0) {
    468 		ftype = statb.st_mode & S_IFMT;
    469 		if(mode == S_IEXEC && regflag && ftype != S_IFREG)
    470 			return(2);
    471 		if(access((char *)name, 010|(mode>>6)) == 0) {
    472 			if(euid == 0) {
    473 				if (ftype != S_IFREG || mode != S_IEXEC)
    474 					return(0);
    475 		    		/* root can execute file as long as it has execute
    476 			   	permission for someone */
    477 				if (statb.st_mode & (S_IEXEC|(S_IEXEC>>3)|(S_IEXEC>>6)))
    478 					return(0);
    479 				return(3);
    480 			}
    481 			return(0);
    482 		}
    483 	}
    484 	return(errno == EACCES ? 3 : 1);
    485 }
    486 
    487 static void
    488 pr_path(unsigned char *name, int count)
    489 {
    490 	unsigned char	*path;
    491 
    492 	path = getpath(name);
    493 
    494 	while (--count && path)
    495 		path = nextpath(path, name);
    496 
    497 	catpath(path, name);
    498 	prs_buff(curstak());
    499 }
    500 
    501 
    502 static int
    503 argpath(struct argnod *arg)
    504 {
    505 	unsigned char 	*s;
    506 	unsigned char	*start;
    507 
    508 	while (arg)
    509 	{
    510 		s = arg->argval;
    511 		start = s;
    512 
    513 		if (letter(*s))
    514 		{
    515 			while (alphanum(*s))
    516 				s++;
    517 
    518 			if (*s == '=')
    519 			{
    520 				*s = 0;
    521 
    522 				if (eq(start, pathname))
    523 				{
    524 					*s = '=';
    525 					return(1);
    526 				}
    527 				else
    528 					*s = '=';
    529 			}
    530 		}
    531 		arg = arg->argnxt;
    532 	}
    533 
    534 	return(0);
    535 }
    536