[project @ 1998-12-02 13:17:09 by simonm]
[ghc-hetmet.git] / ghc / lib / posix / cbits / execvpe.c
1 /*
2 %
3 % (c) The GRASP/AQUA Project, Glasgow University, 1995-1996
4 %
5 \subsection[posix.lc]{executeFile Runtime Support}
6
7 \begin{code}
8 */
9 #if !defined(_AIX)
10 #define NON_POSIX_SOURCE
11 #endif
12
13 #include "Rts.h"
14 #include "libposix.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, etxtbsy;
59     char *bp, *cur, *path, *buf;
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     eacces = etxtbsy = 0;
89     while (cur != NULL) {
90         p = cur;
91         if ((cur = strchr(cur, ':')) != NULL)
92             *cur++ = '\0';
93
94         /*
95          * It's a SHELL path -- double, leading and trailing colons mean the current
96          * directory.
97          */
98         if (!*p) {
99             p = ".";
100             lp = 1;
101         } else
102             lp = strlen(p);
103         ln = strlen(name);
104
105         memcpy(buf, p, lp);
106         buf[lp] = '/';
107         memcpy(buf + lp + 1, name, ln);
108         buf[lp + ln + 1] = '\0';
109
110       retry:
111         (void) execve(bp, argv, envp);
112         switch (errno) {
113         case EACCES:
114             eacces = 1;
115             break;
116         case ENOENT:
117             break;
118         case ENOEXEC:
119             {
120                 register size_t cnt;
121                 register char **ap;
122
123                 for (cnt = 0, ap = (char **) argv; *ap; ++ap, ++cnt)
124                     ;
125                 if ((ap = malloc((cnt + 2) * sizeof(char *))) != NULL) {
126                     memcpy(ap + 2, argv + 1, cnt * sizeof(char *));
127
128                     ap[0] = "sh";
129                     ap[1] = bp;
130                     (void) execve("/bin/sh", ap, envp);
131                     free(ap);
132                 }
133                 goto done;
134             }
135         case ETXTBSY:
136             if (etxtbsy < 3)
137                 (void) sleep(++etxtbsy);
138             goto retry;
139         default:
140             goto done;
141         }
142     }
143     if (eacces)
144         errno = EACCES;
145     else if (!errno)
146         errno = ENOENT;
147   done:
148     if (path)
149         free(path);
150     if (buf)
151         free(buf);
152     return (-1);
153 }