]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libc/gen/exec.c
Merge llvm, clang, lld, lldb, compiler-rt and libc++ r304460, and update
[FreeBSD/FreeBSD.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  * 3. 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
30 #if defined(LIBC_SCCS) && !defined(lint)
31 static char sccsid[] = "@(#)exec.c      8.1 (Berkeley) 6/4/93";
32 #endif /* LIBC_SCCS and not lint */
33 #include <sys/cdefs.h>
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 extern char **environ;
51
52 int
53 execl(const char *name, const char *arg, ...)
54 {
55         va_list ap;
56         const char **argv;
57         int n;
58
59         va_start(ap, arg);
60         n = 1;
61         while (va_arg(ap, char *) != NULL)
62                 n++;
63         va_end(ap);
64         argv = alloca((n + 1) * sizeof(*argv));
65         if (argv == NULL) {
66                 errno = ENOMEM;
67                 return (-1);
68         }
69         va_start(ap, arg);
70         n = 1;
71         argv[0] = arg;
72         while ((argv[n] = va_arg(ap, char *)) != NULL)
73                 n++;
74         va_end(ap);
75         return (_execve(name, __DECONST(char **, argv), environ));
76 }
77
78 int
79 execle(const char *name, const char *arg, ...)
80 {
81         va_list ap;
82         const char **argv;
83         char **envp;
84         int n;
85
86         va_start(ap, arg);
87         n = 1;
88         while (va_arg(ap, char *) != NULL)
89                 n++;
90         va_end(ap);
91         argv = alloca((n + 1) * sizeof(*argv));
92         if (argv == NULL) {
93                 errno = ENOMEM;
94                 return (-1);
95         }
96         va_start(ap, arg);
97         n = 1;
98         argv[0] = arg;
99         while ((argv[n] = va_arg(ap, char *)) != NULL)
100                 n++;
101         envp = va_arg(ap, char **);
102         va_end(ap);
103         return (_execve(name, __DECONST(char **, argv), 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, 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         (void)_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         size_t cnt, lp, ln;
151         int eacces, save_errno;
152         char *cur, buf[MAXPATHLEN];
153         const char *p, *bp;
154         struct stat sb;
155
156         eacces = 0;
157
158         /* If it's an absolute or relative path name, it's easy. */
159         if (strchr(name, '/')) {
160                 bp = name;
161                 cur = NULL;
162                 goto retry;
163         }
164         bp = buf;
165
166         /* If it's an empty path name, fail in the usual POSIX way. */
167         if (*name == '\0') {
168                 errno = ENOENT;
169                 return (-1);
170         }
171
172         cur = alloca(strlen(path) + 1);
173         if (cur == NULL) {
174                 errno = ENOMEM;
175                 return (-1);
176         }
177         strcpy(cur, path);
178         while ((p = strsep(&cur, ":")) != NULL) {
179                 /*
180                  * It's a SHELL path -- double, leading and trailing colons
181                  * mean the current directory.
182                  */
183                 if (*p == '\0') {
184                         p = ".";
185                         lp = 1;
186                 } else
187                         lp = strlen(p);
188                 ln = strlen(name);
189
190                 /*
191                  * If the path is too long complain.  This is a possible
192                  * security issue; given a way to make the path too long
193                  * the user may execute the wrong program.
194                  */
195                 if (lp + ln + 2 > sizeof(buf)) {
196                         (void)_write(STDERR_FILENO, "execvP: ", 8);
197                         (void)_write(STDERR_FILENO, p, lp);
198                         (void)_write(STDERR_FILENO, ": path too long\n",
199                             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
207 retry:          (void)_execve(bp, argv, envp);
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                         (void)_execve(_PATH_BSHELL,
227                             __DECONST(char **, memp), envp);
228                         goto done;
229                 case ENOMEM:
230                         goto done;
231                 case ENOTDIR:
232                         break;
233                 case ETXTBSY:
234                         /*
235                          * We used to retry here, but sh(1) doesn't.
236                          */
237                         goto done;
238                 default:
239                         /*
240                          * EACCES may be for an inaccessible directory or
241                          * a non-executable file.  Call stat() to decide
242                          * which.  This also handles ambiguities for EFAULT
243                          * and EIO, and undocumented errors like ESTALE.
244                          * We hope that the race for a stat() is unimportant.
245                          */
246                         save_errno = errno;
247                         if (stat(bp, &sb) != 0)
248                                 break;
249                         if (save_errno == EACCES) {
250                                 eacces = 1;
251                                 continue;
252                         }
253                         errno = save_errno;
254                         goto done;
255                 }
256         }
257         if (eacces)
258                 errno = EACCES;
259         else
260                 errno = ENOENT;
261 done:
262         return (-1);
263 }
264
265 int
266 execvP(const char *name, const char *path, char * const argv[])
267 {
268         return execvPe(name, path, argv, environ);
269 }
270
271 int
272 _execvpe(const char *name, char * const argv[], char * const envp[])
273 {
274         const char *path;
275
276         /* Get the path we're searching. */
277         if ((path = getenv("PATH")) == NULL)
278                 path = _PATH_DEFPATH;
279
280         return (execvPe(name, path, argv, envp));
281 }