2 * Copyright © 1994 the Free Software Foundation, Inc.
4 * Author: Roland B. Roberts (roberts@nsrl.rochester.edu)
6 * This file is a part of GNU VMSLIB, the GNU library for porting GNU
9 * GNU VMSLIB is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * GNU VMSLIB is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
21 * Modification History
23 * Use event flag one -- zero seems to cause sys$synch to hang.
25 * All pipes now use event flag zero.
26 * Removed the limit on the number of pipes.
27 * Added members to PIPE structure and memory corruption tests.
37 #if __VMS_VER < 70200000 || __DECC_VER < 50700000
39 /* This won't work with GCC, but it won't cause any problems either. */
41 #define VERSION "V1.5"
44 #pragma module MODULE VERSION
47 #module MODULE VERSION
64 #include <lib$routines.h>
67 #include "vms-types.h"
69 /* A linked list of pipes, for internal use only */
72 struct PIPE *next; /* next pipe in the chain */
73 struct PIPE *prev; /* previous pipe in the chain */
74 struct PIPE *self; /* self reference */
75 int mode; /* pipe I/O mode (read or write) */
76 long status; /* subprocess completion status */
77 struct IOSB iosb; /* pipe I/O status block */
78 FILE *file; /* pipe file structure */
79 int pid; /* pipe process id */
80 short chan; /* pipe channel */
81 jmp_buf jmpbuf; /* jump buffer, if needed */
82 int has_jmpbuf; /* flag */
85 /* Head of the pipe chain */
86 static struct PIPE *phead = NULL, *ptail = NULL;
88 static unsigned char evf = 1;
91 * Exit handler for current process, established by popen().
92 * Force the current process to wait for the completion of children
93 * which were started via popen().
107 if (this->self != this)
112 if (!this->iosb.status)
115 if (this->mode == O_WRONLY)
116 sys$qio (0, this->chan, IO$_WRITEOF, &iosb,
117 0, 0, 0, 0, 0, 0, 0, 0);
119 sys$synch (evf, &this->iosb);
123 sys$dassgn (this->chan);
130 * Close a "pipe" created by popen()
132 * >0 VMS exit status of process
133 * 0 success, pipe was closed
134 * -1 stream not found in list of pipes
135 * -2 memory corruption detected
142 struct PIPE *this = phead;
144 while (this && this->self == this && this->file != stream)
147 /* Pipe not found or failed sanity check */
150 else if (this->self != this)
153 /* Flush the I/O buffer and wait for the close to complete */
154 if (!this->iosb.status)
157 if (this->mode == O_WRONLY)
158 sys$qio (0, this->chan, IO$_WRITEOF, &iosb,
159 0, 0, 0, 0, 0, 0, 0, 0);
161 sys$synch (evf, &this->iosb);
165 sys$dassgn (this->chan);
167 /* Remove `this' from the list of pipes and free its storage */
173 this->prev->next = this->next;
175 this->next->prev = this->prev;
178 if (this->status & STS$M_SUCCESS != STS$M_SUCCESS)
185 * Subprocess AST completion routine
186 * Indicate successful completion in the iosb and clear the pid.
187 * Note that the channel is *not* deassigned and the file is
196 if (this->self != this)
198 this->iosb.status = 1;
200 if (this->has_jmpbuf)
202 this->has_jmpbuf = 0;
203 longjmp (this->jmpbuf, 1);
208 pipe_set_fd_jmpbuf (fd, jmpbuf)
212 struct PIPE *this = phead;
215 if (fileno (this->file) == fd)
217 memcpy (this->jmpbuf, jmpbuf, sizeof (jmp_buf));
218 this->has_jmpbuf = 1;
221 this->has_jmpbuf = 0;
222 longjmp (this->jmpbuf, 1);
231 pipe_unset_fd_jmpbuf (fd)
234 struct PIPE *this = phead;
237 if (fileno (this->file) == fd)
239 this->has_jmpbuf = 0;
247 /* Exit handler control block for the current process. */
248 static struct EXHCB pexhcb = { 0, pwait, 1, &pexhcb.exh$l_status, 0 };
253 char body[NAM$C_MAXRSS+1];
257 * Emulate a unix popen() call using lib$spawn
259 * if mode == "w", lib$spawn uses the mailbox for sys$input
260 * if mode == "r", lib$spawn uses the mailbox for sys$output
262 * Don't now how to handle both read and write
265 * FILE * file pointer to the pipe
266 * NULL indicates an error ocurred, check errno value
273 int i, status, flags, mbxsize;
275 struct dsc$descriptor_s cmddsc, mbxdsc;
276 struct Vstring mbxname = { sizeof(mbxname.body) };
277 struct itm$list3 mbxlist[2] = {
278 { sizeof(mbxname.body)-1, DVI$_DEVNAM, &mbxname.body, &mbxname.length },
280 struct itm$list3 syilist[2] = {
281 { sizeof(mbxsize), SYI$_MAXBUF, &mbxsize, (void *) 0 },
283 static int noExitHandler = 1;
286 /* First allocate space for the new pipe */
287 this = (struct PIPE *) calloc (1, sizeof(struct PIPE));
294 /* Sanity check value */
297 /* Use the smaller of SYI$_MAXBUF and 2048 for the mailbox size */
298 status = sys$getsyiw(0, 0, 0, syilist, &iosb, 0, 0, 0);
299 if (status != SS$_NORMAL && !(iosb.status & STS$M_SUCCESS))
301 vaxc$errno = iosb.status;
304 perror ("popen, $GETSYIW failure for SYI$_MAXBUF");
311 status = sys$crembx (0, &this->chan, mbxsize, mbxsize, 0, 0, 0, 0);
312 if (status != SS$_NORMAL)
317 perror ("popen, $CREMBX failure");
321 /* Retrieve mailbox name, use for fopen */
322 status = sys$getdviw (0, this->chan, 0, &mbxlist, &iosb, 0, 0, 0);
323 if (status != SS$_NORMAL && !(iosb.status & STS$M_SUCCESS))
325 vaxc$errno = iosb.status;
327 sys$dassgn (this->chan);
329 perror ("popen, $GETDVIW failure");
333 /* Spawn the command using the mailbox as the name for sys$input */
334 mbxname.body[mbxname.length] = 0;
335 mbxdsc.dsc$w_length = mbxname.length;
336 mbxdsc.dsc$b_dtype = DSC$K_DTYPE_T;
337 mbxdsc.dsc$b_class = DSC$K_CLASS_S;
338 mbxdsc.dsc$a_pointer = mbxname.body;
340 cmddsc.dsc$w_length = strlen(cmd);
341 cmddsc.dsc$b_dtype = DSC$K_DTYPE_T;
342 cmddsc.dsc$b_class = DSC$K_CLASS_S;
343 cmddsc.dsc$a_pointer = (char *)cmd;
344 flags = CLI$M_NOWAIT;
345 if (strcmp(mode,"w") == 0)
347 status = lib$spawn (&cmddsc, &mbxdsc, 0, &flags, 0, &this->pid,
348 &this->status, &evf, &pdone, this->self);
349 this->mode = O_WRONLY;
353 status = lib$spawn (&cmddsc, 0, &mbxdsc, &flags, 0, &this->pid,
354 &this->status, &evf, &pdone, this->self);
355 this->mode = O_RDONLY;
357 if (status != SS$_NORMAL)
361 sys$dassgn (this->chan);
363 perror("popen, LIB$SPAWN failure");
367 /* Set up an exit handler so the subprocess isn't prematurely killed */
370 status = sys$dclexh (&pexhcb);
371 if (status != SS$_NORMAL)
375 sys$dassgn (this->chan);
376 sys$delprc (&this->pid, 0);
378 perror("popen, $DCLEXH failure");
384 /* Pipes are always binary mode devices */
385 if (this->mode == O_WRONLY)
386 this->file = fopen (mbxname.body, "wb");
388 this->file = fopen (mbxname.body, "rb");
390 /* Paranoia, check for failure again */
393 sys$dassgn (this->chan);
394 sys$delprc (this->pid);
396 perror ("popen, fopen failure");
400 this->has_jmpbuf = 0;
402 /* Insert the new pipe into the list of open pipes */
410 phead = ptail = this;
427 printf ("\nEnter a command to run >> ");
428 fgets (line, 511, stdin);
431 line[strlen(line)-1] = 0;
432 stdpipe = popen (line, "r");
435 fprintf (stderr, "popen failed.\n");
439 fgets (line, 511, stdpipe);
440 fputs (line, stdout);
441 } while (!feof(stdpipe));
447 #else /* __VMS_VER >= 70200000 && __DECC_VER >= 50700000 */
448 #pragma message disable EMPTYFILE
449 #endif /* __VMS_VER >= 70200000 && __DECC_VER >= 50700000 */