xref: /csrg-svn/lib/libc/gen/exec.c (revision 46592)
1*46592Sbostic /*-
2*46592Sbostic  * Copyright (c) 1991 The Regents of the University of California.
3*46592Sbostic  * All rights reserved.
4*46592Sbostic  *
5*46592Sbostic  * %sccs.include.redist.c%
6*46592Sbostic  */
7*46592Sbostic 
826549Sdonn #if defined(LIBC_SCCS) && !defined(lint)
9*46592Sbostic static char sccsid[] = "@(#)exec.c	5.5 (Berkeley) 02/23/91";
10*46592Sbostic #endif /* LIBC_SCCS and not lint */
1122086Smckusick 
12*46592Sbostic #include <sys/param.h>
13*46592Sbostic #include <sys/types.h>
141965Swnj #include <errno.h>
15*46592Sbostic #include <unistd.h>
1646572Sdonn #include <stdlib.h>
17*46592Sbostic #include <stdarg.h>
1846572Sdonn #include <string.h>
19*46592Sbostic #include <stdio.h>
20*46592Sbostic #include <paths.h>
211965Swnj 
22*46592Sbostic extern char **environ;
231965Swnj 
24*46592Sbostic static char **buildargv(va_list ap, const char *arg, char ***envpp)
251965Swnj {
26*46592Sbostic 	register size_t max, off;
27*46592Sbostic 	register char **argv;
28*46592Sbostic 
29*46592Sbostic 	for (off = max = 0;; ++off) {
30*46592Sbostic 		if (off >= max) {
31*46592Sbostic 			max += 50;	/* Starts out at 0. */
32*46592Sbostic 			max *= 2;	/* Ramp up fast. */
33*46592Sbostic 			if (!(argv = realloc(argv, max * sizeof(char *))))
34*46592Sbostic 				return(NULL);
35*46592Sbostic 			if (off == 0) {
36*46592Sbostic 				argv[0] = (char *)arg;
37*46592Sbostic 				off = 1;
38*46592Sbostic 			}
39*46592Sbostic 		}
40*46592Sbostic 		if (!(argv[off] = va_arg(ap, char *)))
41*46592Sbostic 			break;
42*46592Sbostic 	}
43*46592Sbostic 	/* Get environment pointer if need user supposed to provide one. */
44*46592Sbostic 	if (envpp)
45*46592Sbostic 		*envpp = va_arg(ap, char **);
46*46592Sbostic 	return(argv);
471965Swnj }
481965Swnj 
49*46592Sbostic int execl(const char *name, const char *arg, ...)
501965Swnj {
51*46592Sbostic 	va_list ap;
52*46592Sbostic 	int sverrno;
53*46592Sbostic 	char **argv;
541965Swnj 
55*46592Sbostic 	va_start(ap, arg);
56*46592Sbostic 	if (argv = buildargv(ap, arg, (char ***)NULL))
57*46592Sbostic 		(void)execve(name, argv, environ);
58*46592Sbostic 	va_end(ap);
59*46592Sbostic 	sverrno = errno;
60*46592Sbostic 	free(argv);
61*46592Sbostic 	errno = sverrno;
62*46592Sbostic 	return(-1);
63*46592Sbostic }
641965Swnj 
65*46592Sbostic int execle(const char *name, const char *arg, ...)
66*46592Sbostic {
67*46592Sbostic 	va_list ap;
68*46592Sbostic 	int sverrno;
69*46592Sbostic 	char **argv, **envp;
70*46592Sbostic 
71*46592Sbostic 	va_start(ap, arg);
72*46592Sbostic 	if (argv = buildargv(ap, arg, &envp))
73*46592Sbostic 		(void)execve(name, argv, envp);
74*46592Sbostic 	va_end(ap);
75*46592Sbostic 	sverrno = errno;
76*46592Sbostic 	free(argv);
77*46592Sbostic 	errno = sverrno;
78*46592Sbostic 	return(-1);
79*46592Sbostic }
80*46592Sbostic 
81*46592Sbostic int execlp(const char *name, const char *arg, ...)
82*46592Sbostic {
83*46592Sbostic 	va_list ap;
84*46592Sbostic 	int sverrno;
85*46592Sbostic 	char **argv;
86*46592Sbostic 
87*46592Sbostic 	va_start(ap, arg);
88*46592Sbostic 	if (argv = buildargv(ap, arg, (char ***)NULL))
89*46592Sbostic 		(void)execvp(name, argv);
90*46592Sbostic 	va_end(ap);
91*46592Sbostic 	sverrno = errno;
92*46592Sbostic 	free(argv);
93*46592Sbostic 	errno = sverrno;
94*46592Sbostic 	return(-1);
95*46592Sbostic }
96*46592Sbostic 
97*46592Sbostic int execv(const char *name, char * const *argv)
98*46592Sbostic {
99*46592Sbostic 	(void)execve(name, argv, environ);
100*46592Sbostic 	return(-1);
101*46592Sbostic }
102*46592Sbostic 
103*46592Sbostic int execvp(const char *name, char * const *argv)
104*46592Sbostic {
105*46592Sbostic 	register char *p;
106*46592Sbostic 	int eacces, etxtbsy;
107*46592Sbostic 	char *cur, *path, buf[MAXPATHLEN];
108*46592Sbostic 
109*46592Sbostic 	/* If it's an absolute or relative path name, it's easy. */
110*46592Sbostic 	if (index(name, '/')) {
111*46592Sbostic 		(void)execve(name, argv, environ);
112*46592Sbostic 		return(-1);
113*46592Sbostic 	}
114*46592Sbostic 
115*46592Sbostic 	/* Get the path we're searching. */
116*46592Sbostic 	if (!(path = getenv("PATH")))
117*46592Sbostic 		path = _PATH_DEFPATH;
118*46592Sbostic 	cur = path = strdup(path);
119*46592Sbostic 
120*46592Sbostic 	eacces = etxtbsy = 0;
121*46592Sbostic 	while (p = strsep(&cur, ":")) {
122*46592Sbostic 		/*
123*46592Sbostic 		 * It's a SHELL path -- double, leading and trailing colons
124*46592Sbostic 		 * mean the current directory.
125*46592Sbostic 		 */
126*46592Sbostic 		if (!*p)
127*46592Sbostic 			p = ".";
128*46592Sbostic 		(void)snprintf(buf, sizeof(buf), "%s/%s", p, name);
129*46592Sbostic 
130*46592Sbostic retry:		(void)execve(buf, argv, environ);
1311965Swnj 		switch(errno) {
132*46592Sbostic 		case EACCES:
133*46592Sbostic 			eacces = 1;
134*46592Sbostic 			break;
135*46592Sbostic 		case ENOENT:
136*46592Sbostic 			break;
137*46592Sbostic 		case ENOEXEC: {
138*46592Sbostic 			register size_t cnt;
139*46592Sbostic 			register char **ap;
140*46592Sbostic 
141*46592Sbostic 			for (cnt = 0, ap = (char **)argv; *ap; ++ap, ++cnt);
142*46592Sbostic 			if (ap = malloc((cnt + 2) * sizeof(char *))) {
143*46592Sbostic 				bcopy(argv, ap + 2, cnt * sizeof(char *));
144*46592Sbostic 				ap[0] = "sh";
145*46592Sbostic 				ap[1] = buf;
146*46592Sbostic 				(void)execve(_PATH_BSHELL, ap, environ);
147*46592Sbostic 				free(ap);
1481965Swnj 			}
149*46592Sbostic 			goto done;
150*46592Sbostic 		}
1511965Swnj 		case ETXTBSY:
152*46592Sbostic 			if (etxtbsy < 3)
153*46592Sbostic 				(void)sleep(++etxtbsy);
1541965Swnj 			goto retry;
155*46592Sbostic 		default:
156*46592Sbostic 			goto done;
1571965Swnj 		}
158*46592Sbostic 	}
1591965Swnj 	if (eacces)
1601965Swnj 		errno = EACCES;
161*46592Sbostic 	else if (!errno)
162*46592Sbostic 		errno = ENOENT;
163*46592Sbostic done:	free(path);
1641965Swnj 	return(-1);
1651965Swnj }
166