declare blkcmp() static
[haskell-directory.git] / cbits / execvpe.c
1 /* -----------------------------------------------------------------------------
2    (c) The University of Glasgow 1995-2004
3
4    Our low-level exec() variant.
5    -------------------------------------------------------------------------- */
6 #include "HsBase.h"
7
8 #if !defined(mingw32_HOST_OS) /* to the end */
9
10 /* Evidently non-Posix. */
11 /* #include "PosixSource.h" */
12
13 #include <unistd.h>
14 #include <sys/time.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <errno.h>
18
19 /*
20  * We want the search semantics of execvp, but we want to provide our
21  * own environment, like execve.  The following copyright applies to
22  * this code, as it is a derivative of execvp:
23  *-
24  * Copyright (c) 1991 The Regents of the University of California.
25  * All rights reserved.
26  *
27  * Redistribution and use in source and binary forms, with or without
28  * modification, are permitted provided that the following conditions
29  * are met:
30  * 1. Redistributions of source code must retain the above copyright
31  *    notice, this list of conditions and the following disclaimer.
32  * 2. Redistributions in binary form must reproduce the above copyright
33  *    notice, this list of conditions and the following disclaimer in the
34  *    documentation and/or other materials provided with the distribution.
35  * 3. All advertising materials mentioning features or use of this software
36  *    must display the following acknowledgement:
37  *      This product includes software developed by the University of
38  *      California, Berkeley and its contributors.
39  * 4. Neither the name of the University nor the names of its contributors
40  *    may be used to endorse or promote products derived from this software
41  *    without specific prior written permission.
42  *
43  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
44  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
45  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
47  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
48  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
49  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
50  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
51  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
52  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
53  * SUCH DAMAGE.
54  */
55
56 int
57 execvpe(char *name, char *const argv[], char **envp)
58 {
59     register int lp, ln;
60     register char *p;
61     int eacces=0, etxtbsy=0;
62     char *bp, *cur, *path, *buf = 0;
63
64     /* If it's an absolute or relative path name, it's easy. */
65     if (strchr(name, '/')) {
66         bp = (char *) name;
67         cur = path = buf = NULL;
68         goto retry;
69     }
70
71     /* Get the path we're searching. */
72     if (!(path = getenv("PATH"))) {
73 #ifdef HAVE_CONFSTR
74         ln = confstr(_CS_PATH, NULL, 0);
75         if ((cur = path = malloc(ln + 1)) != NULL) {
76             path[0] = ':';
77             (void) confstr (_CS_PATH, path + 1, ln);
78         }
79 #else
80         if ((cur = path = malloc(1 + 1)) != NULL) {
81             path[0] = ':';
82             path[1] = '\0';
83         }
84 #endif
85     } else
86         cur = path = strdup(path);
87
88     if (path == NULL || (bp = buf = malloc(strlen(path)+strlen(name)+2)) == NULL)
89         goto done;
90
91     while (cur != NULL) {
92         p = cur;
93         if ((cur = strchr(cur, ':')) != NULL)
94             *cur++ = '\0';
95
96         /*
97          * It's a SHELL path -- double, leading and trailing colons mean the current
98          * directory.
99          */
100         if (!*p) {
101             p = ".";
102             lp = 1;
103         } else
104             lp = strlen(p);
105         ln = strlen(name);
106
107         memcpy(buf, p, lp);
108         buf[lp] = '/';
109         memcpy(buf + lp + 1, name, ln);
110         buf[lp + ln + 1] = '\0';
111
112       retry:
113         (void) execve(bp, argv, envp);
114         switch (errno) {
115         case EACCES:
116             eacces = 1;
117             break;
118         case ENOENT:
119             break;
120         case ENOEXEC:
121             {
122                 register size_t cnt;
123                 register char **ap;
124
125                 for (cnt = 0, ap = (char **) argv; *ap; ++ap, ++cnt)
126                     ;
127                 if ((ap = malloc((cnt + 2) * sizeof(char *))) != NULL) {
128                     memcpy(ap + 2, argv + 1, cnt * sizeof(char *));
129
130                     ap[0] = "sh";
131                     ap[1] = bp;
132                     (void) execve("/bin/sh", ap, envp);
133                     free(ap);
134                 }
135                 goto done;
136             }
137         case ETXTBSY:
138             if (etxtbsy < 3)
139                 (void) sleep(++etxtbsy);
140             goto retry;
141         default:
142             goto done;
143         }
144     }
145     if (eacces)
146         errno = EACCES;
147     else if (!errno)
148         errno = ENOENT;
149   done:
150     if (path)
151         free(path);
152     if (buf)
153         free(buf);
154     return (-1);
155 }
156
157
158 /* Copied verbatim from ghc/lib/std/cbits/system.c. */
159 void pPrPr_disableITimers (void)
160 {
161 #  ifdef HAVE_SETITIMER
162    /* Reset the itimers in the child, so it doesn't get plagued
163     * by SIGVTALRM interrupts.
164     */
165    struct timeval tv_null = { 0, 0 };
166    struct itimerval itv;
167    itv.it_interval = tv_null;
168    itv.it_value = tv_null;
169    setitimer(ITIMER_REAL, &itv, NULL);
170    setitimer(ITIMER_VIRTUAL, &itv, NULL);
171    setitimer(ITIMER_PROF, &itv, NULL);
172 #  endif
173 }
174
175 #endif