Add SIGCKPT support to tcsh's built-in kill.
[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  * 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  * $FreeBSD: src/lib/libc/gen/exec.c,v 1.15 2000/01/27 23:06:14 jasone Exp $
34  * $DragonFly: src/lib/libc/gen/exec.c,v 1.2 2003/06/17 04:26:42 dillon Exp $
35  *
36  * @(#)exec.c   8.1 (Berkeley) 6/4/93
37  * $FreeBSD: src/lib/libc/gen/exec.c,v 1.15 2000/01/27 23:06:14 jasone Exp $
38  */
39
40 #include <sys/param.h>
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <errno.h>
44 #include <unistd.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <stdio.h>
48 #include <paths.h>
49
50 #if __STDC__
51 #include <stdarg.h>
52 #else
53 #include <varargs.h>
54 #endif
55
56 extern char **environ;
57
58 int
59 #if __STDC__
60 execl(const char *name, const char *arg, ...)
61 #else
62 execl(name, arg, va_alist)
63         const char *name;
64         const char *arg;
65         va_dcl
66 #endif
67 {
68         va_list ap;
69         char **argv;
70         int n;
71
72 #if __STDC__
73         va_start(ap, arg);
74 #else
75         va_start(ap);
76 #endif
77         n = 1;
78         while (va_arg(ap, char *) != NULL)
79                 n++;
80         va_end(ap);
81         argv = alloca((n + 1) * sizeof(*argv));
82         if (argv == NULL) {
83                 errno = ENOMEM;
84                 return (-1);
85         }
86 #if __STDC__
87         va_start(ap, arg);
88 #else
89         va_start(ap);
90 #endif
91         n = 1;
92         argv[0] = (char *)arg;
93         while ((argv[n] = va_arg(ap, char *)) != NULL)
94                 n++;
95         va_end(ap);
96         return (execve(name, argv, environ));
97 }
98
99 int
100 #if __STDC__
101 execle(const char *name, const char *arg, ...)
102 #else
103 execle(name, arg, va_alist)
104         const char *name;
105         const char *arg;
106         va_dcl
107 #endif
108 {
109         va_list ap;
110         char **argv, **envp;
111         int n;
112
113 #if __STDC__
114         va_start(ap, arg);
115 #else
116         va_start(ap);
117 #endif
118         n = 1;
119         while (va_arg(ap, char *) != NULL)
120                 n++;
121         va_end(ap);
122         argv = alloca((n + 1) * sizeof(*argv));
123         if (argv == NULL) {
124                 errno = ENOMEM;
125                 return (-1);
126         }
127 #if __STDC__
128         va_start(ap, arg);
129 #else
130         va_start(ap);
131 #endif
132         n = 1;
133         argv[0] = (char *)arg;
134         while ((argv[n] = va_arg(ap, char *)) != NULL)
135                 n++;
136         envp = va_arg(ap, char **);
137         va_end(ap);
138         return (execve(name, argv, envp));
139 }
140
141 int
142 #if __STDC__
143 execlp(const char *name, const char *arg, ...)
144 #else
145 execlp(name, arg, va_alist)
146         const char *name;
147         const char *arg;
148         va_dcl
149 #endif
150 {
151         va_list ap;
152         int sverrno;
153         char **argv;
154         int n;
155
156 #if __STDC__
157         va_start(ap, arg);
158 #else
159         va_start(ap);
160 #endif
161         n = 1;
162         while (va_arg(ap, char *) != NULL)
163                 n++;
164         va_end(ap);
165         argv = alloca((n + 1) * sizeof(*argv));
166         if (argv == NULL) {
167                 errno = ENOMEM;
168                 return (-1);
169         }
170 #if __STDC__
171         va_start(ap, arg);
172 #else
173         va_start(ap);
174 #endif
175         n = 1;
176         argv[0] = (char *)arg;
177         while ((argv[n] = va_arg(ap, char *)) != NULL)
178                 n++;
179         va_end(ap);
180         return (execvp(name, argv));
181 }
182
183 int
184 execv(name, argv)
185         const char *name;
186         char * const *argv;
187 {
188         (void)execve(name, argv, environ);
189         return (-1);
190 }
191
192 int
193 execvp(name, argv)
194         const char *name;
195         char * const *argv;
196 {
197         char **memp;
198         register int cnt, lp, ln;
199         register char *p;
200         int eacces, save_errno;
201         char *bp, *cur, *path, buf[MAXPATHLEN];
202         struct stat sb;
203
204         eacces = 0;
205
206         /* If it's an absolute or relative path name, it's easy. */
207         if (index(name, '/')) {
208                 bp = (char *)name;
209                 cur = path = NULL;
210                 goto retry;
211         }
212         bp = buf;
213
214         /* If it's an empty path name, fail in the usual POSIX way. */
215         if (*name == '\0') {
216                 errno = ENOENT;
217                 return (-1);
218         }
219
220         /* Get the path we're searching. */
221         if (!(path = getenv("PATH")))
222                 path = _PATH_DEFPATH;
223         cur = alloca(strlen(path) + 1);
224         if (cur == NULL) {
225                 errno = ENOMEM;
226                 return (-1);
227         }
228         strcpy(cur, path);
229         path = cur;
230         while ( (p = strsep(&cur, ":")) ) {
231                 /*
232                  * It's a SHELL path -- double, leading and trailing colons
233                  * mean the current directory.
234                  */
235                 if (!*p) {
236                         p = ".";
237                         lp = 1;
238                 } else
239                         lp = strlen(p);
240                 ln = strlen(name);
241
242                 /*
243                  * If the path is too long complain.  This is a possible
244                  * security issue; given a way to make the path too long
245                  * the user may execute the wrong program.
246                  */
247                 if (lp + ln + 2 > sizeof(buf)) {
248                         (void)_write(STDERR_FILENO, "execvp: ", 8);
249                         (void)_write(STDERR_FILENO, p, lp);
250                         (void)_write(STDERR_FILENO, ": path too long\n",
251                             16);
252                         continue;
253                 }
254                 bcopy(p, buf, lp);
255                 buf[lp] = '/';
256                 bcopy(name, buf + lp + 1, ln);
257                 buf[lp + ln + 1] = '\0';
258
259 retry:          (void)execve(bp, argv, environ);
260                 switch(errno) {
261                 case E2BIG:
262                         goto done;
263                 case ELOOP:
264                 case ENAMETOOLONG:
265                 case ENOENT:
266                         break;
267                 case ENOEXEC:
268                         for (cnt = 0; argv[cnt]; ++cnt)
269                                 ;
270                         memp = alloca((cnt + 2) * sizeof(char *));
271                         if (memp == NULL) {
272                                 /* errno = ENOMEM; XXX override ENOEXEC? */
273                                 goto done;
274                         }
275                         memp[0] = "sh";
276                         memp[1] = bp;
277                         bcopy(argv + 1, memp + 2, cnt * sizeof(char *));
278                         (void)execve(_PATH_BSHELL, memp, environ);
279                         goto done;
280                 case ENOMEM:
281                         goto done;
282                 case ENOTDIR:
283                         break;
284                 case ETXTBSY:
285                         /*
286                          * We used to retry here, but sh(1) doesn't.
287                          */
288                         goto done;
289                 default:
290                         /*
291                          * EACCES may be for an inaccessible directory or
292                          * a non-executable file.  Call stat() to decide
293                          * which.  This also handles ambiguities for EFAULT
294                          * and EIO, and undocumented errors like ESTALE.
295                          * We hope that the race for a stat() is unimportant.
296                          */
297                         save_errno = errno;
298                         if (stat(bp, &sb) != 0)
299                                 break;
300                         if (save_errno == EACCES) {
301                                 eacces = 1;
302                                 continue;
303                         }
304                         errno = save_errno;
305                         goto done;
306                 }
307         }
308         if (eacces)
309                 errno = EACCES;
310         else
311                 errno = ENOENT;
312 done:
313         return (-1);
314 }