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