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