Add posix_spawn() and posix_spawnp().
[dragonfly.git] / lib / libc / gen / exec.c
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  * 4. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * @(#)exec.c   8.1 (Berkeley) 6/4/93
30  * $FreeBSD: src/lib/libc/gen/exec.c,v 1.25 2008/06/23 05:22:06 ed Exp $
31  * $DragonFly: src/lib/libc/gen/exec.c,v 1.7 2005/11/13 00:07:42 swildner Exp $
32  */
33
34 #include "namespace.h"
35 #include <sys/param.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <errno.h>
39 #include <unistd.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <stdio.h>
43 #include <paths.h>
44
45 #include <stdarg.h>
46 #include "un-namespace.h"
47 #include "libc_private.h"
48
49 extern char **environ;
50
51 int
52 execl(const char *name, const char *arg, ...)
53 {
54         va_list ap;
55         const char **argv;
56         int n;
57
58         va_start(ap, arg);
59         n = 1;
60         while (va_arg(ap, char *) != NULL)
61                 n++;
62         va_end(ap);
63         argv = alloca((n + 1) * sizeof(*argv));
64         if (argv == NULL) {
65                 errno = ENOMEM;
66                 return (-1);
67         }
68         va_start(ap, arg);
69         n = 1;
70         argv[0] = arg;
71         while ((argv[n] = va_arg(ap, const char *)) != NULL)
72                 n++;
73         va_end(ap);
74         return (_execve(name, __DECONST(char **, argv),
75                         __DECONST(char **, environ)));
76 }
77
78 int
79 execle(const char *name, const char *arg, ...)
80 {
81         va_list ap;
82         const char **argv, **envp;
83         int n;
84
85         va_start(ap, arg);
86         n = 1;
87         while (va_arg(ap, char *) != NULL)
88                 n++;
89         va_end(ap);
90         argv = alloca((n + 1) * sizeof(*argv));
91         if (argv == NULL) {
92                 errno = ENOMEM;
93                 return (-1);
94         }
95         va_start(ap, arg);
96         n = 1;
97         argv[0] = arg;
98         while ((argv[n] = va_arg(ap, const char *)) != NULL)
99                 n++;
100         envp = va_arg(ap, const char **);
101         va_end(ap);
102         return (_execve(name, __DECONST(char **, argv),
103                         __DECONST(char **, envp)));
104 }
105
106 int
107 execlp(const char *name, const char *arg, ...)
108 {
109         va_list ap;
110         const char **argv;
111         int n;
112
113         va_start(ap, arg);
114         n = 1;
115         while (va_arg(ap, char *) != NULL)
116                 n++;
117         va_end(ap);
118         argv = alloca((n + 1) * sizeof(*argv));
119         if (argv == NULL) {
120                 errno = ENOMEM;
121                 return (-1);
122         }
123         va_start(ap, arg);
124         n = 1;
125         argv[0] = arg;
126         while ((argv[n] = va_arg(ap, const char *)) != NULL)
127                 n++;
128         va_end(ap);
129         return (execvp(name, __DECONST(char **, argv)));
130 }
131
132 int
133 execv(const char *name, char * const *argv)
134 {
135         _execve(name, argv, environ);
136         return (-1);
137 }
138
139 int
140 execvp(const char *name, char * const *argv)
141 {
142         return (_execvpe(name, argv, environ));
143 }
144
145 static int
146 execvPe(const char *name, const char *path, char * const *argv,
147         char * const *envp)
148 {
149         const char **memp;
150         int cnt;
151         size_t lp, ln;
152         int eacces, save_errno;
153         const char *bp, *p;
154         char *cur, buf[MAXPATHLEN];
155         struct stat sb;
156
157         eacces = 0;
158
159         /* If it's an absolute or relative path name, it's easy. */
160         if (index(name, '/')) {
161                 bp = name;
162                 cur = 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         cur = alloca(strlen(path) + 1);
174         if (cur == NULL) {
175                 errno = ENOMEM;
176                 return (-1);
177         }
178         strcpy(cur, path);
179         while ((p = strsep(&cur, ":")) != NULL) {
180                 /*
181                  * It's a SHELL path -- double, leading and trailing colons
182                  * mean the current directory.
183                  */
184                 if (*p == '\0') {
185                         p = ".";
186                         lp = 1;
187                 } else
188                         lp = strlen(p);
189                 ln = strlen(name);
190
191                 /*
192                  * If the path is too long complain.  This is a possible
193                  * security issue; given a way to make the path too long
194                  * the user may execute the wrong program.
195                  */
196                 if (lp + ln + 2 > sizeof(buf)) {
197                         _write(STDERR_FILENO, "execvP: ", 8);
198                         _write(STDERR_FILENO, p, lp);
199                         _write(STDERR_FILENO, ": path too long\n", 16);
200                         continue;
201                 }
202                 bcopy(p, buf, lp);
203                 buf[lp] = '/';
204                 bcopy(name, buf + lp + 1, ln);
205                 buf[lp + ln + 1] = '\0';
206 retry:
207                 _execve(bp, argv, environ);
208                 switch (errno) {
209                 case E2BIG:
210                         goto done;
211                 case ELOOP:
212                 case ENAMETOOLONG:
213                 case ENOENT:
214                         break;
215                 case ENOEXEC:
216                         for (cnt = 0; argv[cnt]; ++cnt)
217                                 ;
218                         memp = alloca((cnt + 2) * sizeof(char *));
219                         if (memp == NULL) {
220                                 /* errno = ENOMEM; XXX override ENOEXEC? */
221                                 goto done;
222                         }
223                         memp[0] = "sh";
224                         memp[1] = bp;
225                         bcopy(argv + 1, memp + 2, cnt * sizeof(char *));
226                         _execve(_PATH_BSHELL, __DECONST(char **, memp), environ);
227                         goto done;
228                 case ENOMEM:
229                         goto done;
230                 case ENOTDIR:
231                         break;
232                 case ETXTBSY:
233                         /*
234                          * We used to retry here, but sh(1) doesn't.
235                          */
236                         goto done;
237                 default:
238                         /*
239                          * EACCES may be for an inaccessible directory or
240                          * a non-executable file.  Call stat() to decide
241                          * which.  This also handles ambiguities for EFAULT
242                          * and EIO, and undocumented errors like ESTALE.
243                          * We hope that the race for a stat() is unimportant.
244                          */
245                         save_errno = errno;
246                         if (stat(bp, &sb) != 0)
247                                 break;
248                         if (save_errno == EACCES) {
249                                 eacces = 1;
250                                 continue;
251                         }
252                         errno = save_errno;
253                         goto done;
254                 }
255         }
256         if (eacces)
257                 errno = EACCES;
258         else
259                 errno = ENOENT;
260 done:
261         return (-1);
262 }
263
264 int
265 execvP(const char *name, const char *path, char * const argv[])
266 {
267         return execvPe(name, path, argv, environ);
268 }
269
270 int
271 _execvpe(const char *name, char * const argv[], char * const envp[])
272 {
273         const char *path;
274
275         /* Get the path we're searching. */
276         if ((path = getenv("PATH")) == NULL)
277                 path = _PATH_DEFPATH;
278
279         return (execvPe(name, path, argv, envp));
280 }