1 /* Implement unix popen and pclose in vms by using mailboxes
2    and lib$spawn.
3    17-APR-91 -GJC@MITECH.COM version 1.0
4 */
5 
6 #include <stdio.h>
7 #include <descrip.h>
8 #include <ssdef.h>
9 #include <string.h>
10 
11 FILE *popen();
12 int pclose();
13 
14 globalvalue CLI$M_NOWAIT;
15 
16 void p_describe(); /* a non-unix function */
17 
18 static struct dsc$descriptor *set_dsc_cst();
19 static int create_mbx();
20 
21 #define mailbox_size (512)
22 #define mailbox_byte_quota (3*mailbox_size)
23 #define mailbox_protection_mask (0x0000F000)
24 
25 struct popen_cell
26 {FILE *fp;
27  char *mbx_name;
28  short mbx_chan;
29  long pid;
30  long completed;
31  long comp_status;
32  struct popen_cell *next;
33  struct popen_cell *prev;};
34 
35 static struct popen_cell *popen_list = NULL;
36 
find_popen_cell(fp)37 static struct popen_cell *find_popen_cell(fp)
38      FILE *fp;
39 {struct popen_cell *l;
40  for(l=popen_list;l != NULL; l = l->next)
41    if (l->fp == fp) return(l);
42  return(NULL);}
43 
p_describe(fp)44 void p_describe(fp)
45      FILE *fp;
46 {struct popen_cell *cell;
47  if (!(cell = find_popen_cell(fp)))
48    {printf("File pointer is not from popen, or it has been closed\n");
49     return;}
50  printf("FILE *fp                = %08X\n",cell->fp);
51  printf("char *mbx_name          = %s\n",cell->mbx_name);
52  printf("short mbx_chan          = %d\n",cell->mbx_chan);
53  printf("long pid                = %08X\n",cell->pid);
54  printf("long completed          = %d\n",cell->completed);
55  printf("long comp_status        = %d\n",cell->comp_status);
56  printf("struct popen_cell *next = %08X\n",cell->next);
57  printf("struct popen_cell *prev = %08X\n",cell->prev);}
58 
proc_exit_ast(cell)59 static void proc_exit_ast(cell)
60      struct popen_cell *cell;
61 {cell->completed = 1;}
62 
pclose_cleanup(cell)63 static void pclose_cleanup(cell)
64      struct popen_cell *cell;
65 {sys$dassgn(cell->mbx_chan);
66  free(cell->mbx_name);
67  if (!cell->completed)
68    sys$delprc(&cell->pid,0);
69  memset(cell,0,sizeof(struct popen_cell));
70  free(cell);}
71 
pclose_delq(cell)72 static void pclose_delq(cell)
73      struct popen_cell *cell;
74 {if (cell->prev)
75    {cell->prev->next = cell->next;
76     if (cell->next)
77       cell->next->prev = cell->prev;}
78  else
79    {popen_list = cell->next;
80     if (cell->next)
81       cell->next->prev = NULL;}}
82 
popen_push(cell)83 static void popen_push(cell)
84      struct popen_cell *cell;
85 {if (popen_list)
86    popen_list->prev = cell;
87  cell->prev = NULL;
88  cell->next = popen_list;
89  popen_list = cell;}
90 
pclose(fp)91 int pclose(fp)
92      FILE *fp;
93 {int i;
94  struct popen_cell *cell;
95  i = fclose(fp);
96  if (cell = find_popen_cell(fp))
97    {pclose_delq(cell);
98     pclose_cleanup(cell);}
99  return(i);}
100 
popen(command,mode)101 FILE *popen(command,mode)
102      char *command,*mode;
103 {char *temp;
104  struct popen_cell *cell;
105  int readp,n,mask,ret;
106  char *name,*prompt,*in,*out;
107  struct dsc$descriptor comm_d,in_d,out_d,name_d,prompt_d;
108 
109  if (strcmp(mode,"r") == 0)
110    readp = 1;
111  else if (strcmp(mode,"w") == 0)
112    readp = 0;
113  else
114    return(NULL);
115 
116  temp = mktemp("POPEN_MB_XXXXXXXXXX");
117  n = strlen(temp);
118   cell =  (struct popen_cell *) malloc(sizeof(struct popen_cell));
119  cell->mbx_name = (char *) malloc(n+1);
120  strcpy(cell->mbx_name,temp);
121  if ((cell->mbx_chan = create_mbx(cell->mbx_name)) < 0)
122    {cell->completed = 1;
123     pclose_cleanup(cell);
124     return(NULL);}
125 
126  if (readp)
127    {in = "NL:";
128     out = cell->mbx_name;}
129  else
130    {in = cell->mbx_name;
131     out = "NL:";}
132 
133  name = 0;
134  prompt = 0;
135  mask = CLI$M_NOWAIT;
136 
137  cell->completed = 0;
138 
139  ret = lib$spawn((command) ? set_dsc_cst(&comm_d,command) : 0,
140                  (in) ? set_dsc_cst(&in_d,in) : 0,
141                  (out) ? set_dsc_cst(&out_d,out) : 0,
142                  &mask,
143                  (name)  ? set_dsc_cst(&name_d,name) : 0,
144                  &cell->pid,
145                  &cell->comp_status,
146                  0, /* event flag */
147 		 proc_exit_ast,
148 		 cell,
149                  (prompt) ? set_dsc_cst(&prompt_d,prompt) : 0,
150                  0 /* cli */
151                  );
152 
153  if (ret != SS$_NORMAL)
154    {cell->completed = 1;
155     pclose_cleanup(cell);
156     return(NULL);}
157 
158  if (!(cell->fp = fopen(cell->mbx_name,mode)))
159    {pclose_cleanup(cell);
160     return(NULL);}
161 
162  popen_push(cell);
163 
164  return(cell->fp);}
165 
set_dsc_cst(x,buff)166 static struct dsc$descriptor *set_dsc_cst(x,buff)
167      struct dsc$descriptor *x;
168      char *buff;
169 {(*x).dsc$w_length = strlen(buff);
170  (*x).dsc$a_pointer = buff;
171  (*x).dsc$b_class = DSC$K_CLASS_S;
172  (*x).dsc$b_dtype = DSC$K_DTYPE_T;
173  return(x);}
174 
create_mbx(name)175 static int create_mbx(name)
176   char *name;
177 {short chan;
178  int prmflg,maxmsg,bufquo,promsk,acmode,iflag,retval;
179  struct dsc$descriptor lognam;
180  prmflg = 0;
181  maxmsg = mailbox_size;
182  bufquo = mailbox_byte_quota;
183  promsk = mailbox_protection_mask;
184  acmode = 0;
185  set_dsc_cst(&lognam,name);
186  retval = sys$crembx(prmflg,&chan,maxmsg,bufquo,promsk,acmode,&lognam);
187  if (retval != SS$_NORMAL) return(-1);
188  return(chan);}
189