Commit | Line | Data |
---|---|---|
468a338d KB |
1 | /*- |
2 | * Copyright (c) 1991 The Regents of the University of California. | |
3 | * All rights reserved. | |
4 | * | |
5 | * %sccs.include.redist.c% | |
6 | */ | |
7 | ||
2ce81398 | 8 | #if defined(LIBC_SCCS) && !defined(lint) |
98c3efdf | 9 | static char sccsid[] = "@(#)exec.c 5.10 (Berkeley) %G%"; |
468a338d | 10 | #endif /* LIBC_SCCS and not lint */ |
b8f253e8 | 11 | |
468a338d KB |
12 | #include <sys/param.h> |
13 | #include <sys/types.h> | |
a69e788c | 14 | #include <errno.h> |
468a338d | 15 | #include <unistd.h> |
c98aae91 | 16 | #include <stdlib.h> |
3a9c73cc KB |
17 | #include <string.h> |
18 | #include <stdio.h> | |
19 | #include <paths.h> | |
20 | ||
e0cd943a | 21 | #if __STDC__ |
468a338d | 22 | #include <stdarg.h> |
e0cd943a DS |
23 | #else |
24 | #include <varargs.h> | |
25 | #endif | |
468a338d KB |
26 | |
27 | extern char **environ; | |
28 | ||
e0cd943a DS |
29 | static char ** |
30 | buildargv(ap, arg, envpp) | |
31 | va_list ap; | |
32 | const char *arg; | |
33 | char ***envpp; | |
468a338d | 34 | { |
98c3efdf KB |
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 | } | |
468a338d KB |
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 | } | |
3a9c73cc | 56 | /* Get environment pointer if user supposed to provide one. */ |
468a338d KB |
57 | if (envpp) |
58 | *envpp = va_arg(ap, char **); | |
98c3efdf | 59 | return (argv); |
468a338d KB |
60 | } |
61 | ||
e0cd943a DS |
62 | int |
63 | #if __STDC__ | |
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 | |
468a338d KB |
71 | { |
72 | va_list ap; | |
73 | int sverrno; | |
74 | char **argv; | |
75 | ||
e0cd943a | 76 | #if __STDC__ |
468a338d | 77 | va_start(ap, arg); |
e0cd943a DS |
78 | #else |
79 | va_start(ap); | |
80 | #endif | |
98c3efdf | 81 | if (argv = buildargv(ap, arg, NULL)) |
468a338d KB |
82 | (void)execve(name, argv, environ); |
83 | va_end(ap); | |
84 | sverrno = errno; | |
85 | free(argv); | |
86 | errno = sverrno; | |
98c3efdf | 87 | return (-1); |
468a338d KB |
88 | } |
89 | ||
e0cd943a DS |
90 | int |
91 | #if __STDC__ | |
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 | |
468a338d KB |
99 | { |
100 | va_list ap; | |
101 | int sverrno; | |
102 | char **argv, **envp; | |
103 | ||
e0cd943a | 104 | #if __STDC__ |
468a338d | 105 | va_start(ap, arg); |
e0cd943a DS |
106 | #else |
107 | va_start(ap); | |
108 | #endif | |
468a338d KB |
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; | |
98c3efdf | 115 | return (-1); |
468a338d KB |
116 | } |
117 | ||
e0cd943a DS |
118 | int |
119 | #if __STDC__ | |
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 | |
468a338d KB |
127 | { |
128 | va_list ap; | |
129 | int sverrno; | |
130 | char **argv; | |
a69e788c | 131 | |
e0cd943a | 132 | #if __STDC__ |
468a338d | 133 | va_start(ap, arg); |
e0cd943a DS |
134 | #else |
135 | va_start(ap); | |
136 | #endif | |
98c3efdf | 137 | if (argv = buildargv(ap, arg, NULL)) |
468a338d KB |
138 | (void)execvp(name, argv); |
139 | va_end(ap); | |
140 | sverrno = errno; | |
141 | free(argv); | |
142 | errno = sverrno; | |
98c3efdf | 143 | return (-1); |
468a338d | 144 | } |
a69e788c | 145 | |
e0cd943a DS |
146 | int |
147 | execv(name, argv) | |
148 | const char *name; | |
149 | char * const *argv; | |
a69e788c | 150 | { |
468a338d | 151 | (void)execve(name, argv, environ); |
98c3efdf | 152 | return (-1); |
a69e788c BJ |
153 | } |
154 | ||
e0cd943a DS |
155 | int |
156 | execvp(name, argv) | |
157 | const char *name; | |
158 | char * const *argv; | |
a69e788c | 159 | { |
98c3efdf KB |
160 | static int memsize; |
161 | static char **memp; | |
162 | register int cnt, lp, ln; | |
468a338d KB |
163 | register char *p; |
164 | int eacces, etxtbsy; | |
57047b12 | 165 | char *bp, *cur, *path, buf[MAXPATHLEN]; |
468a338d KB |
166 | |
167 | /* If it's an absolute or relative path name, it's easy. */ | |
168 | if (index(name, '/')) { | |
57047b12 KB |
169 | bp = (char *)name; |
170 | cur = path = NULL; | |
171 | goto retry; | |
468a338d | 172 | } |
57047b12 | 173 | bp = buf; |
468a338d KB |
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 | */ | |
3a9c73cc | 186 | if (!*p) { |
468a338d | 187 | p = "."; |
3a9c73cc KB |
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'; | |
468a338d | 208 | |
57047b12 | 209 | retry: (void)execve(bp, argv, environ); |
a69e788c | 210 | switch(errno) { |
468a338d KB |
211 | case EACCES: |
212 | eacces = 1; | |
213 | break; | |
214 | case ENOENT: | |
215 | break; | |
98c3efdf KB |
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 | } | |
a69e788c | 224 | } |
98c3efdf KB |
225 | memp[0] = "sh"; |
226 | memp[1] = bp; | |
227 | bcopy(argv + 1, memp + 2, cnt * sizeof(char *)); | |
228 | (void)execve(_PATH_BSHELL, memp, environ); | |
468a338d | 229 | goto done; |
a69e788c | 230 | case ETXTBSY: |
468a338d KB |
231 | if (etxtbsy < 3) |
232 | (void)sleep(++etxtbsy); | |
a69e788c | 233 | goto retry; |
468a338d KB |
234 | default: |
235 | goto done; | |
a69e788c | 236 | } |
468a338d | 237 | } |
a69e788c BJ |
238 | if (eacces) |
239 | errno = EACCES; | |
468a338d KB |
240 | else if (!errno) |
241 | errno = ENOENT; | |
57047b12 KB |
242 | done: if (path) |
243 | free(path); | |
98c3efdf | 244 | return (-1); |
a69e788c | 245 | } |