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