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
pathlook(com,flg,arg)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
zapentry(h)157 zapentry(h)
158 ENTRY *h;
159 {
160 h->data &= HASHZAP;
161 }
162
163 void
zaphash()164 zaphash()
165 {
166 hscan(zapentry);
167 relcmd.next = 0;
168 }
169
170 void
zapcd()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
hashout(h)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
hashpr()211 hashpr()
212 {
213 prs_buff(_gettext("hits cost command\n"));
214 hscan(hashout);
215 }
216
217 void
set_dotpath(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
hash_func(unsigned char * name)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
func_unhash(unsigned char * name)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
hash_cmd(name)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
what_is_path(unsigned char * name)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
findpath(unsigned char * name,int oldpath)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
chk_access(unsigned char * name,mode_t mode,int regflag)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
pr_path(unsigned char * name,int count)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
argpath(struct argnod * arg)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