xref: /csrg-svn/lib/libc/gen/exec.c (revision 46592)
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.5 (Berkeley) 02/23/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 #include <stdarg.h>
18 #include <string.h>
19 #include <stdio.h>
20 #include <paths.h>
21 
22 extern char **environ;
23 
24 static char **buildargv(va_list ap, const char *arg, char ***envpp)
25 {
26 	register size_t max, off;
27 	register char **argv;
28 
29 	for (off = max = 0;; ++off) {
30 		if (off >= max) {
31 			max += 50;	/* Starts out at 0. */
32 			max *= 2;	/* Ramp up fast. */
33 			if (!(argv = realloc(argv, max * sizeof(char *))))
34 				return(NULL);
35 			if (off == 0) {
36 				argv[0] = (char *)arg;
37 				off = 1;
38 			}
39 		}
40 		if (!(argv[off] = va_arg(ap, char *)))
41 			break;
42 	}
43 	/* Get environment pointer if need user supposed to provide one. */
44 	if (envpp)
45 		*envpp = va_arg(ap, char **);
46 	return(argv);
47 }
48 
49 int execl(const char *name, const char *arg, ...)
50 {
51 	va_list ap;
52 	int sverrno;
53 	char **argv;
54 
55 	va_start(ap, arg);
56 	if (argv = buildargv(ap, arg, (char ***)NULL))
57 		(void)execve(name, argv, environ);
58 	va_end(ap);
59 	sverrno = errno;
60 	free(argv);
61 	errno = sverrno;
62 	return(-1);
63 }
64 
65 int execle(const char *name, const char *arg, ...)
66 {
67 	va_list ap;
68 	int sverrno;
69 	char **argv, **envp;
70 
71 	va_start(ap, arg);
72 	if (argv = buildargv(ap, arg, &envp))
73 		(void)execve(name, argv, envp);
74 	va_end(ap);
75 	sverrno = errno;
76 	free(argv);
77 	errno = sverrno;
78 	return(-1);
79 }
80 
81 int execlp(const char *name, const char *arg, ...)
82 {
83 	va_list ap;
84 	int sverrno;
85 	char **argv;
86 
87 	va_start(ap, arg);
88 	if (argv = buildargv(ap, arg, (char ***)NULL))
89 		(void)execvp(name, argv);
90 	va_end(ap);
91 	sverrno = errno;
92 	free(argv);
93 	errno = sverrno;
94 	return(-1);
95 }
96 
97 int execv(const char *name, char * const *argv)
98 {
99 	(void)execve(name, argv, environ);
100 	return(-1);
101 }
102 
103 int execvp(const char *name, char * const *argv)
104 {
105 	register char *p;
106 	int eacces, etxtbsy;
107 	char *cur, *path, buf[MAXPATHLEN];
108 
109 	/* If it's an absolute or relative path name, it's easy. */
110 	if (index(name, '/')) {
111 		(void)execve(name, argv, environ);
112 		return(-1);
113 	}
114 
115 	/* Get the path we're searching. */
116 	if (!(path = getenv("PATH")))
117 		path = _PATH_DEFPATH;
118 	cur = path = strdup(path);
119 
120 	eacces = etxtbsy = 0;
121 	while (p = strsep(&cur, ":")) {
122 		/*
123 		 * It's a SHELL path -- double, leading and trailing colons
124 		 * mean the current directory.
125 		 */
126 		if (!*p)
127 			p = ".";
128 		(void)snprintf(buf, sizeof(buf), "%s/%s", p, name);
129 
130 retry:		(void)execve(buf, argv, environ);
131 		switch(errno) {
132 		case EACCES:
133 			eacces = 1;
134 			break;
135 		case ENOENT:
136 			break;
137 		case ENOEXEC: {
138 			register size_t cnt;
139 			register char **ap;
140 
141 			for (cnt = 0, ap = (char **)argv; *ap; ++ap, ++cnt);
142 			if (ap = malloc((cnt + 2) * sizeof(char *))) {
143 				bcopy(argv, ap + 2, cnt * sizeof(char *));
144 				ap[0] = "sh";
145 				ap[1] = buf;
146 				(void)execve(_PATH_BSHELL, ap, environ);
147 				free(ap);
148 			}
149 			goto done;
150 		}
151 		case ETXTBSY:
152 			if (etxtbsy < 3)
153 				(void)sleep(++etxtbsy);
154 			goto retry;
155 		default:
156 			goto done;
157 		}
158 	}
159 	if (eacces)
160 		errno = EACCES;
161 	else if (!errno)
162 		errno = ENOENT;
163 done:	free(path);
164 	return(-1);
165 }
166