xref: /freebsd/lib/libc/gen/exec.c (revision 33b77e2decd50e53798014b70bf7ca3bdc4c0c7e)
1 /*-
2  * Copyright (c) 1991, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #if defined(LIBC_SCCS) && !defined(lint)
35 #if 0
36 static char sccsid[] = "@(#)exec.c	8.1 (Berkeley) 6/4/93";
37 #endif
38 static const char rcsid[] =
39 	"$Id: exec.c,v 1.6 1997/10/14 07:23:16 bde Exp $";
40 #endif /* LIBC_SCCS and not lint */
41 
42 #include <sys/param.h>
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 #include <errno.h>
46 #include <unistd.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <stdio.h>
50 #include <paths.h>
51 
52 #if __STDC__
53 #include <stdarg.h>
54 #else
55 #include <varargs.h>
56 #endif
57 
58 extern char **environ;
59 
60 static char **
61 buildargv(ap, arg, envpp)
62 	va_list ap;
63 	const char *arg;
64 	char ***envpp;
65 {
66 	register char **argv, **nargv;
67 	register int memsize, off;
68 
69 	argv = NULL;
70 	for (off = memsize = 0;; ++off) {
71 		if (off >= memsize) {
72 			memsize += 50;	/* Starts out at 0. */
73 			memsize *= 2;	/* Ramp up fast. */
74 			nargv = realloc(argv, memsize * sizeof(char *));
75 			if (nargv == NULL) {
76 				free(argv);
77 				return (NULL);
78 			}
79 			argv = nargv;
80 			if (off == 0) {
81 				argv[0] = (char *)arg;
82 				off = 1;
83 			}
84 		}
85 		if (!(argv[off] = va_arg(ap, char *)))
86 			break;
87 	}
88 	/* Get environment pointer if user supposed to provide one. */
89 	if (envpp)
90 		*envpp = va_arg(ap, char **);
91 	return (argv);
92 }
93 
94 int
95 #if __STDC__
96 execl(const char *name, const char *arg, ...)
97 #else
98 execl(name, arg, va_alist)
99 	const char *name;
100 	const char *arg;
101 	va_dcl
102 #endif
103 {
104 	va_list ap;
105 	int sverrno;
106 	char **argv;
107 
108 #if __STDC__
109 	va_start(ap, arg);
110 #else
111 	va_start(ap);
112 #endif
113 	if ( (argv = buildargv(ap, arg, NULL)) )
114 		(void)execve(name, argv, environ);
115 	va_end(ap);
116 	sverrno = errno;
117 	free(argv);
118 	errno = sverrno;
119 	return (-1);
120 }
121 
122 int
123 #if __STDC__
124 execle(const char *name, const char *arg, ...)
125 #else
126 execle(name, arg, va_alist)
127 	const char *name;
128 	const char *arg;
129 	va_dcl
130 #endif
131 {
132 	va_list ap;
133 	int sverrno;
134 	char **argv, **envp;
135 
136 #if __STDC__
137 	va_start(ap, arg);
138 #else
139 	va_start(ap);
140 #endif
141 	if ( (argv = buildargv(ap, arg, &envp)) )
142 		(void)execve(name, argv, envp);
143 	va_end(ap);
144 	sverrno = errno;
145 	free(argv);
146 	errno = sverrno;
147 	return (-1);
148 }
149 
150 int
151 #if __STDC__
152 execlp(const char *name, const char *arg, ...)
153 #else
154 execlp(name, arg, va_alist)
155 	const char *name;
156 	const char *arg;
157 	va_dcl
158 #endif
159 {
160 	va_list ap;
161 	int sverrno;
162 	char **argv;
163 
164 #if __STDC__
165 	va_start(ap, arg);
166 #else
167 	va_start(ap);
168 #endif
169 	if ( (argv = buildargv(ap, arg, NULL)) )
170 		(void)execvp(name, argv);
171 	va_end(ap);
172 	sverrno = errno;
173 	free(argv);
174 	errno = sverrno;
175 	return (-1);
176 }
177 
178 int
179 execv(name, argv)
180 	const char *name;
181 	char * const *argv;
182 {
183 	(void)execve(name, argv, environ);
184 	return (-1);
185 }
186 
187 int
188 execvp(name, argv)
189 	const char *name;
190 	char * const *argv;
191 {
192 	char **memp;
193 	register int cnt, lp, ln;
194 	register char *p;
195 	int eacces, save_errno;
196 	char *bp, *cur, *path, buf[MAXPATHLEN];
197 	struct stat sb;
198 
199 	eacces = 0;
200 
201 	/* If it's an absolute or relative path name, it's easy. */
202 	if (index(name, '/')) {
203 		bp = (char *)name;
204 		cur = path = NULL;
205 		goto retry;
206 	}
207 	bp = buf;
208 
209 	/* If it's an empty path name, fail in the usual POSIX way. */
210 	if (*name == '\0') {
211 		errno = ENOENT;
212 		return (-1);
213 	}
214 
215 	/* Get the path we're searching. */
216 	if (!(path = getenv("PATH")))
217 		path = _PATH_DEFPATH;
218 	cur = path = strdup(path);
219 
220 	while ( (p = strsep(&cur, ":")) ) {
221 		/*
222 		 * It's a SHELL path -- double, leading and trailing colons
223 		 * mean the current directory.
224 		 */
225 		if (!*p) {
226 			p = ".";
227 			lp = 1;
228 		} else
229 			lp = strlen(p);
230 		ln = strlen(name);
231 
232 		/*
233 		 * If the path is too long complain.  This is a possible
234 		 * security issue; given a way to make the path too long
235 		 * the user may execute the wrong program.
236 		 */
237 		if (lp + ln + 2 > sizeof(buf)) {
238 			(void)write(STDERR_FILENO, "execvp: ", 8);
239 			(void)write(STDERR_FILENO, p, lp);
240 			(void)write(STDERR_FILENO, ": path too long\n", 16);
241 			continue;
242 		}
243 		bcopy(p, buf, lp);
244 		buf[lp] = '/';
245 		bcopy(name, buf + lp + 1, ln);
246 		buf[lp + ln + 1] = '\0';
247 
248 retry:		(void)execve(bp, argv, environ);
249 		switch(errno) {
250 		case E2BIG:
251 			goto done;
252 		case ELOOP:
253 		case ENAMETOOLONG:
254 		case ENOENT:
255 			break;
256 		case ENOEXEC:
257 			for (cnt = 0; argv[cnt]; ++cnt)
258 				;
259 			memp = malloc((cnt + 2) * sizeof(char *));
260 			if (memp == NULL)
261 				goto done;
262 			memp[0] = "sh";
263 			memp[1] = bp;
264 			bcopy(argv + 1, memp + 2, cnt * sizeof(char *));
265 			(void)execve(_PATH_BSHELL, memp, environ);
266 			free(memp);
267 			goto done;
268 		case ENOMEM:
269 			goto done;
270 		case ENOTDIR:
271 			break;
272 		case ETXTBSY:
273 			/*
274 			 * We used to retry here, but sh(1) doesn't.
275 			 */
276 			goto done;
277 		default:
278 			/*
279 			 * EACCES may be for an inaccessible directory or
280 			 * a non-executable file.  Call stat() to decide
281 			 * which.  This also handles ambiguities for EFAULT
282 			 * and EIO, and undocumented errors like ESTALE.
283 			 * We hope that the race for a stat() is unimportant.
284 			 */
285 			save_errno = errno;
286 			if (stat(bp, &sb) != 0)
287 				break;
288 			if (save_errno == EACCES) {
289 				eacces = 1;
290 				continue;
291 			}
292 			errno = save_errno;
293 			goto done;
294 		}
295 	}
296 	if (eacces)
297 		errno = EACCES;
298 	else
299 		errno = ENOENT;
300 done:	if (path)
301 		free(path);
302 	return (-1);
303 }
304