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 *) 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 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 */ 386