MotifUI.C: NULL is not 0
[oweals/cde.git] / cde / programs / dtprintinfo / util / Invoke.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 librararies 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 /* $TOG: Invoke.C /main/7 1997/07/30 15:42:39 samborn $ */
24 /*                                                                      *
25  * (c) Copyright 1993, 1994 Hewlett-Packard Company                     *
26  * (c) Copyright 1993, 1994 International Business Machines Corp.       *
27  * (c) Copyright 1993, 1994 Sun Microsystems, Inc.                      *
28  * (c) Copyright 1993, 1994 Novell, Inc.                                *
29  */
30
31 #include "Invoke.h"
32
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <signal.h>
36 #include <fcntl.h>
37 #include <sys/time.h>
38 #include <sys/wait.h>
39 #include <string.h>
40 #include <errno.h>
41 #if !defined(CSRG_BASED)
42 #include <values.h>
43 #endif
44 #ifdef _AIX
45 #include <strings.h>            /* need to get bzero defined */
46 #endif /* _AIX */
47
48 const int BUFFER_SIZE = 512;
49
50 Invoke::Invoke(const char *command,   // Command to Run
51                char **out_ptr,        // ptr to output buffer ptr 
52                char **err_ptr,        // ptr to error buffer ptr
53                uid_t _uid)            // run command as this UID
54 {
55    int m_stdout[2], m_stderr[2];       // progname file descriptors
56    pid_t c_pid;                        // child's pid 
57    pid_t w;                            // temp vars 
58    int out_num,err_num;                // # of chars read 
59    char *out_tmp, *err_tmp;            // temp buffer ptrs 
60    char *out_end,*err_end;             // ptr to end of buffer 
61    int outb_size,errb_size;            // buffer size 
62    int out_count, err_count;           // # of buffers allocated 
63    int trap_out,trap_err;              // flags; if >0, trap output 
64    fd_set rdmask;                      // for select system call 
65    fd_set wrmask;                      // for select system call 
66    fd_set exmask;                      // for select system call 
67    int Nfdsmsgs;
68
69    struct sigaction action;            // parameters of sigaction 
70    struct sigaction oldsigint_act;
71    struct sigaction oldsigquit_act;
72
73    status = 0;
74
75    trap_out = (out_ptr != NULL);
76    trap_err = (err_ptr != NULL);
77
78    // initialize internal variables
79    out_num = err_num = 0;
80
81    // setup pipes if specified
82    if (trap_out)
83     {
84       *out_ptr = 0;
85
86       if (pipe(m_stdout) < 0)
87        {
88          status = -1;
89          return;
90        }
91     }
92
93    if (trap_err)
94     {
95       *err_ptr = 0;
96
97       if (pipe(m_stderr) < 0)
98        {
99          if (trap_out)
100             close(m_stdout[0]);
101          status = -1;
102          return;
103        }
104     }
105    if (trap_err)
106       Nfdsmsgs = m_stderr[0] + 1;
107    else if (trap_out)
108       Nfdsmsgs = m_stdout[0] + 1;
109    else
110       Nfdsmsgs = 0;
111
112    // ignore these signals
113    memset(&action, '\0', sizeof (struct sigaction));
114    memset(&oldsigquit_act, '\0', sizeof (struct sigaction));
115    memset(&oldsigint_act, '\0', sizeof (struct sigaction));
116
117 #if defined(__OSF1__) || defined(__osf__) 
118    action.sa_handler = (void (*)(int))SIG_IGN;
119 #elif defined(USL) || defined(__uxp__) || \
120       ( defined(sun) && OSMAJORVERSION == 5 && OSMINORVERSION <= 4)
121    action.sa_handler = (void (*)())SIG_IGN;
122 #else
123    action.sa_handler = SIG_IGN;
124 #endif
125
126    sigaction(SIGINT, &action, &oldsigint_act);
127    sigaction(SIGQUIT, &action, &oldsigquit_act);
128
129    if ((c_pid = fork()) == 0)
130     { // ------------------------ child process --------------------------
131
132       if (_uid != (uid_t)-1)
133          setuid(_uid);
134
135       if (trap_out)
136        { // duplicate stdout
137          close(m_stdout[0]);
138          close(1);
139          dup(m_stdout[1]);
140          close(m_stdout[1]);
141        }
142
143       if (trap_err)
144        { // duplicate stderr
145          close(m_stderr[0]);
146          close(2);
147          dup(m_stderr[1]);
148          close(m_stderr[1]);
149        }
150
151       // start the program 
152       execlp(KORNSHELL, "ksh", "-c", command, (char *) 0);
153
154       exit(-1);
155     }
156    else if (c_pid == -1)
157     {
158       if (trap_err)
159          close(m_stderr[0]);
160
161       if (trap_out)
162          close(m_stdout[0]);
163
164       status = -1;
165       return;
166     }
167
168    // -------------------------- parent process --------------------------
169
170    // restore signals
171    sigaction(SIGINT, &oldsigint_act, NULL);
172    sigaction(SIGQUIT, &oldsigquit_act, NULL);
173
174    // close the write side of the pipe for the parent
175    if (trap_out)
176     {
177       close(m_stdout[1]);
178       fcntl(m_stdout[0], F_SETFL, O_NDELAY);
179     }
180
181    if (trap_err)
182     {
183       close(m_stderr[1]);
184       fcntl(m_stderr[0], F_SETFL, O_NDELAY);
185     }
186
187    if (!trap_out && !trap_err)
188     { // no piped output 
189       // wait for the child to die
190       while ((w = wait(&status)) != c_pid && w != -1)
191          ;
192       status = (status >> 8) & 0xFF;
193       return;
194     }
195
196    // initialize buffer pointers
197    if (trap_out)
198     {
199       *out_ptr = (char *) malloc(BUFFER_SIZE);
200       if (*out_ptr == NULL)
201        {
202          close(m_stdout[0]);
203          if (trap_err)
204             close(m_stderr[0]);
205          status = -1;
206          return;
207        }
208
209       out_tmp = *out_ptr;
210       out_end = *out_ptr + BUFFER_SIZE - 1;
211       out_count = 1;
212       outb_size = BUFFER_SIZE;
213     }
214
215    if (trap_err)
216     {
217       *err_ptr = (char *) malloc(BUFFER_SIZE);
218       if (*err_ptr == NULL)
219        {
220          close(m_stderr[0]);
221          if (trap_out)
222             close(m_stdout[0]);
223
224          status = -1;
225          return;
226        }
227
228       *err_ptr = (char *) malloc(BUFFER_SIZE);
229       err_tmp = *err_ptr;
230       err_end = *err_ptr + BUFFER_SIZE - 1;
231       err_count = 1;
232       errb_size = BUFFER_SIZE;
233     }
234
235    while (trap_out || trap_err)
236     {
237       // reset the file descriptor masks
238       FD_ZERO(&rdmask);
239       FD_ZERO(&wrmask);
240       FD_ZERO(&exmask);
241
242       // set the bit masks for the descriptors to be checked
243       if (trap_out)
244          FD_SET(m_stdout[0], &rdmask);
245       if (trap_err)
246          FD_SET(m_stderr[0], &rdmask);
247
248       // check the status
249       if (select(Nfdsmsgs,&rdmask,&wrmask,&exmask,(struct timeval *)NULL) == -1)
250        {
251          if (errno == EINTR)
252             continue;
253          else
254           {
255             if (trap_out)
256                close(m_stdout[0]);
257             if (trap_err)
258                close(m_stderr[0]);
259
260             status = -1;
261             return;
262           }
263        }
264       if (trap_out && FD_ISSET(m_stdout[0], &rdmask))
265
266        {
267          // read the child's stdout
268          if ((out_num = read(m_stdout[0], out_tmp, outb_size)) < 0)
269           {
270             close(m_stdout[0]);
271             if (trap_err)
272                close(m_stderr[0]);
273
274             status = -1;
275             return;
276           }
277
278          if (out_num == 0)
279           {
280             // no more to read
281             trap_out = 0;
282             close(m_stdout[0]);
283             *out_tmp = '\0';
284           }
285          else if (out_num == outb_size)
286           {
287             // filled up a buffer; allocate another one
288             out_count++;
289             *out_ptr = (char *)realloc(*out_ptr, (out_count * BUFFER_SIZE));
290             if (*out_ptr == NULL)
291              {
292                close(m_stdout[0]);
293                if (trap_err)
294                   close(m_stderr[0]);
295                status = -1;
296                return;
297              }
298
299             out_tmp = *out_ptr + ((out_count - 1) * BUFFER_SIZE);
300             out_end = out_tmp + BUFFER_SIZE - 1;
301             outb_size = BUFFER_SIZE;
302           }
303          else if (out_num > 0)
304           {
305             // read less than a full buffer; reset amount to read next
306             out_tmp += out_num;
307             outb_size = out_end - out_tmp + 1;
308             outb_size = (outb_size > 0) ? outb_size : 0;
309           }
310        } // if trap_out
311
312       if (trap_err && FD_ISSET(m_stderr[0], &rdmask))
313        {
314          // read the child's stderr
315          if ((err_num = read(m_stderr[0], err_tmp, errb_size)) == -1)
316           {
317             if (trap_out)
318                close(m_stdout[0]);
319
320             close(m_stderr[0]);
321
322             status = -1;
323             return;
324           }
325
326          if (err_num == 0)
327           {
328             // no more to read
329             trap_err = 0;
330             close(m_stderr[0]);
331             *err_tmp = '\0';
332           }
333          else if (err_num == errb_size)
334           {
335             // filled up a buffer; allocate another one
336             err_count++;
337             *err_ptr = (char *)realloc(*err_ptr, (err_count * BUFFER_SIZE));
338             if (*err_ptr == NULL)
339              {
340                close(m_stderr[0]);
341                if (trap_out)
342                   close(m_stdout[0]);
343                status = -1;
344                return;
345              }
346
347             err_tmp = *err_ptr + ((err_count - 1) * BUFFER_SIZE);
348             err_end = err_tmp + BUFFER_SIZE - 1;
349             errb_size = BUFFER_SIZE;
350           }
351          else if (err_num > 0)
352           {
353             // read less than a full buffer; reset amount to read next
354             err_tmp += err_num;
355             errb_size = err_end - err_tmp + 1;
356             errb_size = (errb_size > 0) ? errb_size : 0;
357           }
358        } // if trap_err
359     } // while trap_out or trap_err
360
361    while ((w = wait(&status)) != c_pid && w != -1);
362    status = (status >> 8) & 0xFF;
363 }