xref: /dragonfly/lib/libc/gen/exec.c (revision 6bd457ed)
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  * $FreeBSD: src/lib/libc/gen/exec.c,v 1.15 2000/01/27 23:06:14 jasone Exp $
34  * $DragonFly: src/lib/libc/gen/exec.c,v 1.6 2005/04/26 18:51:44 joerg Exp $
35  *
36  * @(#)exec.c	8.1 (Berkeley) 6/4/93
37  * $FreeBSD: src/lib/libc/gen/exec.c,v 1.15 2000/01/27 23:06:14 jasone Exp $
38  */
39 
40 #include "namespace.h"
41 #include <sys/param.h>
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <errno.h>
45 #include <unistd.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <stdio.h>
49 #include <paths.h>
50 #include "un-namespace.h"
51 
52 #include <stdarg.h>
53 
54 extern char **environ;
55 
56 int
57 execl(const char *name, const char *arg, ...)
58 {
59 	va_list ap;
60 	const char **argv;
61 	int n;
62 
63 	va_start(ap, arg);
64 	n = 1;
65 	while (va_arg(ap, char *) != NULL)
66 		n++;
67 	va_end(ap);
68 	argv = alloca((n + 1) * sizeof(*argv));
69 	if (argv == NULL) {
70 		errno = ENOMEM;
71 		return (-1);
72 	}
73 	va_start(ap, arg);
74 	n = 1;
75 	argv[0] = arg;
76 	while ((argv[n] = va_arg(ap, const char *)) != NULL)
77 		n++;
78 	va_end(ap);
79 	return (_execve(name, __DECONST(char **, argv),
80 			__DECONST(char **, environ)));
81 }
82 
83 int
84 execle(const char *name, const char *arg, ...)
85 {
86 	va_list ap;
87 	const char **argv, **envp;
88 	int n;
89 
90 	va_start(ap, arg);
91 	n = 1;
92 	while (va_arg(ap, char *) != NULL)
93 		n++;
94 	va_end(ap);
95 	argv = alloca((n + 1) * sizeof(*argv));
96 	if (argv == NULL) {
97 		errno = ENOMEM;
98 		return (-1);
99 	}
100 	va_start(ap, arg);
101 	n = 1;
102 	argv[0] = arg;
103 	while ((argv[n] = va_arg(ap, const char *)) != NULL)
104 		n++;
105 	envp = va_arg(ap, const char **);
106 	va_end(ap);
107 	return (_execve(name, __DECONST(char **, argv),
108 			__DECONST(char **, envp)));
109 }
110 
111 int
112 execlp(const char *name, const char *arg, ...)
113 {
114 	va_list ap;
115 	const char **argv;
116 	int n;
117 
118 	va_start(ap, arg);
119 	n = 1;
120 	while (va_arg(ap, char *) != NULL)
121 		n++;
122 	va_end(ap);
123 	argv = alloca((n + 1) * sizeof(*argv));
124 	if (argv == NULL) {
125 		errno = ENOMEM;
126 		return (-1);
127 	}
128 	va_start(ap, arg);
129 	n = 1;
130 	argv[0] = arg;
131 	while ((argv[n] = va_arg(ap, const char *)) != NULL)
132 		n++;
133 	va_end(ap);
134 	return (execvp(name, __DECONST(char **, argv)));
135 }
136 
137 int
138 execv(name, argv)
139 	const char *name;
140 	char * const *argv;
141 {
142 	(void)_execve(name, argv, environ);
143 	return (-1);
144 }
145 
146 int
147 execvp(name, argv)
148 	const char *name;
149 	char * const *argv;
150 {
151 	const char **memp;
152 	int cnt;
153 	size_t lp, ln;
154 	int eacces, save_errno;
155 	const char *bp, *p, *path;
156 	char *cur, buf[MAXPATHLEN];
157 	struct stat sb;
158 
159 	eacces = 0;
160 
161 	/* If it's an absolute or relative path name, it's easy. */
162 	if (index(name, '/')) {
163 		bp = name;
164 		cur = NULL;
165 		path = NULL;
166 		goto retry;
167 	}
168 	bp = buf;
169 
170 	/* If it's an empty path name, fail in the usual POSIX way. */
171 	if (*name == '\0') {
172 		errno = ENOENT;
173 		return (-1);
174 	}
175 
176 	/* Get the path we're searching. */
177 	if (!(path = getenv("PATH")))
178 		path = _PATH_DEFPATH;
179 	cur = alloca(strlen(path) + 1);
180 	if (cur == NULL) {
181 		errno = ENOMEM;
182 		return (-1);
183 	}
184 	strcpy(cur, path);
185 	path = cur;
186 	while ( (p = strsep(&cur, ":")) ) {
187 		/*
188 		 * It's a SHELL path -- double, leading and trailing colons
189 		 * mean the current directory.
190 		 */
191 		if (!*p) {
192 			p = ".";
193 			lp = 1;
194 		} else
195 			lp = strlen(p);
196 		ln = strlen(name);
197 
198 		/*
199 		 * If the path is too long complain.  This is a possible
200 		 * security issue; given a way to make the path too long
201 		 * the user may execute the wrong program.
202 		 */
203 		if (lp + ln + 2 > sizeof(buf)) {
204 			(void)_write(STDERR_FILENO, "execvp: ", 8);
205 			(void)_write(STDERR_FILENO, p, lp);
206 			(void)_write(STDERR_FILENO, ": path too long\n",
207 			    16);
208 			continue;
209 		}
210 		bcopy(p, buf, lp);
211 		buf[lp] = '/';
212 		bcopy(name, buf + lp + 1, ln);
213 		buf[lp + ln + 1] = '\0';
214 
215 retry:		(void)_execve(bp, argv, environ);
216 		switch(errno) {
217 		case E2BIG:
218 			goto done;
219 		case ELOOP:
220 		case ENAMETOOLONG:
221 		case ENOENT:
222 			break;
223 		case ENOEXEC:
224 			for (cnt = 0; argv[cnt]; ++cnt)
225 				;
226 			memp = alloca((cnt + 2) * sizeof(char *));
227 			if (memp == NULL) {
228 				/* errno = ENOMEM; XXX override ENOEXEC? */
229 				goto done;
230 			}
231 			memp[0] = "sh";
232 			memp[1] = bp;
233 			bcopy(argv + 1, memp + 2, cnt * sizeof(char *));
234 			_execve(_PATH_BSHELL, __DECONST(char **, memp), environ);
235 			goto done;
236 		case ENOMEM:
237 			goto done;
238 		case ENOTDIR:
239 			break;
240 		case ETXTBSY:
241 			/*
242 			 * We used to retry here, but sh(1) doesn't.
243 			 */
244 			goto done;
245 		default:
246 			/*
247 			 * EACCES may be for an inaccessible directory or
248 			 * a non-executable file.  Call stat() to decide
249 			 * which.  This also handles ambiguities for EFAULT
250 			 * and EIO, and undocumented errors like ESTALE.
251 			 * We hope that the race for a stat() is unimportant.
252 			 */
253 			save_errno = errno;
254 			if (stat(bp, &sb) != 0)
255 				break;
256 			if (save_errno == EACCES) {
257 				eacces = 1;
258 				continue;
259 			}
260 			errno = save_errno;
261 			goto done;
262 		}
263 	}
264 	if (eacces)
265 		errno = EACCES;
266 	else
267 		errno = ENOENT;
268 done:
269 	return (-1);
270 }
271