xref: /freebsd/crypto/heimdal/lib/roken/simple_exec.c (revision 1e413cf93298b5b97441a21d9a50fdcd0ee9945e)
1 /*
2  * Copyright (c) 1998 - 2001 Kungliga Tekniska H�gskolan
3  * (Royal Institute of Technology, Stockholm, Sweden).
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * 3. Neither the name of the Institute nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #ifdef HAVE_CONFIG_H
35 #include <config.h>
36 RCSID("$Id: simple_exec.c,v 1.10 2001/06/21 03:38:03 assar Exp $");
37 #endif
38 
39 #include <stdarg.h>
40 #include <stdlib.h>
41 #ifdef HAVE_SYS_TYPES_H
42 #include <sys/types.h>
43 #endif
44 #ifdef HAVE_SYS_WAIT_H
45 #include <sys/wait.h>
46 #endif
47 #ifdef HAVE_UNISTD_H
48 #include <unistd.h>
49 #endif
50 #include <errno.h>
51 
52 #include <roken.h>
53 
54 #define EX_NOEXEC	126
55 #define EX_NOTFOUND	127
56 
57 /* return values:
58    -1   on `unspecified' system errors
59    -2   on fork failures
60    -3   on waitpid errors
61    0-   is return value from subprocess
62    126  if the program couldn't be executed
63    127  if the program couldn't be found
64    128- is 128 + signal that killed subprocess
65    */
66 
67 int
68 wait_for_process(pid_t pid)
69 {
70     while(1) {
71 	int status;
72 
73 	while(waitpid(pid, &status, 0) < 0)
74 	    if (errno != EINTR)
75 		return -3;
76 	if(WIFSTOPPED(status))
77 	    continue;
78 	if(WIFEXITED(status))
79 	    return WEXITSTATUS(status);
80 	if(WIFSIGNALED(status))
81 	    return WTERMSIG(status) + 128;
82     }
83 }
84 
85 int
86 pipe_execv(FILE **stdin_fd, FILE **stdout_fd, FILE **stderr_fd,
87 	   const char *file, ...)
88 {
89     int in_fd[2], out_fd[2], err_fd[2];
90     pid_t pid;
91     va_list ap;
92     char **argv;
93 
94     if(stdin_fd != NULL)
95 	pipe(in_fd);
96     if(stdout_fd != NULL)
97 	pipe(out_fd);
98     if(stderr_fd != NULL)
99 	pipe(err_fd);
100     pid = fork();
101     switch(pid) {
102     case 0:
103 	va_start(ap, file);
104 	argv = vstrcollect(&ap);
105 	va_end(ap);
106 	if(argv == NULL)
107 	    exit(-1);
108 
109 	/* close pipes we're not interested in */
110 	if(stdin_fd != NULL)
111 	    close(in_fd[1]);
112 	if(stdout_fd != NULL)
113 	    close(out_fd[0]);
114 	if(stderr_fd != NULL)
115 	    close(err_fd[0]);
116 
117 	/* pipe everything caller doesn't care about to /dev/null */
118 	if(stdin_fd == NULL)
119 	    in_fd[0] = open(_PATH_DEVNULL, O_RDONLY);
120 	if(stdout_fd == NULL)
121 	    out_fd[1] = open(_PATH_DEVNULL, O_WRONLY);
122 	if(stderr_fd == NULL)
123 	    err_fd[1] = open(_PATH_DEVNULL, O_WRONLY);
124 
125 	/* move to proper descriptors */
126 	if(in_fd[0] != STDIN_FILENO) {
127 	    dup2(in_fd[0], STDIN_FILENO);
128 	    close(in_fd[0]);
129 	}
130 	if(out_fd[1] != STDOUT_FILENO) {
131 	    dup2(out_fd[1], STDOUT_FILENO);
132 	    close(out_fd[1]);
133 	}
134 	if(err_fd[1] != STDERR_FILENO) {
135 	    dup2(err_fd[1], STDERR_FILENO);
136 	    close(err_fd[1]);
137 	}
138 
139 	execv(file, argv);
140 	exit((errno == ENOENT) ? EX_NOTFOUND : EX_NOEXEC);
141     case -1:
142 	if(stdin_fd != NULL) {
143 	    close(in_fd[0]);
144 	    close(in_fd[1]);
145 	}
146 	if(stdout_fd != NULL) {
147 	    close(out_fd[0]);
148 	    close(out_fd[1]);
149 	}
150 	if(stderr_fd != NULL) {
151 	    close(err_fd[0]);
152 	    close(err_fd[1]);
153 	}
154 	return -2;
155     default:
156 	if(stdin_fd != NULL) {
157 	    close(in_fd[0]);
158 	    *stdin_fd = fdopen(in_fd[1], "w");
159 	}
160 	if(stdout_fd != NULL) {
161 	    close(out_fd[1]);
162 	    *stdout_fd = fdopen(out_fd[0], "r");
163 	}
164 	if(stderr_fd != NULL) {
165 	    close(err_fd[1]);
166 	    *stderr_fd = fdopen(err_fd[0], "r");
167 	}
168     }
169     return pid;
170 }
171 
172 int
173 simple_execvp(const char *file, char *const args[])
174 {
175     pid_t pid = fork();
176     switch(pid){
177     case -1:
178 	return -2;
179     case 0:
180 	execvp(file, args);
181 	exit((errno == ENOENT) ? EX_NOTFOUND : EX_NOEXEC);
182     default:
183 	return wait_for_process(pid);
184     }
185 }
186 
187 /* gee, I'd like a execvpe */
188 int
189 simple_execve(const char *file, char *const args[], char *const envp[])
190 {
191     pid_t pid = fork();
192     switch(pid){
193     case -1:
194 	return -2;
195     case 0:
196 	execve(file, args, envp);
197 	exit((errno == ENOENT) ? EX_NOTFOUND : EX_NOEXEC);
198     default:
199 	return wait_for_process(pid);
200     }
201 }
202 
203 int
204 simple_execlp(const char *file, ...)
205 {
206     va_list ap;
207     char **argv;
208     int ret;
209 
210     va_start(ap, file);
211     argv = vstrcollect(&ap);
212     va_end(ap);
213     if(argv == NULL)
214 	return -1;
215     ret = simple_execvp(file, argv);
216     free(argv);
217     return ret;
218 }
219 
220 int
221 simple_execle(const char *file, ... /* ,char *const envp[] */)
222 {
223     va_list ap;
224     char **argv;
225     char *const* envp;
226     int ret;
227 
228     va_start(ap, file);
229     argv = vstrcollect(&ap);
230     envp = va_arg(ap, char **);
231     va_end(ap);
232     if(argv == NULL)
233 	return -1;
234     ret = simple_execve(file, argv, envp);
235     free(argv);
236     return ret;
237 }
238 
239 int
240 simple_execl(const char *file, ...)
241 {
242     va_list ap;
243     char **argv;
244     int ret;
245 
246     va_start(ap, file);
247     argv = vstrcollect(&ap);
248     va_end(ap);
249     if(argv == NULL)
250 	return -1;
251     ret = simple_execve(file, argv, environ);
252     free(argv);
253     return ret;
254 }
255