1 /* popen.c -- popen/pclose for OS/2. */
2
3 /* Set to 0 for distribution.
4 Search for "DIAGNOSTIC" in the code to see what it's for. */
5 #define DIAGNOSTIC 0
6
7 #include <process.h>
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <sys/types.h>
12 #include <sys/stat.h>
13 #include <ctype.h>
14 #include <string.h>
15 #include <fcntl.h>
16
17 #include "config.h"
18 #include "os2inc.h"
19
20 #define LL_VAL ULONG
21 #define LL_KEY PID /* also ULONG, really */
22
23 #define STDIN 0
24 #define STDOUT 1
25 #define STDERR 2
26
27 /* ********************************************************************* *
28 * *
29 * First, a little linked-list library to help keep track of pipes: *
30 * *
31 * ********************************************************************* */
32
33 /* Map integer PID's onto integer termination codes. */
34 struct pid_list
35 {
36 HFILE pid; /* key */
37 ULONG term_code; /* val */
38 struct pid_list *next; /* duh */
39 };
40
41 static struct pid_list *pid_ll = (struct pid_list *) NULL;
42
43 /* The ll_*() functions all make use of the global var `pid_ll'. */
44
45 void
ll_insert(HFILE key,ULONG val)46 ll_insert (HFILE key, ULONG val)
47 {
48 struct pid_list *new;
49 new = (struct pid_list *) malloc (sizeof (*new));
50
51 new->pid = key;
52 new->term_code = val;
53 new->next = pid_ll;
54
55 pid_ll = new;
56 }
57
58
59 void
ll_delete(int key)60 ll_delete (int key)
61 {
62 struct pid_list *this, *last;
63
64 this = pid_ll;
65 last = (struct pid_list *) NULL;
66
67 while (this)
68 {
69 if (this->pid == key)
70 {
71 /* Delete this node and leave. */
72 if (last)
73 last->next = this->next;
74 else
75 pid_ll = this->next;
76 free (this);
77 return;
78 }
79
80 /* Else no match, so try the next one. */
81 last = this;
82 this = this->next;
83 }
84 }
85
86 ULONG
ll_lookup(HFILE key)87 ll_lookup (HFILE key)
88 {
89 struct pid_list *this = pid_ll;
90
91 while (this)
92 {
93 if (this->pid == key)
94 return this->term_code;
95
96 /* Else no match, so try the next one. */
97 this = this->next;
98 }
99
100 /* Zero is special in this context anyway. */
101 return 0;
102 }
103
104 #if DIAGNOSTIC
105 ULONG
ll_length()106 ll_length ()
107 {
108 struct pid_list *this = pid_ll;
109 unsigned long int len;
110
111 for (len = 0; this; len++)
112 this = this->next;
113
114 return len;
115 }
116
117 ULONG
ll_print()118 ll_print ()
119 {
120 struct pid_list *this = pid_ll;
121 unsigned long int i;
122
123 for (i = 0; this; i++)
124 {
125 printf ("pid_ll[%d] == (%5d --> %5d)\n",
126 i, this->pid, this->term_code);
127 this = this->next;
128 }
129
130 if (i == 0)
131 printf ("No entries.\n");
132
133 return i;
134 }
135 #endif /* DIAGNOSTIC */
136
137 /* ********************************************************************* *
138 * *
139 * End of linked-list library, beginning of popen/pclose: *
140 * *
141 * ********************************************************************* */
142
143 /*
144 * Routine: popen
145 * Returns: FILE pointer to pipe.
146 * Action : Exec program connected via pipe, connect a FILE * to the
147 * pipe and return it.
148 * Params : Command - Program to run
149 * Mode - Mode to open pipe. "r" implies pipe is connected
150 * to the programs stdout, "w" connects to stdin.
151 */
152 FILE *
popen(const char * Command,const char * Mode)153 popen (const char *Command, const char *Mode)
154 {
155 HFILE End1, End2, Std, Old1, Old2, Tmp;
156
157 FILE *File;
158
159 char Fail[256],
160 *Args,
161 CmdLine[256],
162 *CmdExe;
163
164 RESULTCODES
165 Result;
166
167 int Rc;
168
169 if (DosCreatePipe (&End1, &End2, 4096))
170 return NULL;
171
172 Std = (*Mode == 'w') ? STDIN : STDOUT ;
173 if (Std == STDIN)
174 {
175 Tmp = End1; End1 = End2; End2 = Tmp;
176 }
177
178 Old1 = -1; /* save stdin or stdout */
179 DosDupHandle (Std, &Old1);
180 DosSetFHState (Old1, OPEN_FLAGS_NOINHERIT);
181 Tmp = Std; /* redirect stdin or stdout */
182 DosDupHandle (End2, &Tmp);
183
184 if (Std == 1)
185 {
186 Old2 = -1; /* save stderr */
187 DosDupHandle (STDERR, &Old2);
188 DosSetFHState (Old2, OPEN_FLAGS_NOINHERIT);
189 Tmp = STDERR;
190 DosDupHandle (End2, &Tmp);
191 }
192
193 DosClose (End2);
194 DosSetFHState (End1, OPEN_FLAGS_NOINHERIT);
195
196 if ((CmdExe = getenv ("COMSPEC")) == NULL )
197 CmdExe = "cmd.exe";
198
199 strcpy (CmdLine, CmdExe);
200 Args = CmdLine + strlen (CmdLine) + 1; /* skip zero */
201 strcpy (Args, "/c ");
202 strcat (Args, Command);
203 Args[strlen (Args) + 1] = '\0'; /* two zeroes */
204 Rc = DosExecPgm (Fail, sizeof (Fail), EXEC_ASYNCRESULT,
205 (unsigned char *) CmdLine, 0, &Result,
206 (unsigned char *) CmdExe);
207
208 Tmp = Std; /* restore stdin or stdout */
209 DosDupHandle (Old1, &Tmp);
210 DosClose (Old1);
211
212 if (Std == STDOUT)
213 {
214 Tmp = STDERR; /* restore stderr */
215 DosDupHandle (Old2, &Tmp);
216 DosClose (Old2);
217 }
218
219 if (Rc)
220 {
221 DosClose (End1);
222 return NULL;
223 }
224
225 #ifdef __WATCOMC__
226 /* Watcom does not allow mixing operating system handles and
227 * C library handles, so we have to convert.
228 */
229 File = fdopen (_hdopen (End1, *Mode == 'w'? O_WRONLY : O_RDONLY), Mode);
230 #else
231 File = fdopen (End1, Mode);
232 #endif
233 ll_insert ((LL_KEY) End1, (LL_VAL) Result.codeTerminate);
234
235 return File;
236 }
237
238
239 /*
240 * Routine: popenRW
241 * Returns: PID of child process
242 * Action : Exec program connected via pipe, connect int fd's to
243 * both the stdin and stdout of the process.
244 * Params : Command - Program to run
245 * Pipes - Array of 2 ints to store the pipe descriptors
246 * Pipe[0] writes to child's stdin,
247 * Pipe[1] reads from child's stdout/stderr
248 */
249 int
popenRW(const char ** argv,int * pipes)250 popenRW (const char **argv, int *pipes)
251 {
252 HFILE Out1, Out2, In1, In2;
253 HFILE Old0 = -1, Old1 = -1, Old2 = -1, Tmp;
254
255 int pid;
256
257 if (DosCreatePipe (&Out2, &Out1, 4096))
258 return FALSE;
259
260 if (DosCreatePipe (&In1, &In2, 4096))
261 {
262 DosClose (Out1);
263 DosClose (Out2);
264 return FALSE;
265 }
266
267 /* Save std{in,out,err} */
268 DosDupHandle (STDIN, &Old0);
269 DosSetFHState (Old1, OPEN_FLAGS_NOINHERIT);
270 DosDupHandle (STDOUT, &Old1);
271 DosSetFHState (Old2, OPEN_FLAGS_NOINHERIT);
272 DosDupHandle (STDERR, &Old2);
273 DosSetFHState (Old2, OPEN_FLAGS_NOINHERIT);
274
275 /* Redirect std{in,out,err} */
276 Tmp = STDIN;
277 DosDupHandle (In1, &Tmp);
278 Tmp = STDOUT;
279 DosDupHandle (Out1, &Tmp);
280 Tmp = STDERR;
281 DosDupHandle (Out1, &Tmp);
282
283 /* Close file handles not needed in child */
284
285 DosClose (In1);
286 DosClose (Out1);
287 DosSetFHState (In2, OPEN_FLAGS_NOINHERIT);
288 DosSetFHState (Out2, OPEN_FLAGS_NOINHERIT);
289
290 /* Spawn we now our hoary brood. */
291 pid = spawnvp (P_NOWAIT, argv[0], argv);
292
293 /* Restore std{in,out,err} */
294 Tmp = STDIN;
295 DosDupHandle (Old0, &Tmp);
296 DosClose (Old0);
297 Tmp = STDOUT;
298 DosDupHandle (Old1, &Tmp);
299 DosClose (Old1);
300 Tmp = STDERR;
301 DosDupHandle (Old2, &Tmp);
302 DosClose (Old2);
303
304 if(pid < 0)
305 {
306 DosClose (In2);
307 DosClose (Out2);
308 return -1;
309 }
310
311 pipes[0] = In2;
312 _setmode (pipes[0], O_BINARY);
313 pipes[1] = Out2;
314 _setmode (pipes[1], O_BINARY);
315
316 /* Save ID of write-to-child pipe for pclose() */
317 ll_insert ((LL_KEY) In2, (LL_VAL) pid);
318
319 return pid;
320 }
321
322
323 /*
324 * Routine: pclose
325 * Returns: TRUE on success
326 * Action : Close a pipe opened with popen();
327 * Params : Pipe - pipe to close
328 */
329 int
pclose(FILE * Pipe)330 pclose (FILE *Pipe)
331 {
332 RESULTCODES rc;
333 PID pid, pid1;
334 int Handle = fileno (Pipe);
335
336 fclose (Pipe);
337
338 rc.codeTerminate = -1;
339
340 pid1 = (PID) ll_lookup ((LL_KEY) Handle);
341 /* if pid1 is zero, something's seriously wrong */
342 if (pid1 != 0)
343 {
344 DosWaitChild (DCWA_PROCESSTREE, DCWW_WAIT, &rc, &pid, pid1);
345 ll_delete ((LL_KEY) Handle);
346 }
347 return rc.codeTerminate == 0 ? rc.codeResult : -1;
348 }
349
350
351 #if DIAGNOSTIC
352 void
main()353 main ()
354 {
355 FILE *fp1, *fp2, *fp3;
356 int c;
357
358 ll_print ();
359 fp1 = popen ("gcc --version", "r");
360 ll_print ();
361 fp2 = popen ("link386 /?", "r");
362 ll_print ();
363 fp3 = popen ("dir", "r");
364 ll_print ();
365
366 while ((c = getc (fp1)) != EOF)
367 printf ("%c", c);
368
369 while ((c = getc (fp2)) != EOF)
370 printf ("%c", c);
371
372 while ((c = getc (fp3)) != EOF)
373 printf ("%c", c);
374
375 pclose (fp1);
376 ll_print ();
377 pclose (fp2);
378 ll_print ();
379 pclose (fp3);
380 ll_print ();
381
382 return;
383 }
384
385 #endif /* DIAGNOSTIC */
386