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