113571821Stholo /* popen.c -- popen/pclose for OS/2. */
213571821Stholo
313571821Stholo /* Set to 0 for distribution.
413571821Stholo Search for "DIAGNOSTIC" in the code to see what it's for. */
513571821Stholo #define DIAGNOSTIC 0
613571821Stholo
713571821Stholo #include <process.h>
813571821Stholo
913571821Stholo #include <stdio.h>
1013571821Stholo #include <stdlib.h>
1113571821Stholo #include <sys/types.h>
1213571821Stholo #include <sys/stat.h>
1313571821Stholo #include <ctype.h>
1413571821Stholo #include <string.h>
1513571821Stholo #include <fcntl.h>
1613571821Stholo
17*461cc63eStholo #include "config.h"
18*461cc63eStholo #include "os2inc.h"
19*461cc63eStholo
2013571821Stholo #define LL_VAL ULONG
2113571821Stholo #define LL_KEY PID /* also ULONG, really */
2213571821Stholo
2313571821Stholo #define STDIN 0
2413571821Stholo #define STDOUT 1
2513571821Stholo #define STDERR 2
2613571821Stholo
2713571821Stholo /* ********************************************************************* *
2813571821Stholo * *
2913571821Stholo * First, a little linked-list library to help keep track of pipes: *
3013571821Stholo * *
3113571821Stholo * ********************************************************************* */
3213571821Stholo
3313571821Stholo /* Map integer PID's onto integer termination codes. */
3413571821Stholo struct pid_list
3513571821Stholo {
3613571821Stholo HFILE pid; /* key */
3713571821Stholo ULONG term_code; /* val */
3813571821Stholo struct pid_list *next; /* duh */
3913571821Stholo };
4013571821Stholo
4113571821Stholo static struct pid_list *pid_ll = (struct pid_list *) NULL;
4213571821Stholo
4313571821Stholo /* The ll_*() functions all make use of the global var `pid_ll'. */
4413571821Stholo
4513571821Stholo void
ll_insert(HFILE key,ULONG val)4613571821Stholo ll_insert (HFILE key, ULONG val)
4713571821Stholo {
4813571821Stholo struct pid_list *new;
4913571821Stholo new = (struct pid_list *) malloc (sizeof (*new));
5013571821Stholo
5113571821Stholo new->pid = key;
5213571821Stholo new->term_code = val;
5313571821Stholo new->next = pid_ll;
5413571821Stholo
5513571821Stholo pid_ll = new;
5613571821Stholo }
5713571821Stholo
5813571821Stholo
5913571821Stholo void
ll_delete(int key)6013571821Stholo ll_delete (int key)
6113571821Stholo {
6213571821Stholo struct pid_list *this, *last;
6313571821Stholo
6413571821Stholo this = pid_ll;
6513571821Stholo last = (struct pid_list *) NULL;
6613571821Stholo
6713571821Stholo while (this)
6813571821Stholo {
6913571821Stholo if (this->pid == key)
7013571821Stholo {
7113571821Stholo /* Delete this node and leave. */
7213571821Stholo if (last)
7313571821Stholo last->next = this->next;
7413571821Stholo else
7513571821Stholo pid_ll = this->next;
7613571821Stholo free (this);
7713571821Stholo return;
7813571821Stholo }
7913571821Stholo
8013571821Stholo /* Else no match, so try the next one. */
8113571821Stholo last = this;
8213571821Stholo this = this->next;
8313571821Stholo }
8413571821Stholo }
8513571821Stholo
8613571821Stholo ULONG
ll_lookup(HFILE key)8713571821Stholo ll_lookup (HFILE key)
8813571821Stholo {
8913571821Stholo struct pid_list *this = pid_ll;
9013571821Stholo
9113571821Stholo while (this)
9213571821Stholo {
9313571821Stholo if (this->pid == key)
9413571821Stholo return this->term_code;
9513571821Stholo
9613571821Stholo /* Else no match, so try the next one. */
9713571821Stholo this = this->next;
9813571821Stholo }
9913571821Stholo
10013571821Stholo /* Zero is special in this context anyway. */
10113571821Stholo return 0;
10213571821Stholo }
10313571821Stholo
10413571821Stholo #if DIAGNOSTIC
10513571821Stholo ULONG
ll_length()10613571821Stholo ll_length ()
10713571821Stholo {
10813571821Stholo struct pid_list *this = pid_ll;
10913571821Stholo unsigned long int len;
11013571821Stholo
11113571821Stholo for (len = 0; this; len++)
11213571821Stholo this = this->next;
11313571821Stholo
11413571821Stholo return len;
11513571821Stholo }
11613571821Stholo
11713571821Stholo ULONG
ll_print()11813571821Stholo ll_print ()
11913571821Stholo {
12013571821Stholo struct pid_list *this = pid_ll;
12113571821Stholo unsigned long int i;
12213571821Stholo
12313571821Stholo for (i = 0; this; i++)
12413571821Stholo {
12513571821Stholo printf ("pid_ll[%d] == (%5d --> %5d)\n",
12613571821Stholo i, this->pid, this->term_code);
12713571821Stholo this = this->next;
12813571821Stholo }
12913571821Stholo
13013571821Stholo if (i == 0)
13113571821Stholo printf ("No entries.\n");
13213571821Stholo
13313571821Stholo return i;
13413571821Stholo }
13513571821Stholo #endif /* DIAGNOSTIC */
13613571821Stholo
13713571821Stholo /* ********************************************************************* *
13813571821Stholo * *
13913571821Stholo * End of linked-list library, beginning of popen/pclose: *
14013571821Stholo * *
14113571821Stholo * ********************************************************************* */
14213571821Stholo
14313571821Stholo /*
14413571821Stholo * Routine: popen
14513571821Stholo * Returns: FILE pointer to pipe.
14613571821Stholo * Action : Exec program connected via pipe, connect a FILE * to the
14713571821Stholo * pipe and return it.
14813571821Stholo * Params : Command - Program to run
14913571821Stholo * Mode - Mode to open pipe. "r" implies pipe is connected
15013571821Stholo * to the programs stdout, "w" connects to stdin.
15113571821Stholo */
15213571821Stholo FILE *
popen(const char * Command,const char * Mode)15313571821Stholo popen (const char *Command, const char *Mode)
15413571821Stholo {
15513571821Stholo HFILE End1, End2, Std, Old1, Old2, Tmp;
15613571821Stholo
15713571821Stholo FILE *File;
15813571821Stholo
15913571821Stholo char Fail[256],
16013571821Stholo *Args,
16113571821Stholo CmdLine[256],
16213571821Stholo *CmdExe;
16313571821Stholo
16413571821Stholo RESULTCODES
16513571821Stholo Result;
16613571821Stholo
16713571821Stholo int Rc;
16813571821Stholo
16913571821Stholo if (DosCreatePipe (&End1, &End2, 4096))
17013571821Stholo return NULL;
17113571821Stholo
17213571821Stholo Std = (*Mode == 'w') ? STDIN : STDOUT ;
17313571821Stholo if (Std == STDIN)
17413571821Stholo {
17513571821Stholo Tmp = End1; End1 = End2; End2 = Tmp;
17613571821Stholo }
17713571821Stholo
17813571821Stholo Old1 = -1; /* save stdin or stdout */
17913571821Stholo DosDupHandle (Std, &Old1);
18013571821Stholo DosSetFHState (Old1, OPEN_FLAGS_NOINHERIT);
18113571821Stholo Tmp = Std; /* redirect stdin or stdout */
18213571821Stholo DosDupHandle (End2, &Tmp);
18313571821Stholo
18413571821Stholo if (Std == 1)
18513571821Stholo {
18613571821Stholo Old2 = -1; /* save stderr */
18713571821Stholo DosDupHandle (STDERR, &Old2);
18813571821Stholo DosSetFHState (Old2, OPEN_FLAGS_NOINHERIT);
18913571821Stholo Tmp = STDERR;
19013571821Stholo DosDupHandle (End2, &Tmp);
19113571821Stholo }
19213571821Stholo
19313571821Stholo DosClose (End2);
19413571821Stholo DosSetFHState (End1, OPEN_FLAGS_NOINHERIT);
19513571821Stholo
19613571821Stholo if ((CmdExe = getenv ("COMSPEC")) == NULL )
19713571821Stholo CmdExe = "cmd.exe";
19813571821Stholo
19913571821Stholo strcpy (CmdLine, CmdExe);
20013571821Stholo Args = CmdLine + strlen (CmdLine) + 1; /* skip zero */
20113571821Stholo strcpy (Args, "/c ");
20213571821Stholo strcat (Args, Command);
20313571821Stholo Args[strlen (Args) + 1] = '\0'; /* two zeroes */
20413571821Stholo Rc = DosExecPgm (Fail, sizeof (Fail), EXEC_ASYNCRESULT,
20513571821Stholo (unsigned char *) CmdLine, 0, &Result,
20613571821Stholo (unsigned char *) CmdExe);
20713571821Stholo
20813571821Stholo Tmp = Std; /* restore stdin or stdout */
20913571821Stholo DosDupHandle (Old1, &Tmp);
21013571821Stholo DosClose (Old1);
21113571821Stholo
21213571821Stholo if (Std == STDOUT)
21313571821Stholo {
21413571821Stholo Tmp = STDERR; /* restore stderr */
21513571821Stholo DosDupHandle (Old2, &Tmp);
21613571821Stholo DosClose (Old2);
21713571821Stholo }
21813571821Stholo
21913571821Stholo if (Rc)
22013571821Stholo {
22113571821Stholo DosClose (End1);
22213571821Stholo return NULL;
22313571821Stholo }
22413571821Stholo
225*461cc63eStholo #ifdef __WATCOMC__
226*461cc63eStholo /* Watcom does not allow mixing operating system handles and
227*461cc63eStholo * C library handles, so we have to convert.
228*461cc63eStholo */
229*461cc63eStholo File = fdopen (_hdopen (End1, *Mode == 'w'? O_WRONLY : O_RDONLY), Mode);
230*461cc63eStholo #else
23113571821Stholo File = fdopen (End1, Mode);
232*461cc63eStholo #endif
23313571821Stholo ll_insert ((LL_KEY) End1, (LL_VAL) Result.codeTerminate);
23413571821Stholo
23513571821Stholo return File;
23613571821Stholo }
23713571821Stholo
23813571821Stholo
23913571821Stholo /*
24013571821Stholo * Routine: popenRW
24113571821Stholo * Returns: PID of child process
24213571821Stholo * Action : Exec program connected via pipe, connect int fd's to
24313571821Stholo * both the stdin and stdout of the process.
24413571821Stholo * Params : Command - Program to run
24513571821Stholo * Pipes - Array of 2 ints to store the pipe descriptors
24613571821Stholo * Pipe[0] writes to child's stdin,
24713571821Stholo * Pipe[1] reads from child's stdout/stderr
24813571821Stholo */
24913571821Stholo int
popenRW(const char ** argv,int * pipes)25013571821Stholo popenRW (const char **argv, int *pipes)
25113571821Stholo {
25213571821Stholo HFILE Out1, Out2, In1, In2;
25313571821Stholo HFILE Old0 = -1, Old1 = -1, Old2 = -1, Tmp;
25413571821Stholo
255*461cc63eStholo int pid;
25613571821Stholo
25713571821Stholo if (DosCreatePipe (&Out2, &Out1, 4096))
25813571821Stholo return FALSE;
25913571821Stholo
26013571821Stholo if (DosCreatePipe (&In1, &In2, 4096))
26113571821Stholo {
26213571821Stholo DosClose (Out1);
26313571821Stholo DosClose (Out2);
26413571821Stholo return FALSE;
26513571821Stholo }
26613571821Stholo
26713571821Stholo /* Save std{in,out,err} */
26813571821Stholo DosDupHandle (STDIN, &Old0);
26913571821Stholo DosSetFHState (Old1, OPEN_FLAGS_NOINHERIT);
27013571821Stholo DosDupHandle (STDOUT, &Old1);
27113571821Stholo DosSetFHState (Old2, OPEN_FLAGS_NOINHERIT);
27213571821Stholo DosDupHandle (STDERR, &Old2);
27313571821Stholo DosSetFHState (Old2, OPEN_FLAGS_NOINHERIT);
27413571821Stholo
27513571821Stholo /* Redirect std{in,out,err} */
27613571821Stholo Tmp = STDIN;
27713571821Stholo DosDupHandle (In1, &Tmp);
27813571821Stholo Tmp = STDOUT;
27913571821Stholo DosDupHandle (Out1, &Tmp);
28013571821Stholo Tmp = STDERR;
28113571821Stholo DosDupHandle (Out1, &Tmp);
28213571821Stholo
28313571821Stholo /* Close file handles not needed in child */
28413571821Stholo
28513571821Stholo DosClose (In1);
28613571821Stholo DosClose (Out1);
28713571821Stholo DosSetFHState (In2, OPEN_FLAGS_NOINHERIT);
28813571821Stholo DosSetFHState (Out2, OPEN_FLAGS_NOINHERIT);
28913571821Stholo
29013571821Stholo /* Spawn we now our hoary brood. */
29113571821Stholo pid = spawnvp (P_NOWAIT, argv[0], argv);
29213571821Stholo
29313571821Stholo /* Restore std{in,out,err} */
29413571821Stholo Tmp = STDIN;
29513571821Stholo DosDupHandle (Old0, &Tmp);
29613571821Stholo DosClose (Old0);
29713571821Stholo Tmp = STDOUT;
29813571821Stholo DosDupHandle (Old1, &Tmp);
29913571821Stholo DosClose (Old1);
30013571821Stholo Tmp = STDERR;
30113571821Stholo DosDupHandle (Old2, &Tmp);
30213571821Stholo DosClose (Old2);
30313571821Stholo
30413571821Stholo if(pid < 0)
30513571821Stholo {
30613571821Stholo DosClose (In2);
30713571821Stholo DosClose (Out2);
30813571821Stholo return -1;
30913571821Stholo }
31013571821Stholo
31113571821Stholo pipes[0] = In2;
31213571821Stholo _setmode (pipes[0], O_BINARY);
31313571821Stholo pipes[1] = Out2;
31413571821Stholo _setmode (pipes[1], O_BINARY);
31513571821Stholo
31613571821Stholo /* Save ID of write-to-child pipe for pclose() */
31713571821Stholo ll_insert ((LL_KEY) In2, (LL_VAL) pid);
31813571821Stholo
31913571821Stholo return pid;
32013571821Stholo }
32113571821Stholo
32213571821Stholo
32313571821Stholo /*
32413571821Stholo * Routine: pclose
32513571821Stholo * Returns: TRUE on success
32613571821Stholo * Action : Close a pipe opened with popen();
32713571821Stholo * Params : Pipe - pipe to close
32813571821Stholo */
32913571821Stholo int
pclose(FILE * Pipe)33013571821Stholo pclose (FILE *Pipe)
33113571821Stholo {
33213571821Stholo RESULTCODES rc;
33313571821Stholo PID pid, pid1;
33413571821Stholo int Handle = fileno (Pipe);
33513571821Stholo
33613571821Stholo fclose (Pipe);
33713571821Stholo
33813571821Stholo rc.codeTerminate = -1;
33913571821Stholo
34013571821Stholo pid1 = (PID) ll_lookup ((LL_KEY) Handle);
34113571821Stholo /* if pid1 is zero, something's seriously wrong */
34213571821Stholo if (pid1 != 0)
34313571821Stholo {
34413571821Stholo DosWaitChild (DCWA_PROCESSTREE, DCWW_WAIT, &rc, &pid, pid1);
34513571821Stholo ll_delete ((LL_KEY) Handle);
34613571821Stholo }
34713571821Stholo return rc.codeTerminate == 0 ? rc.codeResult : -1;
34813571821Stholo }
34913571821Stholo
35013571821Stholo
35113571821Stholo #if DIAGNOSTIC
35213571821Stholo void
main()35313571821Stholo main ()
35413571821Stholo {
35513571821Stholo FILE *fp1, *fp2, *fp3;
35613571821Stholo int c;
35713571821Stholo
35813571821Stholo ll_print ();
35913571821Stholo fp1 = popen ("gcc --version", "r");
36013571821Stholo ll_print ();
36113571821Stholo fp2 = popen ("link386 /?", "r");
36213571821Stholo ll_print ();
36313571821Stholo fp3 = popen ("dir", "r");
36413571821Stholo ll_print ();
36513571821Stholo
36613571821Stholo while ((c = getc (fp1)) != EOF)
36713571821Stholo printf ("%c", c);
36813571821Stholo
36913571821Stholo while ((c = getc (fp2)) != EOF)
37013571821Stholo printf ("%c", c);
37113571821Stholo
37213571821Stholo while ((c = getc (fp3)) != EOF)
37313571821Stholo printf ("%c", c);
37413571821Stholo
37513571821Stholo pclose (fp1);
37613571821Stholo ll_print ();
37713571821Stholo pclose (fp2);
37813571821Stholo ll_print ();
37913571821Stholo pclose (fp3);
38013571821Stholo ll_print ();
38113571821Stholo
38213571821Stholo return;
38313571821Stholo }
38413571821Stholo
38513571821Stholo #endif /* DIAGNOSTIC */
386