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