Expand PMF_FN_* macros.
[netbsd-mini2440.git] / usr.sbin / sup / source / run.c
blob7054ad6cc6c2e98242d13335891d697c1c65fbbd
1 /* $NetBSD: run.c,v 1.13 2008/07/28 17:40:33 christos Exp $ */
3 /*
4 * Copyright (c) 1991 Carnegie Mellon University
5 * All Rights Reserved.
7 * Permission to use, copy, modify and distribute this software and its
8 * documentation is hereby granted, provided that both the copyright
9 * notice and this permission notice appear in all copies of the
10 * software, derivative works or modified versions, and any portions
11 * thereof, and that both notices appear in supporting documentation.
13 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
14 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
15 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
17 * Carnegie Mellon requests users of this software to return to
19 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
20 * School of Computer Science
21 * Carnegie Mellon University
22 * Pittsburgh PA 15213-3890
24 * any improvements or extensions that they make and grant Carnegie the rights
25 * to redistribute these changes.
27 /* run, runv, runp, runvp -- execute process and wait for it to exit
29 * Usage:
30 * i = run (file, arg1, arg2, ..., argn, 0);
31 * i = runv (file, arglist);
32 * i = runp (file, arg1, arg2, ..., argn, 0);
33 * i = runvp (file, arglist);
34 * i = runio (argv, in, out, err);
36 * Run, runv, runp and runvp have argument lists exactly like the
37 * corresponding routines, execl, execv, execlp, execvp. The run
38 * routines perform a fork, then:
39 * IN THE NEW PROCESS, an execl[p] or execv[p] is performed with the
40 * specified arguments. The process returns with a -1 code if the
41 * exec was not successful.
42 * IN THE PARENT PROCESS, the signals SIGQUIT and SIGINT are disabled,
43 * the process waits until the newly forked process exits, the
44 * signals are restored to their original status, and the return
45 * status of the process is analyzed.
46 * All run routines return: -1 if the exec failed or if the child was
47 * terminated abnormally; otherwise, the exit code of the child is
48 * returned.
50 **********************************************************************
51 * HISTORY
52 * Revision 1.1 89/10/14 19:53:39 rvb
53 * Initial revision
55 * Revision 1.2 89/08/03 14:36:46 mja
56 * Update run() and runp() to use <varargs.h>.
57 * [89/04/19 mja]
59 * 23-Sep-86 Glenn Marcy (gm0w) at Carnegie-Mellon University
60 * Merged old runv and runvp modules.
62 * 22-Nov-85 Glenn Marcy (gm0w) at Carnegie-Mellon University
63 * Added check and kill if child process was stopped.
65 * 30-Apr-85 Steven Shafer (sas) at Carnegie-Mellon University
66 * Adapted for 4.2 BSD UNIX: Conforms to new signals and wait.
68 * 15-July-82 Mike Accetta (mja) and Neal Friedman (naf)
69 * at Carnegie-Mellon University
70 * Added a return(-1) if vfork fails. This should only happen
71 * if there are no more processes available.
73 * 28-Jan-80 Steven Shafer (sas) at Carnegie-Mellon University
74 * Added setuid and setgid for system programs' use.
76 * 21-Jan-80 Steven Shafer (sas) at Carnegie-Mellon University
77 * Changed fork to vfork.
79 * 20-Nov-79 Steven Shafer (sas) at Carnegie-Mellon University
80 * Created for VAX. The proper way to fork-and-execute a system
81 * program is now by "runvp" or "runp", with the program name
82 * (rather than an absolute pathname) as the first argument;
83 * that way, the "PATH" variable in the environment does the right
84 * thing. Too bad execvp and execlp (hence runvp and runp) don't
85 * accept a pathlist as an explicit argument.
87 **********************************************************************
90 #include <stdio.h>
91 #include <signal.h>
92 #include <fcntl.h>
93 #include <sys/wait.h>
95 #include "supcdefs.h"
96 #include "supextern.h"
98 static int dorun(char *, char **, int);
99 static char **makearglist(va_list);
101 static char **
102 makearglist(va_list ap)
104 static size_t ns = 0;
105 static char **np = NULL;
106 char **nnp;
107 size_t i = 0;
109 do {
110 if (i >= ns) {
111 nnp = realloc(np, (ns + 20) * sizeof(*np));
112 if (nnp == NULL) {
113 free(np);
114 return NULL;
116 np = nnp;
117 ns += 20;
119 np[i] = va_arg(ap, char *);
121 while (np[i++] != NULL);
122 return np;
126 run(char *name, ...)
128 int val;
129 va_list ap;
130 char **argv;
132 va_start(ap, name);
133 if ((argv = makearglist(ap)) == NULL) {
134 va_end(ap);
135 return -1;
137 val = runv(name, argv);
138 va_end(ap);
139 return (val);
142 int
143 runv(char *name, char **argv)
145 return (dorun(name, argv, 0));
149 runp(char *name, ...)
151 int val;
152 va_list ap;
153 char **argv;
155 va_start(ap, name);
156 if ((argv = makearglist(ap)) == NULL) {
157 va_end(ap);
158 return -1;
160 val = runvp(name, argv);
161 va_end(ap);
162 return (val);
165 int
166 runvp(char *name, char **argv)
168 return (dorun(name, argv, 1));
171 static int
172 dorun(char *name, char **argv, int usepath)
174 int wpid;
175 int pid;
176 struct sigaction ignoresig, intsig, quitsig;
177 int status;
179 if ((pid = vfork()) == -1)
180 return (-1); /* no more processes, so exit with error */
182 if (pid == 0) { /* child process */
183 setgid(getgid());
184 setuid(getuid());
185 if (usepath)
186 execvp(name, argv);
187 else
188 execv(name, argv);
189 fprintf(stderr, "run: can't exec %s (%s)\n", name,
190 strerror(errno));
191 _exit(0377);
193 ignoresig.sa_handler = SIG_IGN; /* ignore INT and QUIT signals */
194 sigemptyset(&ignoresig.sa_mask);
195 ignoresig.sa_flags = 0;
196 sigaction(SIGINT, &ignoresig, &intsig);
197 sigaction(SIGQUIT, &ignoresig, &quitsig);
198 do {
199 wpid = wait3(&status, WUNTRACED, 0);
200 if (WIFSTOPPED(status)) {
201 kill(0, SIGTSTP);
202 wpid = 0;
204 } while (wpid != pid && wpid != -1);
205 sigaction(SIGINT, &intsig, 0); /* restore signals */
206 sigaction(SIGQUIT, &quitsig, 0);
208 if (WIFSIGNALED(status) || WEXITSTATUS(status) == 0377)
209 return (-1);
211 return (WEXITSTATUS(status));
215 * Like system(3), but with an argument list and explicit redirections
216 * that does not use the shell
219 runio(char *const * argv, const char *infile, const char *outfile,
220 const char *errfile)
222 int fd;
223 pid_t pid;
224 int status;
226 switch ((pid = fork())) {
227 case -1:
228 return -1;
230 case 0:
231 if (infile) {
232 (void) close(0);
233 if ((fd = open(infile, O_RDONLY)) == -1)
234 exit(1);
235 if (fd != 0)
236 (void) dup2(fd, 0);
238 if (outfile) {
239 (void) close(1);
240 if ((fd = open(outfile, O_RDWR | O_CREAT | O_TRUNC,
241 0666)) == -1)
242 exit(1);
243 if (fd != 1)
244 (void) dup2(fd, 1);
246 if (errfile) {
247 (void) close(2);
248 if ((fd = open(errfile, O_RDWR | O_CREAT | O_TRUNC,
249 0666)) == -1)
250 exit(1);
251 if (fd != 2)
252 (void) dup2(fd, 2);
254 execvp(argv[0], argv);
255 exit(1);
256 /* NOTREACHED */
257 return 0;
259 default:
260 if (waitpid(pid, &status, 0) == -1)
261 return -1;
262 return status;
267 * Like runio, but works with filedescriptors instead of filenames
270 runiofd(char *const * argv, const int infile, const int outfile,
271 const int errfile)
273 pid_t pid;
274 int status;
276 switch ((pid = fork())) {
277 case -1:
278 return -1;
280 case 0:
281 if (infile != 0)
282 dup2(infile, 0);
283 if (outfile != 1)
284 dup2(outfile, 1);
285 if (errfile != 2)
286 dup2(errfile, 2);
287 execvp(argv[0], argv);
288 exit(1);
289 /* NOTREACHED */
290 return 0;
292 default:
293 if (waitpid(pid, &status, 0) == -1)
294 return -1;
295 return status;