xref: /illumos-gate/usr/src/cmd/sh/hashserv.c (revision 657a8c206b913d1ee578fd725f0b25eca5b77253)
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