xref: /openbsd-src/gnu/usr.bin/cvs/vms/piped_child.c (revision 50bf276cd1c7e20f1eda64a5e63e0fae39e12a95)
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