xref: /original-bsd/lib/libc/gen/exec.c (revision e59fb703)
1 /*-
2  * Copyright (c) 1991 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #if defined(LIBC_SCCS) && !defined(lint)
9 static char sccsid[] = "@(#)exec.c	5.9 (Berkeley) 06/17/91";
10 #endif /* LIBC_SCCS and not lint */
11 
12 #include <sys/param.h>
13 #include <sys/types.h>
14 #include <errno.h>
15 #include <unistd.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <stdio.h>
19 #include <paths.h>
20 
21 #if __STDC__
22 #include <stdarg.h>
23 #else
24 #include <varargs.h>
25 #endif
26 
27 extern char **environ;
28 
29 static char **
30 buildargv(ap, arg, envpp)
31 	va_list ap;
32 	const char *arg;
33 	char ***envpp;
34 {
35 	register size_t max, off;
36 	register char **argv = NULL;
37 
38 	for (off = max = 0;; ++off) {
39 		if (off >= max) {
40 			max += 50;	/* Starts out at 0. */
41 			max *= 2;	/* Ramp up fast. */
42 			if (!(argv = realloc(argv, max * sizeof(char *))))
43 				return(NULL);
44 			if (off == 0) {
45 				argv[0] = (char *)arg;
46 				off = 1;
47 			}
48 		}
49 		if (!(argv[off] = va_arg(ap, char *)))
50 			break;
51 	}
52 	/* Get environment pointer if user supposed to provide one. */
53 	if (envpp)
54 		*envpp = va_arg(ap, char **);
55 	return(argv);
56 }
57 
58 int
59 #if __STDC__
60 execl(const char *name, const char *arg, ...)
61 #else
62 execl(name, arg, va_alist)
63 	const char *name;
64 	const char *arg;
65 	va_dcl
66 #endif
67 {
68 	va_list ap;
69 	int sverrno;
70 	char **argv;
71 
72 #if __STDC__
73 	va_start(ap, arg);
74 #else
75 	va_start(ap);
76 #endif
77 	if (argv = buildargv(ap, arg, (char ***)NULL))
78 		(void)execve(name, argv, environ);
79 	va_end(ap);
80 	sverrno = errno;
81 	free(argv);
82 	errno = sverrno;
83 	return(-1);
84 }
85 
86 int
87 #if __STDC__
88 execle(const char *name, const char *arg, ...)
89 #else
90 execle(name, arg, va_alist)
91 	const char *name;
92 	const char *arg;
93 	va_dcl
94 #endif
95 {
96 	va_list ap;
97 	int sverrno;
98 	char **argv, **envp;
99 
100 #if __STDC__
101 	va_start(ap, arg);
102 #else
103 	va_start(ap);
104 #endif
105 	if (argv = buildargv(ap, arg, &envp))
106 		(void)execve(name, argv, envp);
107 	va_end(ap);
108 	sverrno = errno;
109 	free(argv);
110 	errno = sverrno;
111 	return(-1);
112 }
113 
114 int
115 #if __STDC__
116 execlp(const char *name, const char *arg, ...)
117 #else
118 execlp(name, arg, va_alist)
119 	const char *name;
120 	const char *arg;
121 	va_dcl
122 #endif
123 {
124 	va_list ap;
125 	int sverrno;
126 	char **argv;
127 
128 #if __STDC__
129 	va_start(ap, arg);
130 #else
131 	va_start(ap);
132 #endif
133 	if (argv = buildargv(ap, arg, (char ***)NULL))
134 		(void)execvp(name, argv);
135 	va_end(ap);
136 	sverrno = errno;
137 	free(argv);
138 	errno = sverrno;
139 	return(-1);
140 }
141 
142 int
143 execv(name, argv)
144 	const char *name;
145 	char * const *argv;
146 {
147 	(void)execve(name, argv, environ);
148 	return(-1);
149 }
150 
151 int
152 execvp(name, argv)
153 	const char *name;
154 	char * const *argv;
155 {
156 	register int lp, ln;
157 	register char *p;
158 	int eacces, etxtbsy;
159 	char *bp, *cur, *path, buf[MAXPATHLEN];
160 
161 	/* If it's an absolute or relative path name, it's easy. */
162 	if (index(name, '/')) {
163 		bp = (char *)name;
164 		cur = path = NULL;
165 		goto retry;
166 	}
167 	bp = buf;
168 
169 	/* Get the path we're searching. */
170 	if (!(path = getenv("PATH")))
171 		path = _PATH_DEFPATH;
172 	cur = path = strdup(path);
173 
174 	eacces = etxtbsy = 0;
175 	while (p = strsep(&cur, ":")) {
176 		/*
177 		 * It's a SHELL path -- double, leading and trailing colons
178 		 * mean the current directory.
179 		 */
180 		if (!*p) {
181 			p = ".";
182 			lp = 1;
183 		} else
184 			lp = strlen(p);
185 		ln = strlen(name);
186 
187 		/*
188 		 * If the path is too long complain.  This is a possible
189 		 * security issue; given a way to make the path too long
190 		 * the user may execute the wrong program.
191 		 */
192 		if (lp + ln + 2 > sizeof(buf)) {
193 			(void)write(STDERR_FILENO, "execvp: ", 8);
194 			(void)write(STDERR_FILENO, p, lp);
195 			(void)write(STDERR_FILENO, ": path too long\n", 16);
196 			continue;
197 		}
198 		bcopy(p, buf, lp);
199 		buf[lp] = '/';
200 		bcopy(name, buf + lp + 1, ln);
201 		buf[lp + ln + 1] = '\0';
202 
203 retry:		(void)execve(bp, argv, environ);
204 		switch(errno) {
205 		case EACCES:
206 			eacces = 1;
207 			break;
208 		case ENOENT:
209 			break;
210 		case ENOEXEC: {
211 			register size_t cnt;
212 			register char **ap;
213 
214 			for (cnt = 0, ap = (char **)argv; *ap; ++ap, ++cnt);
215 			if (ap = malloc((cnt + 2) * sizeof(char *))) {
216 				bcopy(argv + 1, ap + 2, cnt * sizeof(char *));
217 				ap[0] = "sh";
218 				ap[1] = bp;
219 				(void)execve(_PATH_BSHELL, ap, environ);
220 				free(ap);
221 			}
222 			goto done;
223 		}
224 		case ETXTBSY:
225 			if (etxtbsy < 3)
226 				(void)sleep(++etxtbsy);
227 			goto retry;
228 		default:
229 			goto done;
230 		}
231 	}
232 	if (eacces)
233 		errno = EACCES;
234 	else if (!errno)
235 		errno = ENOENT;
236 done:	if (path)
237 		free(path);
238 	return(-1);
239 }
240