xref: /openbsd/gnu/usr.bin/cvs/os2/popen.c (revision 461cc63e)
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