1 /* $NetBSD: run.c,v 1.13 2008/07/28 17:40:33 christos Exp $ */
4 * Copyright (c) 1991 Carnegie Mellon University
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
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
50 **********************************************************************
52 * Revision 1.1 89/10/14 19:53:39 rvb
55 * Revision 1.2 89/08/03 14:36:46 mja
56 * Update run() and runp() to use <varargs.h>.
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 **********************************************************************
96 #include "supextern.h"
98 static int dorun(char *, char **, int);
99 static char **makearglist(va_list);
102 makearglist(va_list ap
)
104 static size_t ns
= 0;
105 static char **np
= NULL
;
111 nnp
= realloc(np
, (ns
+ 20) * sizeof(*np
));
119 np
[i
] = va_arg(ap
, char *);
121 while (np
[i
++] != NULL
);
133 if ((argv
= makearglist(ap
)) == NULL
) {
137 val
= runv(name
, argv
);
143 runv(char *name
, char **argv
)
145 return (dorun(name
, argv
, 0));
149 runp(char *name
, ...)
156 if ((argv
= makearglist(ap
)) == NULL
) {
160 val
= runvp(name
, argv
);
166 runvp(char *name
, char **argv
)
168 return (dorun(name
, argv
, 1));
172 dorun(char *name
, char **argv
, int usepath
)
176 struct sigaction ignoresig
, intsig
, quitsig
;
179 if ((pid
= vfork()) == -1)
180 return (-1); /* no more processes, so exit with error */
182 if (pid
== 0) { /* child process */
189 fprintf(stderr
, "run: can't exec %s (%s)\n", name
,
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
);
199 wpid
= wait3(&status
, WUNTRACED
, 0);
200 if (WIFSTOPPED(status
)) {
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)
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
,
226 switch ((pid
= fork())) {
233 if ((fd
= open(infile
, O_RDONLY
)) == -1)
240 if ((fd
= open(outfile
, O_RDWR
| O_CREAT
| O_TRUNC
,
248 if ((fd
= open(errfile
, O_RDWR
| O_CREAT
| O_TRUNC
,
254 execvp(argv
[0], argv
);
260 if (waitpid(pid
, &status
, 0) == -1)
267 * Like runio, but works with filedescriptors instead of filenames
270 runiofd(char *const * argv
, const int infile
, const int outfile
,
276 switch ((pid
= fork())) {
287 execvp(argv
[0], argv
);
293 if (waitpid(pid
, &status
, 0) == -1)