1 Blake sent me the wrong one.
2 
3 /* RCS  $Id: runargv.c,v 1.2 2007-10-15 15:58:54 ihi Exp $
4 --
5 -- SYNOPSIS
6 --      Invoke a sub process.
7 --
8 -- DESCRIPTION
9 -- 	Use the standard methods of executing a sub process.
10 --
11 -- AUTHOR
12 --      Dennis Vadura, dvadura@dmake.wticorp.com
13 --
14 -- WWW
15 --      http://dmake.wticorp.com/
16 --
17 -- COPYRIGHT
18 --      Copyright (c) 1996,1997 by WTI Corp.  All rights reserved.
19 --
20 --      This program is NOT free software; you can redistribute it and/or
21 --      modify it under the terms of the Software License Agreement Provided
22 --      in the file <distribution-root>/COPYING.
23 --
24 -- LOG
25 --      Use cvs log to obtain detailed change logs.
26 */
27 
28 #include <process.h>
29 #include <errno.h>
30 #include <signal.h>
31 #include "extern.h"
32 #include "sysintf.h"
33 
34 extern char **environ;
35 
36 typedef struct prp {
37    char *prp_cmd;
38    int   prp_group;
39    int   prp_ignore;
40    int   prp_last;
41    int	 prp_shell;
42    struct prp *prp_next;
43 } RCP, *RCPPTR;
44 
45 typedef struct pr {
46    int		pr_valid;
47    int		pr_pid;
48    CELLPTR	pr_target;
49    int		pr_ignore;
50    int		pr_last;
51    RCPPTR  	pr_recipe;
52    RCPPTR  	pr_recipe_end;
53    char        *pr_dir;
54 } PR;
55 
56 static PR  *_procs    = NIL(PR);
57 static int  _proc_cnt = 0;
58 static int  _abort_flg= FALSE;
59 static int  _use_i    = -1;
60 static int  _do_upd   = 0;
61 
62 static  void	_add_child ANSI((int, CELLPTR, int, int));
63 static  void	_attach_cmd ANSI((char *, int, int, CELLPTR, int, int));
64 static  void    _finished_child ANSI((int, int));
65 static  int     _running ANSI((CELLPTR));
66 
67 PUBLIC int
runargv(target,ignore,group,last,shell,cmd)68 runargv(target, ignore, group, last, shell, cmd)
69 CELLPTR target;
70 int     ignore;
71 int	group;
72 int	last;
73 int     shell;
74 char	*cmd;
75 {
76    extern  int  errno;
77    extern  char *sys_errlist[];
78    int          pid;
79    char         **argv;
80 
81    if( _running(target) /*&& Max_proc != 1*/ ) {
82       /* The command will be executed when the previous recipe
83        * line completes. */
84       _attach_cmd( cmd, group, ignore, target, last, shell );
85       return(1);
86    }
87 
88    while( _proc_cnt == Max_proc )
89       if( Wait_for_child(FALSE, -1) == -1 )  Fatal( "Lost a child %d", errno );
90 
91    argv = Pack_argv( group, shell, cmd );
92 
93    pid = _spawnvpe(_P_NOWAIT, argv[0], argv, environ);
94    if (pid == -1)  {  /*  failed  */
95 	   Error("%s: %s", argv[0], sys_errlist[errno]);
96 	   Handle_result(-1, ignore, _abort_flg, target);
97 	   return(-1);
98    } else
99 	   _add_child(pid, target, ignore, last);
100 
101    return(1);
102 }
103 
104 
105 PUBLIC int
Wait_for_child(abort_flg,pid)106 Wait_for_child( abort_flg, pid )
107 int abort_flg;
108 int pid;
109 {
110    int wid;
111    int status;
112    int waitchild;
113 
114    waitchild = (pid == -1)? FALSE : Wait_for_completion;
115 
116    do {
117       if( (wid = wait(&status)) == -1 ) return(-1);
118 
119       _abort_flg = abort_flg;
120       _finished_child(wid, status);
121       _abort_flg = FALSE;
122    } while( waitchild && pid != wid );
123 
124    return(0);
125 }
126 
127 
128 PUBLIC void
Clean_up_processes()129 Clean_up_processes()
130 {
131    int i;
132 
133    if( _procs != NIL(PR) ) {
134       for( i=0; i<Max_proc; i++ )
135 	 if( _procs[i].pr_valid )
136 	    kill(_procs[i].pr_pid, SIGTERM);
137 
138       while( Wait_for_child(TRUE, -1) != -1 );
139    }
140 }
141 
142 
143 static void
_add_child(pid,target,ignore,last)144 _add_child( pid, target, ignore, last )
145 int	pid;
146 CELLPTR target;
147 int	ignore;
148 int     last;
149 {
150    register int i;
151    register PR *pp;
152 
153    if( _procs == NIL(PR) ) {
154       TALLOC( _procs, Max_proc, PR );
155    }
156 
157    if( (i = _use_i) == -1 )
158       for( i=0; i<Max_proc; i++ )
159 	 if( !_procs[i].pr_valid )
160 	    break;
161 
162    pp = _procs+i;
163 
164    pp->pr_valid  = 1;
165    pp->pr_pid    = pid;
166    pp->pr_target = target;
167    pp->pr_ignore = ignore;
168    pp->pr_last   = last;
169    pp->pr_dir    = DmStrDup(Get_current_dir());
170 
171    Current_target = NIL(CELL);
172 
173    _proc_cnt++;
174 
175    if( Wait_for_completion ) Wait_for_child( FALSE, pid );
176 }
177 
178 
179 static void
_finished_child(pid,status)180 _finished_child(pid, status)
181 int	pid;
182 int	status;
183 {
184    register int i;
185    char     *dir;
186 
187    for( i=0; i<Max_proc; i++ )
188       if( _procs[i].pr_valid && _procs[i].pr_pid == pid )
189 	 break;
190 
191    /* Some children we didn't make esp true if using /bin/sh to execute a
192     * a pipe and feed the output as a makefile into dmake. */
193    if( i == Max_proc ) return;
194    _procs[i].pr_valid = 0;
195    _proc_cnt--;
196    dir = DmStrDup(Get_current_dir());
197    Set_dir( _procs[i].pr_dir );
198 
199    if( _procs[i].pr_recipe != NIL(RCP) && !_abort_flg ) {
200       RCPPTR rp = _procs[i].pr_recipe;
201 
202 
203       Current_target = _procs[i].pr_target;
204       Handle_result( status, _procs[i].pr_ignore, FALSE, _procs[i].pr_target );
205       Current_target = NIL(CELL);
206 
207       if ( _procs[i].pr_target->ce_attr & A_ERROR ) {
208 	 _procs[i].pr_last = TRUE;
209 	 goto ABORT_REMAINDER_OF_RECIPE;
210       }
211 
212       _procs[i].pr_recipe = rp->prp_next;
213 
214       _use_i = i;
215       runargv( _procs[i].pr_target, rp->prp_ignore, rp->prp_group,
216 	       rp->prp_last, rp->prp_shell, rp->prp_cmd );
217       _use_i = -1;
218 
219       FREE( rp->prp_cmd );
220       FREE( rp );
221 
222       if( _proc_cnt == Max_proc ) Wait_for_child( FALSE, -1 );
223    }
224    else {
225       Handle_result(status,_procs[i].pr_ignore,_abort_flg,_procs[i].pr_target);
226 
227  ABORT_REMAINDER_OF_RECIPE:
228       if( _procs[i].pr_last ) {
229 	 FREE(_procs[i].pr_dir );
230 
231 	 if( !Doing_bang ) Update_time_stamp( _procs[i].pr_target );
232       }
233    }
234 
235    Set_dir(dir);
236    FREE(dir);
237 }
238 
239 
240 static int
_running(cp)241 _running( cp )
242 CELLPTR cp;
243 {
244    register int i;
245 
246    if( !_procs ) return(FALSE);
247 
248    for( i=0; i<Max_proc; i++ )
249       if( _procs[i].pr_valid &&
250 	  _procs[i].pr_target == cp  )
251 	 break;
252 
253    return( i != Max_proc );
254 }
255 
256 
257 static void
_attach_cmd(cmd,group,ignore,cp,last,shell)258 _attach_cmd( cmd, group, ignore, cp, last, shell )
259 char    *cmd;
260 int	group;
261 int     ignore;
262 CELLPTR cp;
263 int     last;
264 int     shell;
265 {
266    register int i;
267    RCPPTR rp;
268 
269    for( i=0; i<Max_proc; i++ )
270       if( _procs[i].pr_valid &&
271 	  _procs[i].pr_target == cp  )
272 	 break;
273 
274    TALLOC( rp, 1, RCP );
275    rp->prp_cmd   = DmStrDup(cmd);
276    rp->prp_group = group;
277    rp->prp_ignore= ignore;
278    rp->prp_last  = last;
279    rp->prp_shell = shell;
280 
281    if( _procs[i].pr_recipe == NIL(RCP) )
282       _procs[i].pr_recipe = _procs[i].pr_recipe_end = rp;
283    else {
284       _procs[i].pr_recipe_end->prp_next = rp;
285       _procs[i].pr_recipe_end = rp;
286    }
287 }
288