2 * Pipe support for OS/2.
4 * WARNING: I am guilty of chumminess with the runtime library because
5 * I had no choice. Details to follow.
11 #define INCL_DOSPROCESS
12 #define INCL_DOSQUEUES
14 #define INCL_DOSMEMMGR
17 extern char **environ;
19 /* This mysterious array _osfile is used internally by the runtime
20 * library to remember assorted things about open file handles.
21 * The problem is that we are creating file handles via DosMakePipe,
22 * rather than via the runtime library. This means that we have
23 * to fake the runtime library into thinking that the handles we've
24 * created are honest file handles. So just before doing the fdopen,
25 * we poke in a magic value that fools the library functions into
26 * thinking that the handle is already open in text mode.
28 * This might not work for your compiler, so beware.
30 extern char _osfile[];
32 /* The maximum number of simultaneously open pipes. We create an
33 * array of this size to record information about each open pipe.
37 /* Information to remember about each open pipe.
38 * The (FILE *) that popen returns is stored because that's the only
39 * way we can keep track of the pipes.
41 typedef struct pipeinfo {
42 FILE *pfId; /* Which FILE we're talking about */
43 HFILE hfMe; /* handle I should close at pclose */
44 PID pidChild; /* Child's PID */
45 CHAR fReading; /* A read or write pipe? */
46 } PIPEINFO, *PPIPEINFO; /* pi and ppi */
48 static PIPEINFO PipeInfo[MAXPIPES];
50 FILE *mypopen(const char *command, const char *t)
53 PSZZ pszzPipeArgs = 0;
65 /* Validate pipe type */
66 if (*t != 'w' && *t != 'r') fatal("Unknown pipe type");
68 /* Room for another pipe? */
69 for (ppi = &PipeInfo[0]; ppi < &PipeInfo[MAXPIPES]; ppi++)
70 if (ppi->pfId == 0) goto foundone;
76 if (DosMakePipe(&hfMe, &hfYou, 0)) return NULL;
78 /* Build the environment. First compute its length, then copy
79 * the environment strings into it.
82 for (ppsz = environ; *ppsz; ppsz++) i += 1 + strlen(*ppsz);
83 New(1204, pszzEnviron, 1+i, CHAR);
86 for (ppsz = environ; *ppsz; ppsz++) {
88 psz += 1 + strlen(*ppsz);
92 /* Build the command string to execute.
93 * 6 = length(0 "/c " 0 0)
95 if (DosScanEnv("COMSPEC", &psz)) psz = "C:\\OS2\\cmd.exe";
97 New(1203, pszzPipeArgs, strlen(psz) + strlen(command) + 6, CHAR);
99 #define pszzPipeArgs buf
101 sprintf(pszzPipeArgs, "%s%c/c %s%c", psz, 0, command, 0);
103 /* Now some stuff that depends on what kind of pipe we're doing.
104 * We pull a sneaky trick; namely, that stdin = 0 = false,
105 * and stdout = 1 = true. The end result is that if the
106 * pipe is a read pipe, then hf = 1; if it's a write pipe, then
107 * hf = 0 and Me and You are reversed.
109 if (!(hf = (*t == 'r'))) {
110 /* The meaning of Me and You is reversed for write pipes. */
111 hfSave = hfYou; hfYou = hfMe; hfMe = hfSave;
116 /* Trick number 1: Fooling the runtime library into thinking
117 * that the file handle is legit.
119 * Trick number 2: Don't let my handle go over to the child!
120 * Since the child never closes it (why should it?), I'd better
121 * make sure he never sees it in the first place. Otherwise,
122 * we are in deadlock city.
124 _osfile[hfMe] = 0x81; /* Danger, Will Robinson! */
125 if (!(ppi->pfId = fdopen(hfMe, t))) goto no_fdopen;
126 DosSetFHandState(hfMe, OPEN_FLAGS_NOINHERIT);
128 /* Save the original handle because we're going to diddle it */
130 if (DosDupHandle(hf, &hfSave)) goto no_dup_init;
132 /* Force the child's handle onto the stdio handle */
133 if (DosDupHandle(hfYou, &hf)) goto no_force_dup;
136 /* Now run the guy servicing the pipe */
137 us = DosExecPgm(NULL, 0, EXEC_ASYNCRESULT, pszzPipeArgs, pszzEnviron,
140 /* Restore stdio handle, even if exec failed. */
141 DosDupHandle(hfSave, &hf); close(hfSave);
143 /* See if the exec succeeded. */
144 if (us) goto no_exec_pgm;
146 /* Remember the child's PID */
147 ppi->pidChild = rc.codeTerminate;
149 Safefree(pszzEnviron);
154 /* Here is where we clean up after an error. */
156 no_force_dup: close(hfSave);
157 no_dup_init: fclose(f);
159 DosClose(hfMe); DosClose(hfYou);
161 Safefree(pszzEnviron);
166 /* mypclose: Closes the pipe associated with the file handle.
167 * After waiting for the child process to terminate, its return
168 * code is returned. If the stream was not associated with a pipe,
178 /* Find the pipe this (FILE *) refers to */
179 for (ppi = &PipeInfo[0]; ppi < &PipeInfo[MAXPIPES]; ppi++)
180 if (ppi->pfId == f) goto foundit;
183 if (ppi->fReading && !DosRead(fileno(f), &rc, 1, &us) && us > 0) {
184 DosKillProcess(DKP_PROCESSTREE, ppi->pidChild);
187 DosCwait(DCWA_PROCESS, DCWW_WAIT, &rc, &ppi->pidChild, ppi->pidChild);
189 return rc.codeResult;
192 /* pipe: The only tricky thing is letting the runtime library know about
193 * our two new file descriptors.
195 int pipe(int filedes[2])
197 HFILE hfRead, hfWrite;
200 usResult = DosMakePipe(&hfRead, &hfWrite, 0);
202 /* Error 4 == ERROR_TOO_MANY_OPEN_FILES */
203 errno = (usResult == 4) ? ENFILE : ENOMEM;
206 _osfile[hfRead] = _osfile[hfWrite] = 0x81;/* Danger, Will Robinson! */
208 filedes[1] = hfWrite;