8a55263264c3599c998da5c613a7b03f65d62db2
[oweals/cde.git] / cde / programs / dtmail / libDtMail / Common / Process.C
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these libraries and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /*
24  *+SNOTICE
25  *
26  *
27  *      $TOG: Process.C /main/6 1998/04/06 13:26:21 mgreess $
28  *
29  *      RESTRICTED CONFIDENTIAL INFORMATION:
30  *      
31  *      The information in this document is subject to special
32  *      restrictions in a confidential disclosure agreement bertween
33  *      HP, IBM, Sun, USL, SCO and Univel.  Do not distribute this
34  *      document outside HP, IBM, Sun, USL, SCO, or Univel wihtout
35  *      Sun's specific written approval.  This documment and all copies
36  *      and derivative works thereof must be returned or destroyed at
37  *      Sun's request.
38  *
39  *      Copyright 1993 Sun Microsystems, Inc.  All rights reserved.
40  *
41  *+ENOTICE
42  */
43
44 #include <unistd.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <fcntl.h>
48 #include <errno.h>
49 #include <poll.h>
50
51 /*
52 ** file included for INFTIM
53 */ 
54 #if defined(SunOS) || defined(USL) || defined(__uxp__)
55 #include <stropts.h>
56 #elif defined(HPUX)
57 #include <sys/poll.h>
58 #elif defined(_AIX) || defined(linux)
59 #define INFTIM (-1)             /* Infinite timeout */
60 #endif
61
62 #include <sys/wait.h>
63
64 #include "Process.hh"
65 #include <DtMail/Threads.hh>
66 #include <DtMail/IO.hh>
67
68 static const int DEFAULT_SIZE = 64 << 10;
69
70 void
71 SetNoBlock(int fd)
72 {
73     int flags;
74     do {
75         flags = fcntl(fd, F_GETFL);
76     } while(flags < 0 && errno == EINTR);
77
78     if (flags < 0) {
79         return;
80     }
81
82     flags |= O_NONBLOCK;
83
84     int status;
85     do {
86         status = fcntl(fd, F_SETFL, flags);
87     } while (status < 0 && errno == EINTR);
88
89     return;
90 }
91
92 int
93 RunProg(const char * program,
94         char *const * argv,
95         const char * stdin_data,
96         const unsigned long stdin_size,
97         char ** stdout_data,
98         unsigned long & stdout_size,
99         char ** stderr_data,
100         unsigned long & stderr_size)
101 {
102     // See if we are supposed to do I/O with the child.
103     //
104     int stdin_fd[2];
105     int stdout_fd[2];
106     int stderr_fd[2];
107
108     size_t stdout_bufsize = 0;
109     unsigned long stderr_bufsize = 0;
110
111     if (stdin_data) {
112         pipe(stdin_fd);
113         SetNoBlock(stdin_fd[1]);
114     }
115
116     if (stdout_data) {
117         pipe(stdout_fd);
118         SetNoBlock(stdout_fd[0]);
119     }
120
121     if (stderr_data) {
122         pipe(stderr_fd);
123         SetNoBlock(stderr_fd[0]);
124     }
125
126     // We will fork and set up the file descriptors in the
127     // child.
128     //
129
130 #if defined(POSIX_THREADS)
131     pid_t child = fork1();
132 #else
133     pid_t child = fork();
134 #endif
135
136     if (child < 0) {
137         return(child);
138     }
139
140     if (child == 0) { // The real child process.
141         if (stdin_data) {
142             SafeDup2(stdin_fd[0], STDIN_FILENO);
143             close(stdin_fd[0]);
144             close(stdin_fd[1]);
145         }
146
147         if (stdout_data) {
148             SafeDup2(stdout_fd[1], STDOUT_FILENO);
149             close(stdout_fd[0]);
150             close(stdout_fd[1]);
151         }
152
153         if (stderr_data) {
154             SafeDup2(stderr_fd[1], STDERR_FILENO);
155             close(stderr_fd[0]);
156             close(stderr_fd[1]);
157         }
158
159         SafeExecvp(program, argv);
160         return(child);
161     }
162     else { // This is still us.
163
164         int stdin_written = 0;
165
166         int nfds = 1;
167         pollfd fds[3];
168         memset(fds, 0, sizeof(fds));
169
170         fds[0].fd = stdin_fd[1];
171         fds[0].events = POLLOUT;
172         close(stdin_fd[0]);
173
174         if (stdout_data) {
175             fds[1].fd = stdout_fd[0];
176             fds[1].events = POLLIN;
177             nfds = 2;
178             *stdout_data = (char *)malloc(DEFAULT_SIZE);
179             stdout_bufsize = DEFAULT_SIZE;
180             stdout_size = 0;
181             close(stdout_fd[1]);
182         } else {
183             fds[1].fd = -1;
184         }
185
186         if (stderr_data) {
187             fds[2].fd = stderr_fd[0];
188             fds[2].events = POLLIN;
189             nfds = 3;
190             *stderr_data = (char *)malloc(DEFAULT_SIZE);
191             stderr_bufsize = DEFAULT_SIZE;
192             stderr_size = 0;
193             close(stderr_fd[1]);
194         } else {
195             fds[2].fd = -1;
196         }
197
198         // set up the initial events we way we care about.  Note that
199         // fds[1] and fds[2] may not be used -- nfds may be less than 3
200
201
202         while (1) {
203             int result;
204             int i;
205
206             // check to make sure there is really some work to do
207             // walk through the fds structure.  If we get to the end
208             // without finding anything to do, i will be == nfds
209             for (i = 0; i < nfds; i++) {
210                 if (fds[i].fd >= 0) break;
211             }
212             if (i == nfds) {
213                 // there was no work to do
214                 break;
215             }
216
217
218             // we probably don't want to wait forever, so we can try
219             // and reap the child here, just in case it exits...
220             result = poll(fds, nfds, INFTIM);
221
222             if (result < 0) {
223                 // poll error -- what do we do?
224                 if (errno == EINTR) continue;
225
226                 // not much else to do -- poll really shouldn't fail...
227                 break;
228             }
229
230             if ((fds[0].revents & POLLOUT) &&
231                 stdin_data && stdin_written < stdin_size) {
232                 int status = SafeWrite(stdin_fd[1], stdin_data + stdin_written,
233                                        (size_t) stdin_size - stdin_written);
234                 if (status > 0) {
235                     stdin_written += status;
236                 }
237
238                 if (stdin_written >= stdin_size) {
239                     // we're done with the input
240                     close(stdin_fd[1]);
241                     fds[0].fd = -1;
242                     fds[0].events = 0;
243                 }
244             }
245
246             // We will now try to read 4K from each requested file
247             // descriptor.
248             //
249             if (stdout_data && (fds[1].revents & POLLIN)) {
250                 int status = SafeRead(stdout_fd[0], *stdout_data + stdout_size,
251                                       4096);
252
253                 if (status < 0 && errno != EAGAIN) {
254                     break;
255                 }
256
257                 if (status > 0) {
258                     stdout_size += status;
259                     if ((stdout_size + 4096) > stdout_bufsize) {
260                         stdout_bufsize += DEFAULT_SIZE;
261                         *stdout_data = (char *)realloc(*stdout_data, stdout_bufsize);
262                     }
263                 }
264             }
265
266             if (stderr_data && (fds[2].revents & POLLIN)) {
267                 int status = SafeRead(stderr_fd[0], *stderr_data + stderr_size,
268                                       4096);
269
270                 if (status < 0 && errno != EAGAIN) {
271                     break;
272                 }
273
274                 if (status > 0) {
275                     stderr_size += status;
276                 }
277
278                 if ((stderr_size + 4096) > stderr_bufsize) {
279                     stderr_bufsize += DEFAULT_SIZE;
280                     *stderr_data =
281                       (char*) realloc(*stderr_data, (size_t) stderr_bufsize);
282                 }
283             }
284
285             if ((fds[0].revents & POLLHUP) ||
286                 (fds[1].revents & POLLHUP) ||
287                 (fds[2].revents & POLLHUP)) {
288                 break;
289             }
290         }
291
292         int child_stat;
293         SafeWaitpid(child, &child_stat, 0);
294         return(child_stat);
295     }
296     return(child);
297 }