xref: /original-bsd/bin/sh/exec.c (revision b55621b9)
1 /*-
2  * Copyright (c) 1991, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Kenneth Almquist.
7  *
8  * %sccs.include.redist.c%
9  */
10 
11 #ifndef lint
12 static char sccsid[] = "@(#)exec.c	8.2 (Berkeley) 04/28/95";
13 #endif /* not lint */
14 
15 /*
16  * When commands are first encountered, they are entered in a hash table.
17  * This ensures that a full path search will not have to be done for them
18  * on each invocation.
19  *
20  * We should investigate converting to a linear search, even though that
21  * would make the command name "hash" a misnomer.
22  */
23 
24 #include "shell.h"
25 #include "main.h"
26 #include "nodes.h"
27 #include "parser.h"
28 #include "redir.h"
29 #include "eval.h"
30 #include "exec.h"
31 #include "builtins.h"
32 #include "var.h"
33 #include "options.h"
34 #include "input.h"
35 #include "output.h"
36 #include "syntax.h"
37 #include "memalloc.h"
38 #include "error.h"
39 #include "init.h"
40 #include "mystring.h"
41 #include "jobs.h"
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <fcntl.h>
45 #include <errno.h>
46 
47 
48 #define CMDTABLESIZE 31		/* should be prime */
49 #define ARB 1			/* actual size determined at run time */
50 
51 
52 
53 struct tblentry {
54 	struct tblentry *next;	/* next entry in hash chain */
55 	union param param;	/* definition of builtin function */
56 	short cmdtype;		/* index identifying command */
57 	char rehash;		/* if set, cd done since entry created */
58 	char cmdname[ARB];	/* name of command */
59 };
60 
61 
62 STATIC struct tblentry *cmdtable[CMDTABLESIZE];
63 STATIC int builtinloc = -1;		/* index in path of %builtin, or -1 */
64 
65 
66 #ifdef __STDC__
67 STATIC void tryexec(char *, char **, char **);
68 STATIC void execinterp(char **, char **);
69 STATIC void printentry(struct tblentry *, int);
70 STATIC void clearcmdentry(int);
71 STATIC struct tblentry *cmdlookup(char *, int);
72 STATIC void delete_cmd_entry(void);
73 #else
74 STATIC void tryexec();
75 STATIC void execinterp();
76 STATIC void printentry();
77 STATIC void clearcmdentry();
78 STATIC struct tblentry *cmdlookup();
79 STATIC void delete_cmd_entry();
80 #endif
81 
82 
83 
84 /*
85  * Exec a program.  Never returns.  If you change this routine, you may
86  * have to change the find_command routine as well.
87  */
88 
89 void
90 shellexec(argv, envp, path, index)
91 	char **argv, **envp;
92 	char *path;
93 	{
94 	char *cmdname;
95 	int e;
96 
97 	if (strchr(argv[0], '/') != NULL) {
98 		tryexec(argv[0], argv, envp);
99 		e = errno;
100 	} else {
101 		e = ENOENT;
102 		while ((cmdname = padvance(&path, argv[0])) != NULL) {
103 			if (--index < 0 && pathopt == NULL) {
104 				tryexec(cmdname, argv, envp);
105 				if (errno != ENOENT && errno != ENOTDIR)
106 					e = errno;
107 			}
108 			stunalloc(cmdname);
109 		}
110 	}
111 	error2(argv[0], errmsg(e, E_EXEC));
112 }
113 
114 
115 STATIC void
116 tryexec(cmd, argv, envp)
117 	char *cmd;
118 	char **argv;
119 	char **envp;
120 	{
121 	int e;
122 	char *p;
123 
124 #ifdef SYSV
125 	do {
126 		execve(cmd, argv, envp);
127 	} while (errno == EINTR);
128 #else
129 	execve(cmd, argv, envp);
130 #endif
131 	e = errno;
132 	if (e == ENOEXEC) {
133 		initshellproc();
134 		setinputfile(cmd, 0);
135 		commandname = arg0 = savestr(argv[0]);
136 #ifndef BSD
137 		pgetc(); pungetc();		/* fill up input buffer */
138 		p = parsenextc;
139 		if (parsenleft > 2 && p[0] == '#' && p[1] == '!') {
140 			argv[0] = cmd;
141 			execinterp(argv, envp);
142 		}
143 #endif
144 		setparam(argv + 1);
145 		exraise(EXSHELLPROC);
146 		/*NOTREACHED*/
147 	}
148 	errno = e;
149 }
150 
151 
152 #ifndef BSD
153 /*
154  * Execute an interpreter introduced by "#!", for systems where this
155  * feature has not been built into the kernel.  If the interpreter is
156  * the shell, return (effectively ignoring the "#!").  If the execution
157  * of the interpreter fails, exit.
158  *
159  * This code peeks inside the input buffer in order to avoid actually
160  * reading any input.  It would benefit from a rewrite.
161  */
162 
163 #define NEWARGS 5
164 
165 STATIC void
166 execinterp(argv, envp)
167 	char **argv, **envp;
168 	{
169 	int n;
170 	char *inp;
171 	char *outp;
172 	char c;
173 	char *p;
174 	char **ap;
175 	char *newargs[NEWARGS];
176 	int i;
177 	char **ap2;
178 	char **new;
179 
180 	n = parsenleft - 2;
181 	inp = parsenextc + 2;
182 	ap = newargs;
183 	for (;;) {
184 		while (--n >= 0 && (*inp == ' ' || *inp == '\t'))
185 			inp++;
186 		if (n < 0)
187 			goto bad;
188 		if ((c = *inp++) == '\n')
189 			break;
190 		if (ap == &newargs[NEWARGS])
191 bad:		  error("Bad #! line");
192 		STARTSTACKSTR(outp);
193 		do {
194 			STPUTC(c, outp);
195 		} while (--n >= 0 && (c = *inp++) != ' ' && c != '\t' && c != '\n');
196 		STPUTC('\0', outp);
197 		n++, inp--;
198 		*ap++ = grabstackstr(outp);
199 	}
200 	if (ap == newargs + 1) {	/* if no args, maybe no exec is needed */
201 		p = newargs[0];
202 		for (;;) {
203 			if (equal(p, "sh") || equal(p, "ash")) {
204 				return;
205 			}
206 			while (*p != '/') {
207 				if (*p == '\0')
208 					goto break2;
209 				p++;
210 			}
211 			p++;
212 		}
213 break2:;
214 	}
215 	i = (char *)ap - (char *)newargs;		/* size in bytes */
216 	if (i == 0)
217 		error("Bad #! line");
218 	for (ap2 = argv ; *ap2++ != NULL ; );
219 	new = ckmalloc(i + ((char *)ap2 - (char *)argv));
220 	ap = newargs, ap2 = new;
221 	while ((i -= sizeof (char **)) >= 0)
222 		*ap2++ = *ap++;
223 	ap = argv;
224 	while (*ap2++ = *ap++);
225 	shellexec(new, envp, pathval(), 0);
226 }
227 #endif
228 
229 
230 
231 /*
232  * Do a path search.  The variable path (passed by reference) should be
233  * set to the start of the path before the first call; padvance will update
234  * this value as it proceeds.  Successive calls to padvance will return
235  * the possible path expansions in sequence.  If an option (indicated by
236  * a percent sign) appears in the path entry then the global variable
237  * pathopt will be set to point to it; otherwise pathopt will be set to
238  * NULL.
239  */
240 
241 char *pathopt;
242 
243 char *
244 padvance(path, name)
245 	char **path;
246 	char *name;
247 	{
248 	register char *p, *q;
249 	char *start;
250 	int len;
251 
252 	if (*path == NULL)
253 		return NULL;
254 	start = *path;
255 	for (p = start ; *p && *p != ':' && *p != '%' ; p++);
256 	len = p - start + strlen(name) + 2;	/* "2" is for '/' and '\0' */
257 	while (stackblocksize() < len)
258 		growstackblock();
259 	q = stackblock();
260 	if (p != start) {
261 		memmove(q, start, p - start);
262 		q += p - start;
263 		*q++ = '/';
264 	}
265 	strcpy(q, name);
266 	pathopt = NULL;
267 	if (*p == '%') {
268 		pathopt = ++p;
269 		while (*p && *p != ':')  p++;
270 	}
271 	if (*p == ':')
272 		*path = p + 1;
273 	else
274 		*path = NULL;
275 	return stalloc(len);
276 }
277 
278 
279 
280 /*** Command hashing code ***/
281 
282 
283 hashcmd(argc, argv)  char **argv; {
284 	struct tblentry **pp;
285 	struct tblentry *cmdp;
286 	int c;
287 	int verbose;
288 	struct cmdentry entry;
289 	char *name;
290 
291 	verbose = 0;
292 	while ((c = nextopt("rv")) != '\0') {
293 		if (c == 'r') {
294 			clearcmdentry(0);
295 		} else if (c == 'v') {
296 			verbose++;
297 		}
298 	}
299 	if (*argptr == NULL) {
300 		for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
301 			for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
302 				printentry(cmdp, verbose);
303 			}
304 		}
305 		return 0;
306 	}
307 	while ((name = *argptr) != NULL) {
308 		if ((cmdp = cmdlookup(name, 0)) != NULL
309 		 && (cmdp->cmdtype == CMDNORMAL
310 		     || cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
311 			delete_cmd_entry();
312 		find_command(name, &entry, 1);
313 		if (verbose) {
314 			if (entry.cmdtype != CMDUNKNOWN) {	/* if no error msg */
315 				cmdp = cmdlookup(name, 0);
316 				printentry(cmdp, verbose);
317 			}
318 			flushall();
319 		}
320 		argptr++;
321 	}
322 	return 0;
323 }
324 
325 
326 STATIC void
327 printentry(cmdp, verbose)
328 	struct tblentry *cmdp;
329 	int verbose;
330 	{
331 	int index;
332 	char *path;
333 	char *name;
334 
335 	if (cmdp->cmdtype == CMDNORMAL) {
336 		index = cmdp->param.index;
337 		path = pathval();
338 		do {
339 			name = padvance(&path, cmdp->cmdname);
340 			stunalloc(name);
341 		} while (--index >= 0);
342 		out1str(name);
343 	} else if (cmdp->cmdtype == CMDBUILTIN) {
344 		out1fmt("builtin %s", cmdp->cmdname);
345 	} else if (cmdp->cmdtype == CMDFUNCTION) {
346 		out1fmt("function %s", cmdp->cmdname);
347 		if (verbose) {
348 			INTOFF;
349 			name = commandtext(cmdp->param.func);
350 			out1c(' ');
351 			out1str(name);
352 			ckfree(name);
353 			INTON;
354 		}
355 #ifdef DEBUG
356 	} else {
357 		error("internal error: cmdtype %d", cmdp->cmdtype);
358 #endif
359 	}
360 	if (cmdp->rehash)
361 		out1c('*');
362 	out1c('\n');
363 }
364 
365 
366 
367 /*
368  * Resolve a command name.  If you change this routine, you may have to
369  * change the shellexec routine as well.
370  */
371 
372 void
373 find_command(name, entry, printerr)
374 	char *name;
375 	struct cmdentry *entry;
376 	{
377 	struct tblentry *cmdp;
378 	int index;
379 	int prev;
380 	char *path;
381 	char *fullname;
382 	struct stat statb;
383 	int e;
384 	int i;
385 
386 	/* If name contains a slash, don't use the hash table */
387 	if (strchr(name, '/') != NULL) {
388 		entry->cmdtype = CMDNORMAL;
389 		entry->u.index = 0;
390 		return;
391 	}
392 
393 	/* If name is in the table, and not invalidated by cd, we're done */
394 	if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0)
395 		goto success;
396 
397 	/* If %builtin not in path, check for builtin next */
398 	if (builtinloc < 0 && (i = find_builtin(name)) >= 0) {
399 		INTOFF;
400 		cmdp = cmdlookup(name, 1);
401 		cmdp->cmdtype = CMDBUILTIN;
402 		cmdp->param.index = i;
403 		INTON;
404 		goto success;
405 	}
406 
407 	/* We have to search path. */
408 	prev = -1;		/* where to start */
409 	if (cmdp) {		/* doing a rehash */
410 		if (cmdp->cmdtype == CMDBUILTIN)
411 			prev = builtinloc;
412 		else
413 			prev = cmdp->param.index;
414 	}
415 
416 	path = pathval();
417 	e = ENOENT;
418 	index = -1;
419 loop:
420 	while ((fullname = padvance(&path, name)) != NULL) {
421 		stunalloc(fullname);
422 		index++;
423 		if (pathopt) {
424 			if (prefix("builtin", pathopt)) {
425 				if ((i = find_builtin(name)) < 0)
426 					goto loop;
427 				INTOFF;
428 				cmdp = cmdlookup(name, 1);
429 				cmdp->cmdtype = CMDBUILTIN;
430 				cmdp->param.index = i;
431 				INTON;
432 				goto success;
433 			} else if (prefix("func", pathopt)) {
434 				/* handled below */
435 			} else {
436 				goto loop;	/* ignore unimplemented options */
437 			}
438 		}
439 		/* if rehash, don't redo absolute path names */
440 		if (fullname[0] == '/' && index <= prev) {
441 			if (index < prev)
442 				goto loop;
443 			TRACE(("searchexec \"%s\": no change\n", name));
444 			goto success;
445 		}
446 		while (stat(fullname, &statb) < 0) {
447 #ifdef SYSV
448 			if (errno == EINTR)
449 				continue;
450 #endif
451 			if (errno != ENOENT && errno != ENOTDIR)
452 				e = errno;
453 			goto loop;
454 		}
455 		e = EACCES;	/* if we fail, this will be the error */
456 		if ((statb.st_mode & S_IFMT) != S_IFREG)
457 			goto loop;
458 		if (pathopt) {		/* this is a %func directory */
459 			stalloc(strlen(fullname) + 1);
460 			readcmdfile(fullname);
461 			if ((cmdp = cmdlookup(name, 0)) == NULL || cmdp->cmdtype != CMDFUNCTION)
462 				error("%s not defined in %s", name, fullname);
463 			stunalloc(fullname);
464 			goto success;
465 		}
466 #ifdef notdef
467 		if (statb.st_uid == geteuid()) {
468 			if ((statb.st_mode & 0100) == 0)
469 				goto loop;
470 		} else if (statb.st_gid == getegid()) {
471 			if ((statb.st_mode & 010) == 0)
472 				goto loop;
473 		} else {
474 			if ((statb.st_mode & 01) == 0)
475 				goto loop;
476 		}
477 #endif
478 		TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
479 		INTOFF;
480 		cmdp = cmdlookup(name, 1);
481 		cmdp->cmdtype = CMDNORMAL;
482 		cmdp->param.index = index;
483 		INTON;
484 		goto success;
485 	}
486 
487 	/* We failed.  If there was an entry for this command, delete it */
488 	if (cmdp)
489 		delete_cmd_entry();
490 	if (printerr)
491 		outfmt(out2, "%s: %s\n", name, errmsg(e, E_EXEC));
492 	entry->cmdtype = CMDUNKNOWN;
493 	return;
494 
495 success:
496 	cmdp->rehash = 0;
497 	entry->cmdtype = cmdp->cmdtype;
498 	entry->u = cmdp->param;
499 }
500 
501 
502 
503 /*
504  * Search the table of builtin commands.
505  */
506 
507 int
508 find_builtin(name)
509 	char *name;
510 	{
511 	const register struct builtincmd *bp;
512 
513 	for (bp = builtincmd ; bp->name ; bp++) {
514 		if (*bp->name == *name && equal(bp->name, name))
515 			return bp->code;
516 	}
517 	return -1;
518 }
519 
520 
521 
522 /*
523  * Called when a cd is done.  Marks all commands so the next time they
524  * are executed they will be rehashed.
525  */
526 
527 void
528 hashcd() {
529 	struct tblentry **pp;
530 	struct tblentry *cmdp;
531 
532 	for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
533 		for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
534 			if (cmdp->cmdtype == CMDNORMAL
535 			 || cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)
536 				cmdp->rehash = 1;
537 		}
538 	}
539 }
540 
541 
542 
543 /*
544  * Called before PATH is changed.  The argument is the new value of PATH;
545  * pathval() still returns the old value at this point.  Called with
546  * interrupts off.
547  */
548 
549 void
550 changepath(newval)
551 	char *newval;
552 	{
553 	char *old, *new;
554 	int index;
555 	int firstchange;
556 	int bltin;
557 	int hasdot;
558 
559 	old = pathval();
560 	new = newval;
561 	firstchange = 9999;	/* assume no change */
562 	index = hasdot = 0;
563 	bltin = -1;
564 	if (*new == ':')
565 		hasdot++;
566 	for (;;) {
567 		if (*old != *new) {
568 			firstchange = index;
569 			if (*old == '\0' && *new == ':'
570 			 || *old == ':' && *new == '\0')
571 				firstchange++;
572 			old = new;	/* ignore subsequent differences */
573 		}
574 		if (*new == '\0')
575 			break;
576 		if (*new == '%' && bltin < 0 && prefix("builtin", new + 1))
577 			bltin = index;
578 		if (*new == ':') {
579 			char c = *(new+1);
580 
581 			index++;
582 			if (c == ':' || c == '\0' || (c == '.' &&
583 			   ((c = *(new+2)) == ':' || c == '\0')))
584 				hasdot++;
585 		}
586 		new++, old++;
587 	}
588 	if (hasdot && geteuid() == 0)
589 		out2str("sh: warning: running as root with dot in PATH\n");
590 	if (builtinloc < 0 && bltin >= 0)
591 		builtinloc = bltin;		/* zap builtins */
592 	if (builtinloc >= 0 && bltin < 0)
593 		firstchange = 0;
594 	clearcmdentry(firstchange);
595 	builtinloc = bltin;
596 }
597 
598 
599 /*
600  * Clear out command entries.  The argument specifies the first entry in
601  * PATH which has changed.
602  */
603 
604 STATIC void
605 clearcmdentry(firstchange) {
606 	struct tblentry **tblp;
607 	struct tblentry **pp;
608 	struct tblentry *cmdp;
609 
610 	INTOFF;
611 	for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
612 		pp = tblp;
613 		while ((cmdp = *pp) != NULL) {
614 			if (cmdp->cmdtype == CMDNORMAL && cmdp->param.index >= firstchange
615 			 || cmdp->cmdtype == CMDBUILTIN && builtinloc >= firstchange) {
616 				*pp = cmdp->next;
617 				ckfree(cmdp);
618 			} else {
619 				pp = &cmdp->next;
620 			}
621 		}
622 	}
623 	INTON;
624 }
625 
626 
627 /*
628  * Delete all functions.
629  */
630 
631 #ifdef mkinit
632 MKINIT void deletefuncs();
633 
634 SHELLPROC {
635 	deletefuncs();
636 }
637 #endif
638 
639 void
640 deletefuncs() {
641 	struct tblentry **tblp;
642 	struct tblentry **pp;
643 	struct tblentry *cmdp;
644 
645 	INTOFF;
646 	for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
647 		pp = tblp;
648 		while ((cmdp = *pp) != NULL) {
649 			if (cmdp->cmdtype == CMDFUNCTION) {
650 				*pp = cmdp->next;
651 				freefunc(cmdp->param.func);
652 				ckfree(cmdp);
653 			} else {
654 				pp = &cmdp->next;
655 			}
656 		}
657 	}
658 	INTON;
659 }
660 
661 
662 
663 /*
664  * Locate a command in the command hash table.  If "add" is nonzero,
665  * add the command to the table if it is not already present.  The
666  * variable "lastcmdentry" is set to point to the address of the link
667  * pointing to the entry, so that delete_cmd_entry can delete the
668  * entry.
669  */
670 
671 struct tblentry **lastcmdentry;
672 
673 
674 STATIC struct tblentry *
675 cmdlookup(name, add)
676 	char *name;
677 	{
678 	int hashval;
679 	register char *p;
680 	struct tblentry *cmdp;
681 	struct tblentry **pp;
682 
683 	p = name;
684 	hashval = *p << 4;
685 	while (*p)
686 		hashval += *p++;
687 	hashval &= 0x7FFF;
688 	pp = &cmdtable[hashval % CMDTABLESIZE];
689 	for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
690 		if (equal(cmdp->cmdname, name))
691 			break;
692 		pp = &cmdp->next;
693 	}
694 	if (add && cmdp == NULL) {
695 		INTOFF;
696 		cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
697 					+ strlen(name) + 1);
698 		cmdp->next = NULL;
699 		cmdp->cmdtype = CMDUNKNOWN;
700 		cmdp->rehash = 0;
701 		strcpy(cmdp->cmdname, name);
702 		INTON;
703 	}
704 	lastcmdentry = pp;
705 	return cmdp;
706 }
707 
708 /*
709  * Delete the command entry returned on the last lookup.
710  */
711 
712 STATIC void
713 delete_cmd_entry() {
714 	struct tblentry *cmdp;
715 
716 	INTOFF;
717 	cmdp = *lastcmdentry;
718 	*lastcmdentry = cmdp->next;
719 	ckfree(cmdp);
720 	INTON;
721 }
722 
723 
724 
725 #ifdef notdef
726 void
727 getcmdentry(name, entry)
728 	char *name;
729 	struct cmdentry *entry;
730 	{
731 	struct tblentry *cmdp = cmdlookup(name, 0);
732 
733 	if (cmdp) {
734 		entry->u = cmdp->param;
735 		entry->cmdtype = cmdp->cmdtype;
736 	} else {
737 		entry->cmdtype = CMDUNKNOWN;
738 		entry->u.index = 0;
739 	}
740 }
741 #endif
742 
743 
744 /*
745  * Add a new command entry, replacing any existing command entry for
746  * the same name.
747  */
748 
749 void
750 addcmdentry(name, entry)
751 	char *name;
752 	struct cmdentry *entry;
753 	{
754 	struct tblentry *cmdp;
755 
756 	INTOFF;
757 	cmdp = cmdlookup(name, 1);
758 	if (cmdp->cmdtype == CMDFUNCTION) {
759 		freefunc(cmdp->param.func);
760 	}
761 	cmdp->cmdtype = entry->cmdtype;
762 	cmdp->param = entry->u;
763 	INTON;
764 }
765 
766 
767 /*
768  * Define a shell function.
769  */
770 
771 void
772 defun(name, func)
773 	char *name;
774 	union node *func;
775 	{
776 	struct cmdentry entry;
777 
778 	INTOFF;
779 	entry.cmdtype = CMDFUNCTION;
780 	entry.u.func = copyfunc(func);
781 	addcmdentry(name, &entry);
782 	INTON;
783 }
784 
785 
786 /*
787  * Delete a function if it exists.
788  */
789 
790 int
791 unsetfunc(name)
792 	char *name;
793 	{
794 	struct tblentry *cmdp;
795 
796 	if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) {
797 		freefunc(cmdp->param.func);
798 		delete_cmd_entry();
799 		return (0);
800 	}
801 	return (1);
802 }
803