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