]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - lib/libc/gen/exec.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.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
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/types.h>
39 #include <sys/stat.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 #include <stdarg.h>
48 #include "un-namespace.h"
49
50 extern char **environ;
51
52 int
53 execl(const char *name, const char *arg, ...)
54 {
55         va_list ap;
56         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] = (char *)arg;
72         while ((argv[n] = va_arg(ap, char *)) != NULL)
73                 n++;
74         va_end(ap);
75         return (_execve(name, argv, environ));
76 }
77
78 int
79 execle(const char *name, const char *arg, ...)
80 {
81         va_list ap;
82         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] = (char *)arg;
98         while ((argv[n] = va_arg(ap, char *)) != NULL)
99                 n++;
100         envp = va_arg(ap, char **);
101         va_end(ap);
102         return (_execve(name, argv, envp));
103 }
104
105 int
106 execlp(const char *name, const char *arg, ...)
107 {
108         va_list ap;
109         char **argv;
110         int n;
111
112         va_start(ap, arg);
113         n = 1;
114         while (va_arg(ap, char *) != NULL)
115                 n++;
116         va_end(ap);
117         argv = alloca((n + 1) * sizeof(*argv));
118         if (argv == NULL) {
119                 errno = ENOMEM;
120                 return (-1);
121         }
122         va_start(ap, arg);
123         n = 1;
124         argv[0] = (char *)arg;
125         while ((argv[n] = va_arg(ap, char *)) != NULL)
126                 n++;
127         va_end(ap);
128         return (execvp(name, argv));
129 }
130
131 int
132 execv(name, argv)
133         const char *name;
134         char * const *argv;
135 {
136         (void)_execve(name, argv, environ);
137         return (-1);
138 }
139
140 int
141 execvp(const char *name, char * const *argv)
142 {
143         const char *path;
144
145         /* Get the path we're searching. */
146         if ((path = getenv("PATH")) == NULL)
147                 path = _PATH_DEFPATH;
148
149         return (execvP(name, path, argv));
150 }
151
152 int
153 execvP(name, path, argv)
154         const char *name;
155         const char *path;
156         char * const *argv;
157 {
158         char **memp;
159         int cnt, lp, ln;
160         char *p;
161         int eacces, save_errno;
162         char *bp, *cur, buf[MAXPATHLEN];
163         struct stat sb;
164
165         eacces = 0;
166
167         /* If it's an absolute or relative path name, it's easy. */
168         if (index(name, '/')) {
169                 bp = (char *)name;
170                 cur = NULL;
171                 goto retry;
172         }
173         bp = buf;
174
175         /* If it's an empty path name, fail in the usual POSIX way. */
176         if (*name == '\0') {
177                 errno = ENOENT;
178                 return (-1);
179         }
180
181         cur = alloca(strlen(path) + 1);
182         if (cur == NULL) {
183                 errno = ENOMEM;
184                 return (-1);
185         }
186         strcpy(cur, path);
187         while ((p = strsep(&cur, ":")) != NULL) {
188                 /*
189                  * It's a SHELL path -- double, leading and trailing colons
190                  * mean the current directory.
191                  */
192                 if (*p == '\0') {
193                         p = ".";
194                         lp = 1;
195                 } else
196                         lp = strlen(p);
197                 ln = strlen(name);
198
199                 /*
200                  * If the path is too long complain.  This is a possible
201                  * security issue; given a way to make the path too long
202                  * the user may execute the wrong program.
203                  */
204                 if (lp + ln + 2 > sizeof(buf)) {
205                         (void)_write(STDERR_FILENO, "execvP: ", 8);
206                         (void)_write(STDERR_FILENO, p, lp);
207                         (void)_write(STDERR_FILENO, ": path too long\n",
208                             16);
209                         continue;
210                 }
211                 bcopy(p, buf, lp);
212                 buf[lp] = '/';
213                 bcopy(name, buf + lp + 1, ln);
214                 buf[lp + ln + 1] = '\0';
215
216 retry:          (void)_execve(bp, argv, environ);
217                 switch (errno) {
218                 case E2BIG:
219                         goto done;
220                 case ELOOP:
221                 case ENAMETOOLONG:
222                 case ENOENT:
223                         break;
224                 case ENOEXEC:
225                         for (cnt = 0; argv[cnt]; ++cnt)
226                                 ;
227                         memp = alloca((cnt + 2) * sizeof(char *));
228                         if (memp == NULL) {
229                                 /* errno = ENOMEM; XXX override ENOEXEC? */
230                                 goto done;
231                         }
232                         memp[0] = "sh";
233                         memp[1] = bp;
234                         bcopy(argv + 1, memp + 2, cnt * sizeof(char *));
235                         (void)_execve(_PATH_BSHELL, memp, environ);
236                         goto done;
237                 case ENOMEM:
238                         goto done;
239                 case ENOTDIR:
240                         break;
241                 case ETXTBSY:
242                         /*
243                          * We used to retry here, but sh(1) doesn't.
244                          */
245                         goto done;
246                 default:
247                         /*
248                          * EACCES may be for an inaccessible directory or
249                          * a non-executable file.  Call stat() to decide
250                          * which.  This also handles ambiguities for EFAULT
251                          * and EIO, and undocumented errors like ESTALE.
252                          * We hope that the race for a stat() is unimportant.
253                          */
254                         save_errno = errno;
255                         if (stat(bp, &sb) != 0)
256                                 break;
257                         if (save_errno == EACCES) {
258                                 eacces = 1;
259                                 continue;
260                         }
261                         errno = save_errno;
262                         goto done;
263                 }
264         }
265         if (eacces)
266                 errno = EACCES;
267         else
268                 errno = ENOENT;
269 done:
270         return (-1);
271 }