1 /*-
2 * Copyright (c) 1991, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 */
7
8 #if defined(LIBC_SCCS) && !defined(lint)
9 static char sccsid[] = "@(#)exec.c 8.1 (Berkeley) 06/04/93";
10 #endif /* LIBC_SCCS and not lint */
11
12 #include <sys/param.h>
13 #include <sys/types.h>
14 #include <errno.h>
15 #include <unistd.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <stdio.h>
19 #include <paths.h>
20
21 #if __STDC__
22 #include <stdarg.h>
23 #else
24 #include <varargs.h>
25 #endif
26
27 extern char **environ;
28
29 static char **
buildargv(ap,arg,envpp)30 buildargv(ap, arg, envpp)
31 va_list ap;
32 const char *arg;
33 char ***envpp;
34 {
35 static int memsize;
36 static char **argv;
37 register int off;
38
39 argv = NULL;
40 for (off = 0;; ++off) {
41 if (off >= memsize) {
42 memsize += 50; /* Starts out at 0. */
43 memsize *= 2; /* Ramp up fast. */
44 if (!(argv = realloc(argv, memsize * sizeof(char *)))) {
45 memsize = 0;
46 return (NULL);
47 }
48 if (off == 0) {
49 argv[0] = (char *)arg;
50 off = 1;
51 }
52 }
53 if (!(argv[off] = va_arg(ap, char *)))
54 break;
55 }
56 /* Get environment pointer if user supposed to provide one. */
57 if (envpp)
58 *envpp = va_arg(ap, char **);
59 return (argv);
60 }
61
62 int
63 #if __STDC__
execl(const char * name,const char * arg,...)64 execl(const char *name, const char *arg, ...)
65 #else
66 execl(name, arg, va_alist)
67 const char *name;
68 const char *arg;
69 va_dcl
70 #endif
71 {
72 va_list ap;
73 int sverrno;
74 char **argv;
75
76 #if __STDC__
77 va_start(ap, arg);
78 #else
79 va_start(ap);
80 #endif
81 if (argv = buildargv(ap, arg, NULL))
82 (void)execve(name, argv, environ);
83 va_end(ap);
84 sverrno = errno;
85 free(argv);
86 errno = sverrno;
87 return (-1);
88 }
89
90 int
91 #if __STDC__
execle(const char * name,const char * arg,...)92 execle(const char *name, const char *arg, ...)
93 #else
94 execle(name, arg, va_alist)
95 const char *name;
96 const char *arg;
97 va_dcl
98 #endif
99 {
100 va_list ap;
101 int sverrno;
102 char **argv, **envp;
103
104 #if __STDC__
105 va_start(ap, arg);
106 #else
107 va_start(ap);
108 #endif
109 if (argv = buildargv(ap, arg, &envp))
110 (void)execve(name, argv, envp);
111 va_end(ap);
112 sverrno = errno;
113 free(argv);
114 errno = sverrno;
115 return (-1);
116 }
117
118 int
119 #if __STDC__
execlp(const char * name,const char * arg,...)120 execlp(const char *name, const char *arg, ...)
121 #else
122 execlp(name, arg, va_alist)
123 const char *name;
124 const char *arg;
125 va_dcl
126 #endif
127 {
128 va_list ap;
129 int sverrno;
130 char **argv;
131
132 #if __STDC__
133 va_start(ap, arg);
134 #else
135 va_start(ap);
136 #endif
137 if (argv = buildargv(ap, arg, NULL))
138 (void)execvp(name, argv);
139 va_end(ap);
140 sverrno = errno;
141 free(argv);
142 errno = sverrno;
143 return (-1);
144 }
145
146 int
execv(name,argv)147 execv(name, argv)
148 const char *name;
149 char * const *argv;
150 {
151 (void)execve(name, argv, environ);
152 return (-1);
153 }
154
155 int
execvp(name,argv)156 execvp(name, argv)
157 const char *name;
158 char * const *argv;
159 {
160 static int memsize;
161 static char **memp;
162 register int cnt, lp, ln;
163 register char *p;
164 int eacces, etxtbsy;
165 char *bp, *cur, *path, buf[MAXPATHLEN];
166
167 /* If it's an absolute or relative path name, it's easy. */
168 if (index(name, '/')) {
169 bp = (char *)name;
170 cur = path = NULL;
171 goto retry;
172 }
173 bp = buf;
174
175 /* Get the path we're searching. */
176 if (!(path = getenv("PATH")))
177 path = _PATH_DEFPATH;
178 cur = path = strdup(path);
179
180 eacces = etxtbsy = 0;
181 while (p = strsep(&cur, ":")) {
182 /*
183 * It's a SHELL path -- double, leading and trailing colons
184 * mean the current directory.
185 */
186 if (!*p) {
187 p = ".";
188 lp = 1;
189 } else
190 lp = strlen(p);
191 ln = strlen(name);
192
193 /*
194 * If the path is too long complain. This is a possible
195 * security issue; given a way to make the path too long
196 * the user may execute the wrong program.
197 */
198 if (lp + ln + 2 > sizeof(buf)) {
199 (void)write(STDERR_FILENO, "execvp: ", 8);
200 (void)write(STDERR_FILENO, p, lp);
201 (void)write(STDERR_FILENO, ": path too long\n", 16);
202 continue;
203 }
204 bcopy(p, buf, lp);
205 buf[lp] = '/';
206 bcopy(name, buf + lp + 1, ln);
207 buf[lp + ln + 1] = '\0';
208
209 retry: (void)execve(bp, argv, environ);
210 switch(errno) {
211 case EACCES:
212 eacces = 1;
213 break;
214 case ENOENT:
215 break;
216 case ENOEXEC:
217 for (cnt = 0; argv[cnt]; ++cnt);
218 if ((cnt + 2) * sizeof(char *) > memsize) {
219 memsize = (cnt + 2) * sizeof(char *);
220 if ((memp = realloc(memp, memsize)) == NULL) {
221 memsize = 0;
222 goto done;
223 }
224 }
225 memp[0] = "sh";
226 memp[1] = bp;
227 bcopy(argv + 1, memp + 2, cnt * sizeof(char *));
228 (void)execve(_PATH_BSHELL, memp, environ);
229 goto done;
230 case ETXTBSY:
231 if (etxtbsy < 3)
232 (void)sleep(++etxtbsy);
233 goto retry;
234 default:
235 goto done;
236 }
237 }
238 if (eacces)
239 errno = EACCES;
240 else if (!errno)
241 errno = ENOENT;
242 done: if (path)
243 free(path);
244 return (-1);
245 }
246