xref: /openbsd/lib/libc/gen/exec.c (revision 5365c52e)
1 /*	$OpenBSD: exec.c,v 1.19 2012/03/21 23:20:35 matthew Exp $ */
2 /*-
3  * Copyright (c) 1991, 1993
4  *	The Regents of the University of California.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. Neither the name of the University nor the names of its contributors
15  *    may be used to endorse or promote products derived from this software
16  *    without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30 
31 #include <sys/param.h>
32 #include <sys/types.h>
33 #include <sys/uio.h>
34 #include <errno.h>
35 #include <unistd.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <stdio.h>
39 #include <paths.h>
40 #include <stdarg.h>
41 
42 extern char **environ;
43 
44 int
45 execl(const char *name, const char *arg, ...)
46 {
47 	va_list ap;
48 	char **argv;
49 	int n;
50 
51 	va_start(ap, arg);
52 	n = 1;
53 	while (va_arg(ap, char *) != NULL)
54 		n++;
55 	va_end(ap);
56 	argv = alloca((n + 1) * sizeof(*argv));
57 	if (argv == NULL) {
58 		errno = ENOMEM;
59 		return (-1);
60 	}
61 	va_start(ap, arg);
62 	n = 1;
63 	argv[0] = (char *)arg;
64 	while ((argv[n] = va_arg(ap, char *)) != NULL)
65 		n++;
66 	va_end(ap);
67 	return (execve(name, argv, environ));
68 }
69 
70 int
71 execle(const char *name, const char *arg, ...)
72 {
73 	va_list ap;
74 	char **argv, **envp;
75 	int n;
76 
77 	va_start(ap, arg);
78 	n = 1;
79 	while (va_arg(ap, char *) != NULL)
80 		n++;
81 	va_end(ap);
82 	argv = alloca((n + 1) * sizeof(*argv));
83 	if (argv == NULL) {
84 		errno = ENOMEM;
85 		return (-1);
86 	}
87 	va_start(ap, arg);
88 	n = 1;
89 	argv[0] = (char *)arg;
90 	while ((argv[n] = va_arg(ap, char *)) != NULL)
91 		n++;
92 	envp = va_arg(ap, char **);
93 	va_end(ap);
94 	return (execve(name, argv, envp));
95 }
96 
97 int
98 execlp(const char *name, const char *arg, ...)
99 {
100 	va_list ap;
101 	char **argv;
102 	int n;
103 
104 	va_start(ap, arg);
105 	n = 1;
106 	while (va_arg(ap, char *) != NULL)
107 		n++;
108 	va_end(ap);
109 	argv = alloca((n + 1) * sizeof(*argv));
110 	if (argv == NULL) {
111 		errno = ENOMEM;
112 		return (-1);
113 	}
114 	va_start(ap, arg);
115 	n = 1;
116 	argv[0] = (char *)arg;
117 	while ((argv[n] = va_arg(ap, char *)) != NULL)
118 		n++;
119 	va_end(ap);
120 	return (execvp(name, argv));
121 }
122 
123 int
124 execv(const char *name, char *const *argv)
125 {
126 	(void)execve(name, argv, environ);
127 	return (-1);
128 }
129 
130 int
131 execvpe(const char *name, char *const *argv, char *const *envp)
132 {
133 	char **memp;
134 	int cnt, lp, ln, len;
135 	char *p;
136 	int eacces = 0;
137 	char *bp, *cur, *path, buf[MAXPATHLEN];
138 
139 	/*
140 	 * Do not allow null name
141 	 */
142 	if (name == NULL || *name == '\0') {
143 		errno = ENOENT;
144 		return (-1);
145  	}
146 
147 	/* If it's an absolute or relative path name, it's easy. */
148 	if (strchr(name, '/')) {
149 		bp = (char *)name;
150 		cur = path = NULL;
151 		goto retry;
152 	}
153 	bp = buf;
154 
155 	/* Get the path we're searching. */
156 	if (!(path = getenv("PATH")))
157 		path = _PATH_DEFPATH;
158 	len = strlen(path) + 1;
159 	cur = alloca(len);
160 	if (cur == NULL) {
161 		errno = ENOMEM;
162 		return (-1);
163 	}
164 	strlcpy(cur, path, len);
165 	path = cur;
166 	while ((p = strsep(&cur, ":"))) {
167 		/*
168 		 * It's a SHELL path -- double, leading and trailing colons
169 		 * mean the current directory.
170 		 */
171 		if (!*p) {
172 			p = ".";
173 			lp = 1;
174 		} else
175 			lp = strlen(p);
176 		ln = strlen(name);
177 
178 		/*
179 		 * If the path is too long complain.  This is a possible
180 		 * security issue; given a way to make the path too long
181 		 * the user may execute the wrong program.
182 		 */
183 		if (lp + ln + 2 > sizeof(buf)) {
184 			struct iovec iov[3];
185 
186 			iov[0].iov_base = "execvp: ";
187 			iov[0].iov_len = 8;
188 			iov[1].iov_base = p;
189 			iov[1].iov_len = lp;
190 			iov[2].iov_base = ": path too long\n";
191 			iov[2].iov_len = 16;
192 			(void)writev(STDERR_FILENO, iov, 3);
193 			continue;
194 		}
195 		bcopy(p, buf, lp);
196 		buf[lp] = '/';
197 		bcopy(name, buf + lp + 1, ln);
198 		buf[lp + ln + 1] = '\0';
199 
200 retry:		(void)execve(bp, argv, envp);
201 		switch(errno) {
202 		case E2BIG:
203 			goto done;
204 		case EISDIR:
205 		case ELOOP:
206 		case ENAMETOOLONG:
207 		case ENOENT:
208 			break;
209 		case ENOEXEC:
210 			for (cnt = 0; argv[cnt]; ++cnt)
211 				;
212 			memp = alloca((cnt + 2) * sizeof(char *));
213 			if (memp == NULL)
214 				goto done;
215 			memp[0] = "sh";
216 			memp[1] = bp;
217 			bcopy(argv + 1, memp + 2, cnt * sizeof(char *));
218 			(void)execve(_PATH_BSHELL, memp, envp);
219 			goto done;
220 		case ENOMEM:
221 			goto done;
222 		case ENOTDIR:
223 			break;
224 		case ETXTBSY:
225 			/*
226 			 * We used to retry here, but sh(1) doesn't.
227 			 */
228 			goto done;
229 		case EACCES:
230 			eacces = 1;
231 			break;
232 		default:
233 			goto done;
234 		}
235 	}
236 	if (eacces)
237 		errno = EACCES;
238 	else if (!errno)
239 		errno = ENOENT;
240 done:
241 	return (-1);
242 }
243 
244 int
245 execvp(const char *name, char *const *argv)
246 {
247     return execvpe(name, argv, environ);
248 }
249 
250