]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libc/gen/exec.c
sqlite3: Vendor import of sqlite3 3.45.0
[FreeBSD/FreeBSD.git] / lib / libc / gen / exec.c
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 "namespace.h"
33 #include <sys/param.h>
34 #include <sys/stat.h>
35 #include <errno.h>
36 #include <unistd.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <stdio.h>
40 #include <paths.h>
41
42 #include <stdarg.h>
43 #include "un-namespace.h"
44 #include "libc_private.h"
45
46 static const char execvPe_err_preamble[] = "execvP: ";
47 static const char execvPe_err_trailer[] = ": path too long\n";
48
49 int
50 execl(const char *name, const char *arg, ...)
51 {
52         va_list ap;
53         const char **argv;
54         int n;
55
56         va_start(ap, arg);
57         n = 1;
58         while (va_arg(ap, char *) != NULL)
59                 n++;
60         va_end(ap);
61         argv = alloca((n + 1) * sizeof(*argv));
62         if (argv == NULL) {
63                 errno = ENOMEM;
64                 return (-1);
65         }
66         va_start(ap, arg);
67         n = 1;
68         argv[0] = arg;
69         while ((argv[n] = va_arg(ap, char *)) != NULL)
70                 n++;
71         va_end(ap);
72         return (_execve(name, __DECONST(char **, argv), environ));
73 }
74
75 int
76 execle(const char *name, const char *arg, ...)
77 {
78         va_list ap;
79         const char **argv;
80         char **envp;
81         int n;
82
83         va_start(ap, arg);
84         n = 1;
85         while (va_arg(ap, char *) != NULL)
86                 n++;
87         va_end(ap);
88         argv = alloca((n + 1) * sizeof(*argv));
89         if (argv == NULL) {
90                 errno = ENOMEM;
91                 return (-1);
92         }
93         va_start(ap, arg);
94         n = 1;
95         argv[0] = arg;
96         while ((argv[n] = va_arg(ap, char *)) != NULL)
97                 n++;
98         envp = va_arg(ap, char **);
99         va_end(ap);
100         return (_execve(name, __DECONST(char **, argv), envp));
101 }
102
103 int
104 execlp(const char *name, const char *arg, ...)
105 {
106         va_list ap;
107         const char **argv;
108         int n;
109
110         va_start(ap, arg);
111         n = 1;
112         while (va_arg(ap, char *) != NULL)
113                 n++;
114         va_end(ap);
115         argv = alloca((n + 1) * sizeof(*argv));
116         if (argv == NULL) {
117                 errno = ENOMEM;
118                 return (-1);
119         }
120         va_start(ap, arg);
121         n = 1;
122         argv[0] = arg;
123         while ((argv[n] = va_arg(ap, char *)) != NULL)
124                 n++;
125         va_end(ap);
126         return (execvp(name, __DECONST(char **, argv)));
127 }
128
129 int
130 execv(const char *name, char * const *argv)
131 {
132         (void)_execve(name, argv, environ);
133         return (-1);
134 }
135
136 int
137 execvp(const char *name, char * const *argv)
138 {
139         return (execvpe(name, argv, environ));
140 }
141
142 static int
143 execvPe(const char *name, const char *path, char * const *argv,
144     char * const *envp)
145 {
146         const char **memp;
147         size_t cnt, lp, ln;
148         int eacces, save_errno;
149         char buf[MAXPATHLEN];
150         const char *bp, *np, *op, *p;
151         struct stat sb;
152
153         eacces = 0;
154
155         /* If it's an absolute or relative path name, it's easy. */
156         if (strchr(name, '/')) {
157                 bp = name;
158                 op = NULL;
159                 goto retry;
160         }
161         bp = buf;
162
163         /* If it's an empty path name, fail in the usual POSIX way. */
164         if (*name == '\0') {
165                 errno = ENOENT;
166                 return (-1);
167         }
168
169         op = path;
170         ln = strlen(name);
171         while (op != NULL) {
172                 np = strchrnul(op, ':');
173
174                 /*
175                  * It's a SHELL path -- double, leading and trailing colons
176                  * mean the current directory.
177                  */
178                 if (np == op) {
179                         /* Empty component. */
180                         p = ".";
181                         lp = 1;
182                 } else {
183                         /* Non-empty component. */
184                         p = op;
185                         lp = np - op;
186                 }
187
188                 /* Advance to the next component or terminate after this. */
189                 if (*np == '\0')
190                         op = NULL;
191                 else
192                         op = np + 1;
193
194                 /*
195                  * If the path is too long complain.  This is a possible
196                  * security issue; given a way to make the path too long
197                  * the user may execute the wrong program.
198                  */
199                 if (lp + ln + 2 > sizeof(buf)) {
200                         (void)_write(STDERR_FILENO, execvPe_err_preamble,
201                             sizeof(execvPe_err_preamble) - 1);
202                         (void)_write(STDERR_FILENO, p, lp);
203                         (void)_write(STDERR_FILENO, execvPe_err_trailer,
204                             sizeof(execvPe_err_trailer) - 1);
205                         continue;
206                 }
207                 bcopy(p, buf, lp);
208                 buf[lp] = '/';
209                 bcopy(name, buf + lp + 1, ln);
210                 buf[lp + ln + 1] = '\0';
211
212 retry:          (void)_execve(bp, argv, envp);
213                 switch (errno) {
214                 case E2BIG:
215                         goto done;
216                 case ELOOP:
217                 case ENAMETOOLONG:
218                 case ENOENT:
219                         break;
220                 case ENOEXEC:
221                         for (cnt = 0; argv[cnt]; ++cnt)
222                                 ;
223
224                         /*
225                          * cnt may be 0 above; always allocate at least
226                          * 3 entries so that we can at least fit "sh", bp, and
227                          * the NULL terminator.  We can rely on cnt to take into
228                          * account the NULL terminator in all other scenarios,
229                          * as we drop argv[0].
230                          */
231                         memp = alloca(MAX(3, cnt + 2) * sizeof(char *));
232                         if (memp == NULL) {
233                                 /* errno = ENOMEM; XXX override ENOEXEC? */
234                                 goto done;
235                         }
236                         if (cnt > 0) {
237                                 memp[0] = argv[0];
238                                 memp[1] = bp;
239                                 bcopy(argv + 1, memp + 2, cnt * sizeof(char *));
240                         } else {
241                                 memp[0] = "sh";
242                                 memp[1] = bp;
243                                 memp[2] = NULL;
244                         }
245                         (void)_execve(_PATH_BSHELL,
246                             __DECONST(char **, memp), envp);
247                         goto done;
248                 case ENOMEM:
249                         goto done;
250                 case ENOTDIR:
251                         break;
252                 case ETXTBSY:
253                         /*
254                          * We used to retry here, but sh(1) doesn't.
255                          */
256                         goto done;
257                 default:
258                         /*
259                          * EACCES may be for an inaccessible directory or
260                          * a non-executable file.  Call stat() to decide
261                          * which.  This also handles ambiguities for EFAULT
262                          * and EIO, and undocumented errors like ESTALE.
263                          * We hope that the race for a stat() is unimportant.
264                          */
265                         save_errno = errno;
266                         if (stat(bp, &sb) != 0)
267                                 break;
268                         if (save_errno == EACCES) {
269                                 eacces = 1;
270                                 continue;
271                         }
272                         errno = save_errno;
273                         goto done;
274                 }
275         }
276         if (eacces)
277                 errno = EACCES;
278         else
279                 errno = ENOENT;
280 done:
281         return (-1);
282 }
283
284 int
285 execvP(const char *name, const char *path, char * const argv[])
286 {
287         return execvPe(name, path, argv, environ);
288 }
289
290 int
291 execvpe(const char *name, char * const argv[], char * const envp[])
292 {
293         const char *path;
294
295         /* Get the path we're searching. */
296         if ((path = getenv("PATH")) == NULL)
297                 path = _PATH_DEFPATH;
298
299         return (execvPe(name, path, argv, envp));
300 }