1*50bf276cStholo /*
2*50bf276cStholo * piped_child.c
3*50bf276cStholo *
4*50bf276cStholo * An experimental VMS implementation of the same routine in [-.src]run.c
5*50bf276cStholo * <benjamin@cyclic.com>
6*50bf276cStholo *
7*50bf276cStholo * Derived in part from pipe.c, in this directory.
8*50bf276cStholo */
9*50bf276cStholo
10*50bf276cStholo #include "vms.h"
11*50bf276cStholo #include "vms-types.h"
12*50bf276cStholo
13*50bf276cStholo #include <stdio.h>
14*50bf276cStholo #include <stdlib.h>
15*50bf276cStholo #include <string.h>
16*50bf276cStholo #include <iodef.h>
17*50bf276cStholo #include <ssdef.h>
18*50bf276cStholo #include <syidef.h>
19*50bf276cStholo #include <clidef.h>
20*50bf276cStholo #include <stsdef.h>
21*50bf276cStholo #include <dvidef.h>
22*50bf276cStholo #include <nam.h>
23*50bf276cStholo #include <descrip.h>
24*50bf276cStholo #include <errno.h>
25*50bf276cStholo #include <file.h>
26*50bf276cStholo #include <lib$routines.h>
27*50bf276cStholo #include <starlet.h>
28*50bf276cStholo
29*50bf276cStholo extern int trace;
30*50bf276cStholo
31*50bf276cStholo /* Subprocess IO structure */
32*50bf276cStholo typedef struct _SUBIO {
33*50bf276cStholo struct _SUBIO *self;
34*50bf276cStholo struct _SUBIO *prev;
35*50bf276cStholo struct _SUBIO *next;
36*50bf276cStholo short read_chan;
37*50bf276cStholo short write_chan;
38*50bf276cStholo FILE *read_fp;
39*50bf276cStholo FILE *write_fp;
40*50bf276cStholo struct IOSB read_iosb;
41*50bf276cStholo struct IOSB write_iosb;
42*50bf276cStholo int pid;
43*50bf276cStholo int return_status;
44*50bf276cStholo unsigned long event_flag;
45*50bf276cStholo unsigned char event_flag_byte;
46*50bf276cStholo } SUBIO;
47*50bf276cStholo
48*50bf276cStholo static SUBIO *siop_head = NULL, *siop_tail = NULL;
49*50bf276cStholo
50*50bf276cStholo static int piped_child_exith(int);
51*50bf276cStholo
52*50bf276cStholo static struct EXHCB piped_child_exit_handler_block =
53*50bf276cStholo {0, piped_child_exith, 1, &piped_child_exit_handler_block.exh$l_status, 0};
54*50bf276cStholo
55*50bf276cStholo typedef struct
56*50bf276cStholo {
57*50bf276cStholo short length;
58*50bf276cStholo char body[NAM$C_MAXRSS+1];
59*50bf276cStholo } Vstring;
60*50bf276cStholo
61*50bf276cStholo /* Subprocess Completion AST */
piped_child_done(siop)62*50bf276cStholo void piped_child_done(siop)
63*50bf276cStholo SUBIO *siop;
64*50bf276cStholo {
65*50bf276cStholo struct IOSB iosb;
66*50bf276cStholo int status;
67*50bf276cStholo
68*50bf276cStholo if (siop->self != siop)
69*50bf276cStholo return;
70*50bf276cStholo siop->read_iosb.status = SS$_NORMAL;
71*50bf276cStholo siop->write_iosb.status = SS$_NORMAL;
72*50bf276cStholo
73*50bf276cStholo }
74*50bf276cStholo
75*50bf276cStholo /* Exit handler, established by piped_child() */
76*50bf276cStholo static int
piped_child_exith(status)77*50bf276cStholo piped_child_exith(status)
78*50bf276cStholo int status;
79*50bf276cStholo {
80*50bf276cStholo struct IOSB iosb;
81*50bf276cStholo SUBIO *siop;
82*50bf276cStholo int return_value = 0;
83*50bf276cStholo
84*50bf276cStholo siop = siop_head;
85*50bf276cStholo while (siop)
86*50bf276cStholo {
87*50bf276cStholo if (siop->self != siop)
88*50bf276cStholo {
89*50bf276cStholo return_value = -1;
90*50bf276cStholo continue;
91*50bf276cStholo }
92*50bf276cStholo
93*50bf276cStholo /* Finish pending reads and shutdown */
94*50bf276cStholo if(!siop->read_iosb.status)
95*50bf276cStholo {
96*50bf276cStholo fflush (siop->read_fp);
97*50bf276cStholo fclose (siop->read_fp);
98*50bf276cStholo }
99*50bf276cStholo else
100*50bf276cStholo fclose (siop->read_fp);
101*50bf276cStholo sys$dassgn (siop->read_chan);
102*50bf276cStholo
103*50bf276cStholo /* Finish pending writes and shutdown */
104*50bf276cStholo if(!siop->write_iosb.status)
105*50bf276cStholo {
106*50bf276cStholo fflush (siop->write_fp);
107*50bf276cStholo sys$qio (0, siop->write_chan, IO$_WRITEOF, &iosb,
108*50bf276cStholo 0, 0, 0, 0, 0, 0, 0, 0);
109*50bf276cStholo fclose (siop->write_fp);
110*50bf276cStholo }
111*50bf276cStholo else
112*50bf276cStholo fclose (siop->write_fp);
113*50bf276cStholo sys$dassgn (siop->write_chan);
114*50bf276cStholo
115*50bf276cStholo sys$synch (siop->event_flag, &siop->write_iosb);
116*50bf276cStholo
117*50bf276cStholo siop = siop->next;
118*50bf276cStholo }
119*50bf276cStholo return return_value;
120*50bf276cStholo }
121*50bf276cStholo
piped_child(command,tofdp,fromfdp)122*50bf276cStholo int piped_child(command, tofdp, fromfdp)
123*50bf276cStholo char **command;
124*50bf276cStholo int *tofdp, *fromfdp;
125*50bf276cStholo {
126*50bf276cStholo static int exit_handler = 0;
127*50bf276cStholo struct IOSB iosb1, iosb2;
128*50bf276cStholo int rs1, rs2, i;
129*50bf276cStholo unsigned long flags, vmspid, return_status;
130*50bf276cStholo char cmd[1024];
131*50bf276cStholo struct dsc$descriptor_s cmddsc;
132*50bf276cStholo struct dsc$descriptor_s read_mbxdsc, write_mbxdsc;
133*50bf276cStholo SUBIO *siop;
134*50bf276cStholo static Vstring read_mbxname, write_mbxname;
135*50bf276cStholo static struct itm$list3 write_mbxlist[2] = {
136*50bf276cStholo {sizeof(write_mbxname.body)-1, DVI$_DEVNAM,
137*50bf276cStholo &write_mbxname.body, (size_t *) &write_mbxname.length},
138*50bf276cStholo {0, 0, 0, 0} };
139*50bf276cStholo static struct itm$list3 read_mbxlist[2] = {
140*50bf276cStholo {sizeof(read_mbxname.body)-1, DVI$_DEVNAM,
141*50bf276cStholo &read_mbxname.body, (size_t *) &read_mbxname.length},
142*50bf276cStholo {0, 0, 0, 0} };
143*50bf276cStholo
144*50bf276cStholo read_mbxname.length = sizeof(read_mbxname.body);
145*50bf276cStholo write_mbxname.length = sizeof(write_mbxname.body);
146*50bf276cStholo
147*50bf276cStholo siop = (SUBIO *) calloc(1, sizeof(SUBIO));
148*50bf276cStholo if (!siop)
149*50bf276cStholo {
150*50bf276cStholo perror("piped_child: malloc failed\n");
151*50bf276cStholo return -1;
152*50bf276cStholo }
153*50bf276cStholo
154*50bf276cStholo siop->self = siop;
155*50bf276cStholo
156*50bf276cStholo /* Construct command line by concatenating argument list */
157*50bf276cStholo strcpy(cmd, command[0]);
158*50bf276cStholo for(i=1; command[i] != NULL; i++)
159*50bf276cStholo {
160*50bf276cStholo strcat(cmd, " ");
161*50bf276cStholo strcat(cmd, command[i]);
162*50bf276cStholo }
163*50bf276cStholo
164*50bf276cStholo if(trace)
165*50bf276cStholo fprintf(stderr, "piped_child: running '%s'\n", cmd);
166*50bf276cStholo
167*50bf276cStholo /* Allocate a pair of temporary mailboxes (2kB each) */
168*50bf276cStholo rs1 = sys$crembx (0, &siop->read_chan, 2048, 2048, 0, 0, 0, 0);
169*50bf276cStholo rs2 = sys$crembx (0, &siop->write_chan, 2048, 2048, 0, 0, 0, 0);
170*50bf276cStholo
171*50bf276cStholo if (rs1 != SS$_NORMAL || rs2 != SS$_NORMAL)
172*50bf276cStholo {
173*50bf276cStholo vaxc$errno = rs1 | rs2;
174*50bf276cStholo errno = EVMSERR;
175*50bf276cStholo free (siop);
176*50bf276cStholo perror ("piped_child: $CREMBX failure");
177*50bf276cStholo return -1;
178*50bf276cStholo }
179*50bf276cStholo
180*50bf276cStholo /* Get mailbox names, so we can fopen() them */
181*50bf276cStholo rs1 = sys$getdviw (0, siop->read_chan, 0, &read_mbxlist,
182*50bf276cStholo &iosb1, 0, 0, 0);
183*50bf276cStholo
184*50bf276cStholo rs2 = sys$getdviw (0, siop->write_chan, 0, &write_mbxlist,
185*50bf276cStholo &iosb2, 0, 0, 0);
186*50bf276cStholo
187*50bf276cStholo if ((rs1 != SS$_NORMAL && !(iosb1.status & STS$M_SUCCESS)) ||
188*50bf276cStholo (rs2 != SS$_NORMAL && !(iosb2.status & STS$M_SUCCESS)))
189*50bf276cStholo {
190*50bf276cStholo vaxc$errno = iosb1.status | iosb2.status;
191*50bf276cStholo errno = EVMSERR;
192*50bf276cStholo sys$dassgn (siop->read_chan);
193*50bf276cStholo sys$dassgn (siop->write_chan);
194*50bf276cStholo free (siop);
195*50bf276cStholo perror ("piped_child: $GETDVIW failure, could not get mailbox names");
196*50bf276cStholo return -1;
197*50bf276cStholo }
198*50bf276cStholo
199*50bf276cStholo if (trace)
200*50bf276cStholo {
201*50bf276cStholo fprintf(stderr, "piped_child: $GETDVIW succeeded, got mailbox names\n");
202*50bf276cStholo fprintf(stderr, "piped_child: ReadMBX: %s, WriteMBX: %s\n",
203*50bf276cStholo read_mbxname.body, write_mbxname.body);
204*50bf276cStholo }
205*50bf276cStholo
206*50bf276cStholo /* Make C happy */
207*50bf276cStholo write_mbxname.body[write_mbxname.length] = '\0';
208*50bf276cStholo read_mbxname.body[read_mbxname.length] = '\0';
209*50bf276cStholo
210*50bf276cStholo /* Make VMS happy */
211*50bf276cStholo write_mbxdsc.dsc$w_length = write_mbxname.length;
212*50bf276cStholo write_mbxdsc.dsc$b_dtype = DSC$K_DTYPE_T;
213*50bf276cStholo write_mbxdsc.dsc$b_class = DSC$K_CLASS_S;
214*50bf276cStholo write_mbxdsc.dsc$a_pointer = write_mbxname.body;
215*50bf276cStholo
216*50bf276cStholo read_mbxdsc.dsc$w_length = read_mbxname.length;
217*50bf276cStholo read_mbxdsc.dsc$b_dtype = DSC$K_DTYPE_T;
218*50bf276cStholo read_mbxdsc.dsc$b_class = DSC$K_CLASS_S;
219*50bf276cStholo read_mbxdsc.dsc$a_pointer = read_mbxname.body;
220*50bf276cStholo
221*50bf276cStholo /* Build descriptor for command line */
222*50bf276cStholo cmddsc.dsc$w_length = strlen(cmd);
223*50bf276cStholo cmddsc.dsc$b_dtype = DSC$K_DTYPE_T;
224*50bf276cStholo cmddsc.dsc$b_class = DSC$K_CLASS_S;
225*50bf276cStholo cmddsc.dsc$a_pointer = (char *) cmd;
226*50bf276cStholo
227*50bf276cStholo flags = CLI$M_NOWAIT;
228*50bf276cStholo
229*50bf276cStholo /* Allocate an event flag to signal process termination */
230*50bf276cStholo rs1 = lib$get_ef(&siop->event_flag);
231*50bf276cStholo if (rs1 != SS$_NORMAL)
232*50bf276cStholo {
233*50bf276cStholo vaxc$errno = rs1;
234*50bf276cStholo errno = EVMSERR;
235*50bf276cStholo sys$dassgn(siop->read_chan);
236*50bf276cStholo sys$dassgn(siop->write_chan);
237*50bf276cStholo perror("piped_child: LIB$GET_EF failed");
238*50bf276cStholo return -1;
239*50bf276cStholo }
240*50bf276cStholo
241*50bf276cStholo /* Save the EFN as a byte for later calls to other routines */
242*50bf276cStholo siop->event_flag_byte = 0xff & siop->event_flag;
243*50bf276cStholo
244*50bf276cStholo if (trace)
245*50bf276cStholo fprintf(stderr, "piped_child: Got an EFN: %d\n", siop->event_flag_byte);
246*50bf276cStholo
247*50bf276cStholo rs1 = lib$spawn(&cmddsc, &write_mbxdsc, &read_mbxdsc, &flags, 0,
248*50bf276cStholo &siop->pid, &siop->return_status, &siop->event_flag_byte,
249*50bf276cStholo &piped_child_done, siop->self);
250*50bf276cStholo
251*50bf276cStholo if (rs1 != SS$_NORMAL)
252*50bf276cStholo {
253*50bf276cStholo vaxc$errno = rs1;
254*50bf276cStholo errno = EVMSERR;
255*50bf276cStholo sys$dassgn(siop->read_chan);
256*50bf276cStholo sys$dassgn(siop->write_chan);
257*50bf276cStholo perror("piped_child: LIB$SPAWN failure");
258*50bf276cStholo return -1;
259*50bf276cStholo }
260*50bf276cStholo
261*50bf276cStholo if (trace)
262*50bf276cStholo fprintf(stderr, "piped_child: LIB$SPAWN succeeded, pid is %08x.\n",
263*50bf276cStholo siop->pid);
264*50bf276cStholo
265*50bf276cStholo /* Establish an exit handler so the process isn't prematurely terminated */
266*50bf276cStholo if (!exit_handler)
267*50bf276cStholo {
268*50bf276cStholo rs1 = sys$dclexh (&piped_child_exit_handler_block);
269*50bf276cStholo if (rs1 != SS$_NORMAL)
270*50bf276cStholo {
271*50bf276cStholo vaxc$errno = rs1;
272*50bf276cStholo errno = EVMSERR;
273*50bf276cStholo sys$dassgn (siop->read_chan);
274*50bf276cStholo sys$dassgn (siop->write_chan);
275*50bf276cStholo sys$delprc (siop->pid, 0);
276*50bf276cStholo free (siop);
277*50bf276cStholo perror("piped_child: $DCLEXH failure");
278*50bf276cStholo return -1;
279*50bf276cStholo }
280*50bf276cStholo exit_handler = 1;
281*50bf276cStholo }
282*50bf276cStholo
283*50bf276cStholo /* Let's open some files */
284*50bf276cStholo siop->read_fp = fopen (read_mbxname.body, "r");
285*50bf276cStholo siop->write_fp = fopen (write_mbxname.body, "w");
286*50bf276cStholo
287*50bf276cStholo if (!siop->read_fp || !siop->write_fp)
288*50bf276cStholo {
289*50bf276cStholo sys$dassgn (siop->read_chan);
290*50bf276cStholo sys$dassgn (siop->write_chan);
291*50bf276cStholo sys$delprc (siop->pid);
292*50bf276cStholo free (siop);
293*50bf276cStholo perror("piped_child: fopen() failed");
294*50bf276cStholo return -1;
295*50bf276cStholo }
296*50bf276cStholo
297*50bf276cStholo *fromfdp = fileno(siop->read_fp);
298*50bf276cStholo *tofdp = fileno(siop->write_fp);
299*50bf276cStholo
300*50bf276cStholo if (trace)
301*50bf276cStholo fprintf(stderr, "piped_child: file open successful: tofd=%d fromfd=%d\n",
302*50bf276cStholo *tofdp, *fromfdp);
303*50bf276cStholo
304*50bf276cStholo /* Keep track of active subprocess I/O (SUBIO) structures */
305*50bf276cStholo if (siop_head)
306*50bf276cStholo {
307*50bf276cStholo siop_tail->next = siop;
308*50bf276cStholo siop->prev = siop_tail;
309*50bf276cStholo siop_tail = siop;
310*50bf276cStholo }
311*50bf276cStholo else
312*50bf276cStholo siop_head = siop_tail = siop;
313*50bf276cStholo
314*50bf276cStholo return siop->pid;
315*50bf276cStholo }
316*50bf276cStholo
317*50bf276cStholo /*
318*50bf276cStholo * Return codes
319*50bf276cStholo * >0 VMS exit status of subprocess
320*50bf276cStholo * 0 success, subprocess was shutdown
321*50bf276cStholo * -1 pid not found in list of subprocesses
322*50bf276cStholo * -2 memory corruption detected
323*50bf276cStholo */
324*50bf276cStholo int
piped_child_shutdown(pid)325*50bf276cStholo piped_child_shutdown(pid)
326*50bf276cStholo pid_t pid;
327*50bf276cStholo {
328*50bf276cStholo int return_status;
329*50bf276cStholo struct IOSB iosb;
330*50bf276cStholo SUBIO *siop = siop_head;
331*50bf276cStholo
332*50bf276cStholo while (siop && siop->self == siop && siop->pid != pid)
333*50bf276cStholo siop = siop->next;
334*50bf276cStholo
335*50bf276cStholo if (!siop)
336*50bf276cStholo return -1;
337*50bf276cStholo else if (siop->self != siop)
338*50bf276cStholo return -2;
339*50bf276cStholo
340*50bf276cStholo /* Finish reading and writing and shutdown */
341*50bf276cStholo if (siop->read_iosb.status)
342*50bf276cStholo {
343*50bf276cStholo fflush (siop->read_fp);
344*50bf276cStholo fclose (siop->read_fp);
345*50bf276cStholo }
346*50bf276cStholo else
347*50bf276cStholo fclose(siop->read_fp);
348*50bf276cStholo sys$dassgn (siop->read_chan);
349*50bf276cStholo
350*50bf276cStholo if (siop->write_iosb.status)
351*50bf276cStholo {
352*50bf276cStholo fflush (siop->write_fp);
353*50bf276cStholo sys$qio (0, siop->write_chan, IO$_WRITEOF, &iosb,
354*50bf276cStholo 0, 0, 0, 0, 0, 0, 0, 0);
355*50bf276cStholo fclose (siop->write_fp);
356*50bf276cStholo }
357*50bf276cStholo else
358*50bf276cStholo fclose(siop->write_fp);
359*50bf276cStholo sys$dassgn (siop->write_chan);
360*50bf276cStholo
361*50bf276cStholo sys$synch (siop->event_flag, &siop->write_iosb);
362*50bf276cStholo lib$free_ef(&siop->event_flag);
363*50bf276cStholo
364*50bf276cStholo /* Ditch SUBIO structure */
365*50bf276cStholo if (siop == siop_tail)
366*50bf276cStholo siop_tail = siop->prev;
367*50bf276cStholo if (siop == siop_head)
368*50bf276cStholo siop_head = siop->next;
369*50bf276cStholo if (siop->prev)
370*50bf276cStholo siop->prev->next = siop->next;
371*50bf276cStholo if (siop->next)
372*50bf276cStholo siop->next->prev = siop->prev;
373*50bf276cStholo
374*50bf276cStholo if (siop->return_status)
375*50bf276cStholo return_status = siop->return_status;
376*50bf276cStholo else
377*50bf276cStholo return_status = 0;
378*50bf276cStholo
379*50bf276cStholo free (siop);
380*50bf276cStholo
381*50bf276cStholo return return_status;
382*50bf276cStholo }
383