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
42static unsigned char	cost;
43static int	dotpath;
44static int	multrel;
45static struct entry	relcmd;
46
47static int	argpath();
48static void pr_path(unsigned char *, int);
49
50short
51pathlook(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);
119pathsrch:
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
156static void
157zapentry(h)
158	ENTRY *h;
159{
160	h->data &= HASHZAP;
161}
162
163void
164zaphash()
165{
166	hscan(zapentry);
167	relcmd.next = 0;
168}
169
170void
171zapcd()
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
184static void
185hashout(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
210void
211hashpr()
212{
213	prs_buff(_gettext("hits	cost	command\n"));
214	hscan(hashout);
215}
216
217void
218set_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
247void
248hash_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
267void
268func_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
284short
285hash_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 */
316int
317what_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
396int
397findpath(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
454int
455chk_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
487static void
488pr_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
502static int
503argpath(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