exec.c revision 264629
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 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 4. Neither the name of the University nor the names of its contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#ifndef lint
34#if 0
35static char sccsid[] = "@(#)exec.c	8.4 (Berkeley) 6/8/95";
36#endif
37#endif /* not lint */
38#include <sys/cdefs.h>
39__FBSDID("$FreeBSD: stable/9/bin/sh/exec.c 264629 2014-04-17 21:43:34Z jilles $");
40
41#include <sys/types.h>
42#include <sys/stat.h>
43#include <unistd.h>
44#include <fcntl.h>
45#include <errno.h>
46#include <paths.h>
47#include <stdlib.h>
48
49/*
50 * When commands are first encountered, they are entered in a hash table.
51 * This ensures that a full path search will not have to be done for them
52 * on each invocation.
53 *
54 * We should investigate converting to a linear search, even though that
55 * would make the command name "hash" a misnomer.
56 */
57
58#include "shell.h"
59#include "main.h"
60#include "nodes.h"
61#include "parser.h"
62#include "redir.h"
63#include "eval.h"
64#include "exec.h"
65#include "builtins.h"
66#include "var.h"
67#include "options.h"
68#include "input.h"
69#include "output.h"
70#include "syntax.h"
71#include "memalloc.h"
72#include "error.h"
73#include "init.h"
74#include "mystring.h"
75#include "show.h"
76#include "jobs.h"
77#include "alias.h"
78
79
80#define CMDTABLESIZE 31		/* should be prime */
81#define ARB 1			/* actual size determined at run time */
82
83
84
85struct tblentry {
86	struct tblentry *next;	/* next entry in hash chain */
87	union param param;	/* definition of builtin function */
88	int special;		/* flag for special builtin commands */
89	short cmdtype;		/* index identifying command */
90	char rehash;		/* if set, cd done since entry created */
91	char cmdname[ARB];	/* name of command */
92};
93
94
95static struct tblentry *cmdtable[CMDTABLESIZE];
96int exerrno = 0;			/* Last exec error */
97
98
99static void tryexec(char *, char **, char **);
100static void printentry(struct tblentry *, int);
101static struct tblentry *cmdlookup(const char *, int);
102static void delete_cmd_entry(void);
103static void addcmdentry(const char *, struct cmdentry *);
104
105
106
107/*
108 * Exec a program.  Never returns.  If you change this routine, you may
109 * have to change the find_command routine as well.
110 *
111 * The argv array may be changed and element argv[-1] should be writable.
112 */
113
114void
115shellexec(char **argv, char **envp, const char *path, int idx)
116{
117	char *cmdname;
118	int e;
119
120	if (strchr(argv[0], '/') != NULL) {
121		tryexec(argv[0], argv, envp);
122		e = errno;
123	} else {
124		e = ENOENT;
125		while ((cmdname = padvance(&path, argv[0])) != NULL) {
126			if (--idx < 0 && pathopt == NULL) {
127				tryexec(cmdname, argv, envp);
128				if (errno != ENOENT && errno != ENOTDIR)
129					e = errno;
130				if (e == ENOEXEC)
131					break;
132			}
133			stunalloc(cmdname);
134		}
135	}
136
137	/* Map to POSIX errors */
138	if (e == ENOENT || e == ENOTDIR) {
139		exerrno = 127;
140		exerror(EXEXEC, "%s: not found", argv[0]);
141	} else {
142		exerrno = 126;
143		exerror(EXEXEC, "%s: %s", argv[0], strerror(e));
144	}
145}
146
147
148static void
149tryexec(char *cmd, char **argv, char **envp)
150{
151	int e, in;
152	ssize_t n;
153	char buf[256];
154
155	execve(cmd, argv, envp);
156	e = errno;
157	if (e == ENOEXEC) {
158		INTOFF;
159		in = open(cmd, O_RDONLY | O_NONBLOCK);
160		if (in != -1) {
161			n = pread(in, buf, sizeof buf, 0);
162			close(in);
163			if (n > 0 && memchr(buf, '\0', n) != NULL) {
164				errno = ENOEXEC;
165				return;
166			}
167		}
168		*argv = cmd;
169		*--argv = _PATH_BSHELL;
170		execve(_PATH_BSHELL, argv, envp);
171	}
172	errno = e;
173}
174
175/*
176 * Do a path search.  The variable path (passed by reference) should be
177 * set to the start of the path before the first call; padvance will update
178 * this value as it proceeds.  Successive calls to padvance will return
179 * the possible path expansions in sequence.  If an option (indicated by
180 * a percent sign) appears in the path entry then the global variable
181 * pathopt will be set to point to it; otherwise pathopt will be set to
182 * NULL.
183 */
184
185const char *pathopt;
186
187char *
188padvance(const char **path, const char *name)
189{
190	const char *p, *start;
191	char *q;
192	int len;
193
194	if (*path == NULL)
195		return NULL;
196	start = *path;
197	for (p = start; *p && *p != ':' && *p != '%'; p++)
198		; /* nothing */
199	len = p - start + strlen(name) + 2;	/* "2" is for '/' and '\0' */
200	STARTSTACKSTR(q);
201	CHECKSTRSPACE(len, q);
202	if (p != start) {
203		memcpy(q, start, p - start);
204		q += p - start;
205		*q++ = '/';
206	}
207	strcpy(q, name);
208	pathopt = NULL;
209	if (*p == '%') {
210		pathopt = ++p;
211		while (*p && *p != ':')  p++;
212	}
213	if (*p == ':')
214		*path = p + 1;
215	else
216		*path = NULL;
217	return stalloc(len);
218}
219
220
221
222/*** Command hashing code ***/
223
224
225int
226hashcmd(int argc __unused, char **argv __unused)
227{
228	struct tblentry **pp;
229	struct tblentry *cmdp;
230	int c;
231	int verbose;
232	struct cmdentry entry;
233	char *name;
234
235	verbose = 0;
236	while ((c = nextopt("rv")) != '\0') {
237		if (c == 'r') {
238			clearcmdentry();
239		} else if (c == 'v') {
240			verbose++;
241		}
242	}
243	if (*argptr == NULL) {
244		for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
245			for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
246				if (cmdp->cmdtype == CMDNORMAL)
247					printentry(cmdp, verbose);
248			}
249		}
250		return 0;
251	}
252	while ((name = *argptr) != NULL) {
253		if ((cmdp = cmdlookup(name, 0)) != NULL
254		 && cmdp->cmdtype == CMDNORMAL)
255			delete_cmd_entry();
256		find_command(name, &entry, DO_ERR, pathval());
257		if (verbose) {
258			if (entry.cmdtype != CMDUNKNOWN) {	/* if no error msg */
259				cmdp = cmdlookup(name, 0);
260				if (cmdp != NULL)
261					printentry(cmdp, verbose);
262				else
263					outfmt(out2, "%s: not found\n", name);
264			}
265			flushall();
266		}
267		argptr++;
268	}
269	return 0;
270}
271
272
273static void
274printentry(struct tblentry *cmdp, int verbose)
275{
276	int idx;
277	const char *path;
278	char *name;
279
280	if (cmdp->cmdtype == CMDNORMAL) {
281		idx = cmdp->param.index;
282		path = pathval();
283		do {
284			name = padvance(&path, cmdp->cmdname);
285			stunalloc(name);
286		} while (--idx >= 0);
287		out1str(name);
288	} else if (cmdp->cmdtype == CMDBUILTIN) {
289		out1fmt("builtin %s", cmdp->cmdname);
290	} else if (cmdp->cmdtype == CMDFUNCTION) {
291		out1fmt("function %s", cmdp->cmdname);
292		if (verbose) {
293			INTOFF;
294			name = commandtext(getfuncnode(cmdp->param.func));
295			out1c(' ');
296			out1str(name);
297			ckfree(name);
298			INTON;
299		}
300#ifdef DEBUG
301	} else {
302		error("internal error: cmdtype %d", cmdp->cmdtype);
303#endif
304	}
305	if (cmdp->rehash)
306		out1c('*');
307	out1c('\n');
308}
309
310
311
312/*
313 * Resolve a command name.  If you change this routine, you may have to
314 * change the shellexec routine as well.
315 */
316
317void
318find_command(const char *name, struct cmdentry *entry, int act,
319    const char *path)
320{
321	struct tblentry *cmdp, loc_cmd;
322	int idx;
323	int prev;
324	char *fullname;
325	struct stat statb;
326	int e;
327	int i;
328	int spec;
329
330	/* If name contains a slash, don't use the hash table */
331	if (strchr(name, '/') != NULL) {
332		entry->cmdtype = CMDNORMAL;
333		entry->u.index = 0;
334		return;
335	}
336
337	/* If name is in the table, and not invalidated by cd, we're done */
338	if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0) {
339		if (cmdp->cmdtype == CMDFUNCTION && act & DO_NOFUNC)
340			cmdp = NULL;
341		else
342			goto success;
343	}
344
345	/* Check for builtin next */
346	if ((i = find_builtin(name, &spec)) >= 0) {
347		INTOFF;
348		cmdp = cmdlookup(name, 1);
349		if (cmdp->cmdtype == CMDFUNCTION)
350			cmdp = &loc_cmd;
351		cmdp->cmdtype = CMDBUILTIN;
352		cmdp->param.index = i;
353		cmdp->special = spec;
354		INTON;
355		goto success;
356	}
357
358	/* We have to search path. */
359	prev = -1;		/* where to start */
360	if (cmdp) {		/* doing a rehash */
361		if (cmdp->cmdtype == CMDBUILTIN)
362			prev = -1;
363		else
364			prev = cmdp->param.index;
365	}
366
367	e = ENOENT;
368	idx = -1;
369loop:
370	while ((fullname = padvance(&path, name)) != NULL) {
371		stunalloc(fullname);
372		idx++;
373		if (pathopt) {
374			if (prefix("func", pathopt)) {
375				/* handled below */
376			} else {
377				goto loop;	/* ignore unimplemented options */
378			}
379		}
380		/* if rehash, don't redo absolute path names */
381		if (fullname[0] == '/' && idx <= prev) {
382			if (idx < prev)
383				goto loop;
384			TRACE(("searchexec \"%s\": no change\n", name));
385			goto success;
386		}
387		if (stat(fullname, &statb) < 0) {
388			if (errno != ENOENT && errno != ENOTDIR)
389				e = errno;
390			goto loop;
391		}
392		e = EACCES;	/* if we fail, this will be the error */
393		if (!S_ISREG(statb.st_mode))
394			goto loop;
395		if (pathopt) {		/* this is a %func directory */
396			stalloc(strlen(fullname) + 1);
397			readcmdfile(fullname);
398			if ((cmdp = cmdlookup(name, 0)) == NULL || cmdp->cmdtype != CMDFUNCTION)
399				error("%s not defined in %s", name, fullname);
400			stunalloc(fullname);
401			goto success;
402		}
403#ifdef notdef
404		if (statb.st_uid == geteuid()) {
405			if ((statb.st_mode & 0100) == 0)
406				goto loop;
407		} else if (statb.st_gid == getegid()) {
408			if ((statb.st_mode & 010) == 0)
409				goto loop;
410		} else {
411			if ((statb.st_mode & 01) == 0)
412				goto loop;
413		}
414#endif
415		TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
416		INTOFF;
417		cmdp = cmdlookup(name, 1);
418		if (cmdp->cmdtype == CMDFUNCTION)
419			cmdp = &loc_cmd;
420		cmdp->cmdtype = CMDNORMAL;
421		cmdp->param.index = idx;
422		INTON;
423		goto success;
424	}
425
426	/* We failed.  If there was an entry for this command, delete it */
427	if (cmdp && cmdp->cmdtype != CMDFUNCTION)
428		delete_cmd_entry();
429	if (act & DO_ERR) {
430		if (e == ENOENT || e == ENOTDIR)
431			outfmt(out2, "%s: not found\n", name);
432		else
433			outfmt(out2, "%s: %s\n", name, strerror(e));
434	}
435	entry->cmdtype = CMDUNKNOWN;
436	entry->u.index = 0;
437	return;
438
439success:
440	cmdp->rehash = 0;
441	entry->cmdtype = cmdp->cmdtype;
442	entry->u = cmdp->param;
443	entry->special = cmdp->special;
444}
445
446
447
448/*
449 * Search the table of builtin commands.
450 */
451
452int
453find_builtin(const char *name, int *special)
454{
455	const struct builtincmd *bp;
456
457	for (bp = builtincmd ; bp->name ; bp++) {
458		if (*bp->name == *name && equal(bp->name, name)) {
459			*special = bp->special;
460			return bp->code;
461		}
462	}
463	return -1;
464}
465
466
467
468/*
469 * Called when a cd is done.  Marks all commands so the next time they
470 * are executed they will be rehashed.
471 */
472
473void
474hashcd(void)
475{
476	struct tblentry **pp;
477	struct tblentry *cmdp;
478
479	for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
480		for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
481			if (cmdp->cmdtype == CMDNORMAL)
482				cmdp->rehash = 1;
483		}
484	}
485}
486
487
488
489/*
490 * Called before PATH is changed.  The argument is the new value of PATH;
491 * pathval() still returns the old value at this point.  Called with
492 * interrupts off.
493 */
494
495void
496changepath(const char *newval)
497{
498	clearcmdentry();
499}
500
501
502/*
503 * Clear out command entries.  The argument specifies the first entry in
504 * PATH which has changed.
505 */
506
507void
508clearcmdentry(void)
509{
510	struct tblentry **tblp;
511	struct tblentry **pp;
512	struct tblentry *cmdp;
513
514	INTOFF;
515	for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
516		pp = tblp;
517		while ((cmdp = *pp) != NULL) {
518			if (cmdp->cmdtype == CMDNORMAL) {
519				*pp = cmdp->next;
520				ckfree(cmdp);
521			} else {
522				pp = &cmdp->next;
523			}
524		}
525	}
526	INTON;
527}
528
529
530/*
531 * Locate a command in the command hash table.  If "add" is nonzero,
532 * add the command to the table if it is not already present.  The
533 * variable "lastcmdentry" is set to point to the address of the link
534 * pointing to the entry, so that delete_cmd_entry can delete the
535 * entry.
536 */
537
538static struct tblentry **lastcmdentry;
539
540
541static struct tblentry *
542cmdlookup(const char *name, int add)
543{
544	int hashval;
545	const char *p;
546	struct tblentry *cmdp;
547	struct tblentry **pp;
548
549	p = name;
550	hashval = *p << 4;
551	while (*p)
552		hashval += *p++;
553	hashval &= 0x7FFF;
554	pp = &cmdtable[hashval % CMDTABLESIZE];
555	for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
556		if (equal(cmdp->cmdname, name))
557			break;
558		pp = &cmdp->next;
559	}
560	if (add && cmdp == NULL) {
561		INTOFF;
562		cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
563					+ strlen(name) + 1);
564		cmdp->next = NULL;
565		cmdp->cmdtype = CMDUNKNOWN;
566		cmdp->rehash = 0;
567		strcpy(cmdp->cmdname, name);
568		INTON;
569	}
570	lastcmdentry = pp;
571	return cmdp;
572}
573
574/*
575 * Delete the command entry returned on the last lookup.
576 */
577
578static void
579delete_cmd_entry(void)
580{
581	struct tblentry *cmdp;
582
583	INTOFF;
584	cmdp = *lastcmdentry;
585	*lastcmdentry = cmdp->next;
586	ckfree(cmdp);
587	INTON;
588}
589
590
591
592/*
593 * Add a new command entry, replacing any existing command entry for
594 * the same name.
595 */
596
597static void
598addcmdentry(const char *name, struct cmdentry *entry)
599{
600	struct tblentry *cmdp;
601
602	INTOFF;
603	cmdp = cmdlookup(name, 1);
604	if (cmdp->cmdtype == CMDFUNCTION) {
605		unreffunc(cmdp->param.func);
606	}
607	cmdp->cmdtype = entry->cmdtype;
608	cmdp->param = entry->u;
609	INTON;
610}
611
612
613/*
614 * Define a shell function.
615 */
616
617void
618defun(const char *name, union node *func)
619{
620	struct cmdentry entry;
621
622	INTOFF;
623	entry.cmdtype = CMDFUNCTION;
624	entry.u.func = copyfunc(func);
625	addcmdentry(name, &entry);
626	INTON;
627}
628
629
630/*
631 * Delete a function if it exists.
632 * Called with interrupts off.
633 */
634
635int
636unsetfunc(const char *name)
637{
638	struct tblentry *cmdp;
639
640	if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) {
641		unreffunc(cmdp->param.func);
642		delete_cmd_entry();
643		return (0);
644	}
645	return (0);
646}
647
648
649/*
650 * Check if a function by a certain name exists.
651 */
652int
653isfunc(const char *name)
654{
655	struct tblentry *cmdp;
656	cmdp = cmdlookup(name, 0);
657	return (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION);
658}
659
660
661/*
662 * Shared code for the following builtin commands:
663 *    type, command -v, command -V
664 */
665
666int
667typecmd_impl(int argc, char **argv, int cmd, const char *path)
668{
669	struct cmdentry entry;
670	struct tblentry *cmdp;
671	const char *const *pp;
672	struct alias *ap;
673	int i;
674	int error1 = 0;
675
676	if (path != pathval())
677		clearcmdentry();
678
679	for (i = 1; i < argc; i++) {
680		/* First look at the keywords */
681		for (pp = parsekwd; *pp; pp++)
682			if (**pp == *argv[i] && equal(*pp, argv[i]))
683				break;
684
685		if (*pp) {
686			if (cmd == TYPECMD_SMALLV)
687				out1fmt("%s\n", argv[i]);
688			else
689				out1fmt("%s is a shell keyword\n", argv[i]);
690			continue;
691		}
692
693		/* Then look at the aliases */
694		if ((ap = lookupalias(argv[i], 1)) != NULL) {
695			if (cmd == TYPECMD_SMALLV)
696				out1fmt("alias %s='%s'\n", argv[i], ap->val);
697			else
698				out1fmt("%s is an alias for %s\n", argv[i],
699				    ap->val);
700			continue;
701		}
702
703		/* Then check if it is a tracked alias */
704		if ((cmdp = cmdlookup(argv[i], 0)) != NULL) {
705			entry.cmdtype = cmdp->cmdtype;
706			entry.u = cmdp->param;
707			entry.special = cmdp->special;
708		}
709		else {
710			/* Finally use brute force */
711			find_command(argv[i], &entry, 0, path);
712		}
713
714		switch (entry.cmdtype) {
715		case CMDNORMAL: {
716			if (strchr(argv[i], '/') == NULL) {
717				const char *path2 = path;
718				char *name;
719				int j = entry.u.index;
720				do {
721					name = padvance(&path2, argv[i]);
722					stunalloc(name);
723				} while (--j >= 0);
724				if (cmd == TYPECMD_SMALLV)
725					out1fmt("%s\n", name);
726				else
727					out1fmt("%s is%s %s\n", argv[i],
728					    (cmdp && cmd == TYPECMD_TYPE) ?
729						" a tracked alias for" : "",
730					    name);
731			} else {
732				if (eaccess(argv[i], X_OK) == 0) {
733					if (cmd == TYPECMD_SMALLV)
734						out1fmt("%s\n", argv[i]);
735					else
736						out1fmt("%s is %s\n", argv[i],
737						    argv[i]);
738				} else {
739					if (cmd != TYPECMD_SMALLV)
740						outfmt(out2, "%s: %s\n",
741						    argv[i], strerror(errno));
742					error1 |= 127;
743				}
744			}
745			break;
746		}
747		case CMDFUNCTION:
748			if (cmd == TYPECMD_SMALLV)
749				out1fmt("%s\n", argv[i]);
750			else
751				out1fmt("%s is a shell function\n", argv[i]);
752			break;
753
754		case CMDBUILTIN:
755			if (cmd == TYPECMD_SMALLV)
756				out1fmt("%s\n", argv[i]);
757			else if (entry.special)
758				out1fmt("%s is a special shell builtin\n",
759				    argv[i]);
760			else
761				out1fmt("%s is a shell builtin\n", argv[i]);
762			break;
763
764		default:
765			if (cmd != TYPECMD_SMALLV)
766				outfmt(out2, "%s: not found\n", argv[i]);
767			error1 |= 127;
768			break;
769		}
770	}
771
772	if (path != pathval())
773		clearcmdentry();
774
775	return error1;
776}
777
778/*
779 * Locate and print what a word is...
780 */
781
782int
783typecmd(int argc, char **argv)
784{
785	return typecmd_impl(argc, argv, TYPECMD_TYPE, bltinlookup("PATH", 1));
786}
787