xref: /illumos-gate/usr/src/cmd/sh/hashserv.c (revision cc6c5292fa8a241fe50604cf6a918edfbf7cd7d2)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 
23 /*
24  * Copyright 1990 Sun Microsystems, Inc.  All rights reserved.
25  * Use is subject to license terms.
26  */
27 
28 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
29 /*	  All Rights Reserved  	*/
30 
31 #pragma ident	"%Z%%M%	%I%	%E% SMI"
32 /*
33  *	UNIX shell
34  */
35 
36 #include	"hash.h"
37 #include	"defs.h"
38 #include	<sys/types.h>
39 #include	<sys/stat.h>
40 #include	<errno.h>
41 
42 #define		EXECUTE		01
43 
44 static unsigned char	cost;
45 static int	dotpath;
46 static int	multrel;
47 static struct entry	relcmd;
48 
49 static int	argpath();
50 static void pr_path(unsigned char *, int);
51 
52 short
53 pathlook(com, flg, arg)
54 	unsigned char	*com;
55 	int		flg;
56 	struct argnod	*arg;
57 {
58 	unsigned char	*name = com;
59 	ENTRY		*h;
60 
61 	ENTRY		hentry;
62 	int		count = 0;
63 	int		i;
64 	int		pathset = 0;
65 	int		oldpath = 0;
66 	struct namnod	*n;
67 
68 
69 
70 	hentry.data = 0;
71 
72 	if (any('/', name))
73 		return(COMMAND);
74 
75 	h = hfind(name);
76 
77 
78 	if (h)
79 	{
80 		if (h->data & (BUILTIN | FUNCTION))
81 		{
82 			if (flg)
83 				h->hits++;
84 			return(h->data);
85 		}
86 
87 		if (arg && (pathset = argpath(arg)))
88 			return(PATH_COMMAND);
89 
90 		if ((h->data & DOT_COMMAND) == DOT_COMMAND)
91 		{
92 			if (multrel == 0 && hashdata(h->data) > dotpath)
93 				oldpath = hashdata(h->data);
94 			else
95 				oldpath = dotpath;
96 
97 			h->data = 0;
98 			goto pathsrch;
99 		}
100 
101 		if (h->data & (COMMAND | REL_COMMAND))
102 		{
103 			if (flg)
104 				h->hits++;
105 			return(h->data);
106 		}
107 
108 		h->data = 0;
109 		h->cost = 0;
110 	}
111 
112 	if (i = syslook(name, commands, no_commands))
113 	{
114 		hentry.data = (BUILTIN | i);
115 		count = 1;
116 	}
117 	else
118 	{
119 		if (arg && (pathset = argpath(arg)))
120 			return(PATH_COMMAND);
121 pathsrch:
122 			count = findpath(name, oldpath);
123 	}
124 
125 	if (count > 0)
126 	{
127 		if (h == 0)
128 		{
129 			hentry.cost = 0;
130 			hentry.key = make(name);
131 			h = henter(hentry);
132 		}
133 
134 		if (h->data == 0)
135 		{
136 			if (count < dotpath)
137 				h->data = COMMAND | count;
138 			else
139 			{
140 				h->data = REL_COMMAND | count;
141 				h->next = relcmd.next;
142 				relcmd.next = h;
143 			}
144 		}
145 
146 
147 		h->hits = flg;
148 		h->cost += cost;
149 		return(h->data);
150 	}
151 	else
152 	{
153 		return(-count);
154 	}
155 }
156 
157 
158 static void
159 zapentry(h)
160 	ENTRY *h;
161 {
162 	h->data &= HASHZAP;
163 }
164 
165 void
166 zaphash()
167 {
168 	hscan(zapentry);
169 	relcmd.next = 0;
170 }
171 
172 void
173 zapcd()
174 {
175 	ENTRY *ptr = relcmd.next;
176 
177 	while (ptr)
178 	{
179 		ptr->data |= CDMARK;
180 		ptr = ptr->next;
181 	}
182 	relcmd.next = 0;
183 }
184 
185 
186 static void
187 hashout(h)
188 	ENTRY *h;
189 {
190 	sigchk();
191 
192 	if (hashtype(h->data) == NOTFOUND)
193 		return;
194 
195 	if (h->data & (BUILTIN | FUNCTION))
196 		return;
197 
198 	prn_buff(h->hits);
199 
200 	if (h->data & REL_COMMAND)
201 		prc_buff('*');
202 
203 
204 	prc_buff(TAB);
205 	prn_buff(h->cost);
206 	prc_buff(TAB);
207 
208 	pr_path(h->key, hashdata(h->data));
209 	prc_buff(NL);
210 }
211 
212 void
213 hashpr()
214 {
215 	prs_buff("hits	cost	command\n");
216 	hscan(hashout);
217 }
218 
219 void
220 set_dotpath(void)
221 {
222 	unsigned char	*path;
223 	int		cnt = 1;
224 
225 	dotpath = 10000;
226 	path = getpath("");
227 
228 	while (path && *path)
229 	{
230 		if (*path == '/')
231 			cnt++;
232 		else
233 		{
234 			if (dotpath == 10000)
235 				dotpath = cnt;
236 			else
237 			{
238 				multrel = 1;
239 				return;
240 			}
241 		}
242 
243 		path = nextpath(path);
244 	}
245 
246 	multrel = 0;
247 }
248 
249 void
250 hash_func(unsigned char *name)
251 {
252 	ENTRY	*h;
253 	ENTRY	hentry;
254 
255 	h = hfind(name);
256 
257 	if (h)
258 		h->data = FUNCTION;
259 	else
260 	{
261 		hentry.data = FUNCTION;
262 		hentry.key = make(name);
263 		hentry.cost = 0;
264 		hentry.hits = 0;
265 		henter(hentry);
266 	}
267 }
268 
269 void
270 func_unhash(unsigned char *name)
271 {
272 	ENTRY 	*h;
273 	int i;
274 
275 	h = hfind(name);
276 
277 	if (h && (h->data & FUNCTION)) {
278 		if(i = syslook(name, commands, no_commands))
279 			h->data = (BUILTIN|i);
280 		else
281 			h->data = NOTFOUND;
282 	}
283 }
284 
285 
286 short
287 hash_cmd(name)
288 	unsigned char *name;
289 {
290 	ENTRY	*h;
291 
292 	if (any('/', name))
293 		return(COMMAND);
294 
295 	h = hfind(name);
296 
297 	if (h)
298 	{
299 		if (h->data & (BUILTIN | FUNCTION))
300 			return(h->data);
301 		else if ((h->data & REL_COMMAND) == REL_COMMAND)
302 		{ /* unlink h from relative command list */
303 			ENTRY *ptr = &relcmd;
304 			while(ptr-> next != h)
305 				ptr = ptr->next;
306 			ptr->next = h->next;
307 		}
308 		zapentry(h);
309 	}
310 
311 	return(pathlook(name, 0, 0));
312 }
313 
314 
315 /*
316  * Return 0 if found, 1 if not.
317  */
318 int
319 what_is_path(unsigned char *name)
320 {
321 	ENTRY	*h;
322 	int	cnt;
323 	short	hashval;
324 
325 	h = hfind(name);
326 
327 	prs_buff(name);
328 	if (h)
329 	{
330 		hashval = hashdata(h->data);
331 
332 		switch (hashtype(h->data))
333 		{
334 			case BUILTIN:
335 				prs_buff(" is a shell builtin\n");
336 				return (0);
337 
338 			case FUNCTION:
339 			{
340 				struct namnod *n = lookup(name);
341 
342 				prs_buff(" is a function\n");
343 				prs_buff(name);
344 				prs_buff("(){\n");
345 				prf(n->namenv);
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(" not found\n");
360 						return (1);
361 					}
362 					else
363 						hashval = hashdata(hash);
364 				}
365 			}
366 
367 			case COMMAND:
368 				prs_buff(" 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(" is a shell builtin\n");
378 		return (0);
379 	}
380 
381 	if ((cnt = findpath(name, 0)) > 0)
382 	{
383 		prs_buff(" is ");
384 		pr_path(name, cnt);
385 		prc_buff(NL);
386 		return (0);
387 	}
388 	else
389 	{
390 		prs_buff(" 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