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