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