cvs  1.11.23
About: CVS (Concurrent Versions System) is a version control system designed for software projects.
  Fossies Dox: cvs-1.11.23.tar.gz  ("inofficial" and yet experimental doxygen-generated source code documentation)  

popen.c
Go to the documentation of this file.
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
46 ll_insert (HFILE key, ULONG val)
47 {
48  struct pid_list *new;
49  new = (struct pid_list *) xmalloc (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
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
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
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
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 *
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
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
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
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 */
STDERR
#define STDERR
Definition: popen.c:25
pid_list
Definition: popen.c:34
O_RDONLY
#define O_RDONLY
Definition: system.h:131
NULL
#define NULL
Definition: getopt1.c:58
popen
FILE * popen(const char *Command, const char *Mode)
Definition: popen.c:153
main
int main(int argc, char **argv)
Definition: main.c:394
STDIN
#define STDIN
Definition: popen.c:23
pclose
int pclose(FILE *Pipe)
Definition: popen.c:330
getenv
char * getenv()
LL_KEY
#define LL_KEY
Definition: popen.c:21
STDOUT
#define STDOUT
Definition: popen.c:24
config.h
LL_VAL
#define LL_VAL
Definition: popen.c:20
pid_list::term_code
ULONG term_code
Definition: popen.c:37
os2inc.h
pid_ll
static struct pid_list * pid_ll
Definition: popen.c:41
xmalloc
char * xmalloc()
FALSE
#define FALSE
Definition: misc.c:98
ll_lookup
ULONG ll_lookup(HFILE key)
Definition: popen.c:87
pid_list::pid
HFILE pid
Definition: popen.c:36
free
void free()
ll_insert
void ll_insert(HFILE key, ULONG val)
Definition: popen.c:46
popenRW
int popenRW(const char **argv, int *pipes)
Definition: popen.c:250
pid_list::next
struct pid_list * next
Definition: popen.c:38
ll_delete
void ll_delete(int key)
Definition: popen.c:60