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