Convert uses of XKeycodeToKeysym (deprecated) to XkbKeycodeToKeysym
[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 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 /* $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(sun) && OSMAJORVERSION == 5 && OSMINORVERSION <= 4)
118    action.sa_handler = (void (*)())SIG_IGN;
119 #else
120    action.sa_handler = SIG_IGN;
121 #endif
122
123    sigaction(SIGINT, &action, &oldsigint_act);
124    sigaction(SIGQUIT, &action, &oldsigquit_act);
125
126    if ((c_pid = fork()) == 0)
127     { // ------------------------ child process --------------------------
128
129       if (_uid != (uid_t)-1)
130          setuid(_uid);
131
132       if (trap_out)
133        { // duplicate stdout
134          close(m_stdout[0]);
135          close(1);
136          dup(m_stdout[1]);
137          close(m_stdout[1]);
138        }
139
140       if (trap_err)
141        { // duplicate stderr
142          close(m_stderr[0]);
143          close(2);
144          dup(m_stderr[1]);
145          close(m_stderr[1]);
146        }
147
148       // start the program 
149       execlp(KORNSHELL, "ksh", "-c", command, (char *) 0);
150
151       exit(-1);
152     }
153    else if (c_pid == -1)
154     {
155       if (trap_err)
156          close(m_stderr[0]);
157
158       if (trap_out)
159          close(m_stdout[0]);
160
161       status = -1;
162       return;
163     }
164
165    // -------------------------- parent process --------------------------
166
167    // restore signals
168    sigaction(SIGINT, &oldsigint_act, NULL);
169    sigaction(SIGQUIT, &oldsigquit_act, NULL);
170
171    // close the write side of the pipe for the parent
172    if (trap_out)
173     {
174       close(m_stdout[1]);
175       fcntl(m_stdout[0], F_SETFL, O_NDELAY);
176     }
177
178    if (trap_err)
179     {
180       close(m_stderr[1]);
181       fcntl(m_stderr[0], F_SETFL, O_NDELAY);
182     }
183
184    if (!trap_out && !trap_err)
185     { // no piped output 
186       // wait for the child to die
187       while ((w = wait(&status)) != c_pid && w != -1)
188          ;
189       status = (status >> 8) & 0xFF;
190       return;
191     }
192
193    // initialize buffer pointers
194    if (trap_out)
195     {
196       *out_ptr = (char *) malloc(BUFFER_SIZE);
197       if (*out_ptr == NULL)
198        {
199          close(m_stdout[0]);
200          if (trap_err)
201             close(m_stderr[0]);
202          status = -1;
203          return;
204        }
205
206       out_tmp = *out_ptr;
207       out_end = *out_ptr + BUFFER_SIZE - 1;
208       out_count = 1;
209       outb_size = BUFFER_SIZE;
210     }
211
212    if (trap_err)
213     {
214       *err_ptr = (char *) malloc(BUFFER_SIZE);
215       if (*err_ptr == NULL)
216        {
217          close(m_stderr[0]);
218          if (trap_out)
219             close(m_stdout[0]);
220
221          status = -1;
222          return;
223        }
224
225       *err_ptr = (char *) malloc(BUFFER_SIZE);
226       err_tmp = *err_ptr;
227       err_end = *err_ptr + BUFFER_SIZE - 1;
228       err_count = 1;
229       errb_size = BUFFER_SIZE;
230     }
231
232    while (trap_out || trap_err)
233     {
234       // reset the file descriptor masks
235       FD_ZERO(&rdmask);
236       FD_ZERO(&wrmask);
237       FD_ZERO(&exmask);
238
239       // set the bit masks for the descriptors to be checked
240       if (trap_out)
241          FD_SET(m_stdout[0], &rdmask);
242       if (trap_err)
243          FD_SET(m_stderr[0], &rdmask);
244
245       // check the status
246       if (select(Nfdsmsgs,&rdmask,&wrmask,&exmask,(struct timeval *)NULL) == -1)
247        {
248          if (errno == EINTR)
249             continue;
250          else
251           {
252             if (trap_out)
253                close(m_stdout[0]);
254             if (trap_err)
255                close(m_stderr[0]);
256
257             status = -1;
258             return;
259           }
260        }
261       if (trap_out && FD_ISSET(m_stdout[0], &rdmask))
262
263        {
264          // read the child's stdout
265          if ((out_num = read(m_stdout[0], out_tmp, outb_size)) < 0)
266           {
267             close(m_stdout[0]);
268             if (trap_err)
269                close(m_stderr[0]);
270
271             status = -1;
272             return;
273           }
274
275          if (out_num == 0)
276           {
277             // no more to read
278             trap_out = 0;
279             close(m_stdout[0]);
280             *out_tmp = '\0';
281           }
282          else if (out_num == outb_size)
283           {
284             // filled up a buffer; allocate another one
285             out_count++;
286             *out_ptr = (char *)realloc(*out_ptr, (out_count * BUFFER_SIZE));
287             if (*out_ptr == NULL)
288              {
289                close(m_stdout[0]);
290                if (trap_err)
291                   close(m_stderr[0]);
292                status = -1;
293                return;
294              }
295
296             out_tmp = *out_ptr + ((out_count - 1) * BUFFER_SIZE);
297             out_end = out_tmp + BUFFER_SIZE - 1;
298             outb_size = BUFFER_SIZE;
299           }
300          else if (out_num > 0)
301           {
302             // read less than a full buffer; reset amount to read next
303             out_tmp += out_num;
304             outb_size = out_end - out_tmp + 1;
305             outb_size = (outb_size > 0) ? outb_size : 0;
306           }
307        } // if trap_out
308
309       if (trap_err && FD_ISSET(m_stderr[0], &rdmask))
310        {
311          // read the child's stderr
312          if ((err_num = read(m_stderr[0], err_tmp, errb_size)) == -1)
313           {
314             if (trap_out)
315                close(m_stdout[0]);
316
317             close(m_stderr[0]);
318
319             status = -1;
320             return;
321           }
322
323          if (err_num == 0)
324           {
325             // no more to read
326             trap_err = 0;
327             close(m_stderr[0]);
328             *err_tmp = '\0';
329           }
330          else if (err_num == errb_size)
331           {
332             // filled up a buffer; allocate another one
333             err_count++;
334             *err_ptr = (char *)realloc(*err_ptr, (err_count * BUFFER_SIZE));
335             if (*err_ptr == NULL)
336              {
337                close(m_stderr[0]);
338                if (trap_out)
339                   close(m_stdout[0]);
340                status = -1;
341                return;
342              }
343
344             err_tmp = *err_ptr + ((err_count - 1) * BUFFER_SIZE);
345             err_end = err_tmp + BUFFER_SIZE - 1;
346             errb_size = BUFFER_SIZE;
347           }
348          else if (err_num > 0)
349           {
350             // read less than a full buffer; reset amount to read next
351             err_tmp += err_num;
352             errb_size = err_end - err_tmp + 1;
353             errb_size = (errb_size > 0) ? errb_size : 0;
354           }
355        } // if trap_err
356     } // while trap_out or trap_err
357
358    while ((w = wait(&status)) != c_pid && w != -1);
359    status = (status >> 8) & 0xFF;
360 }