nsgmls: resolve coverity warnings related to uninitialed members in C++ classes
[oweals/cde.git] / cde / programs / dtpdmd / dtpdmd.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 /* $XConsortium: dtpdmd.c /main/9 1996/10/30 19:10:08 cde-hp $ */
24
25 /******************************************************************************
26  ******************************************************************************
27  **
28  ** File:         dtpdmd.c
29  **
30  ** Description:  main file for the implementation of the dtpdmd.
31  **
32  ** (c) Copyright 1995, 1996 Hewlett-Packard Company, all rights reserved.
33  **
34  ******************************************************************************
35  *****************************************************************************/
36
37 /******************************************************************************
38  *
39  * BASIC dtpdmd FLOW
40  *
41  * Other than setup, one event loop runs the show.
42  *
43  * Legend:
44  *
45  *    ->  means XtAppNextEvent breaks out with an event, and a
46  *        case statement figures out where the event should go.
47  *
48  *    =>  means XtAppNextEvent dispatches the handler for
49  *        the event directly.
50  *
51  * XtAppNextEvent()
52  *
53  *    -> dispatch_mgr
54  *          o find_rec              }
55  *          o mgr_initialize        }  mgr_launch_reply and delete_rec
56  *          o mgr_fetch_pdm         }  called as soon as any errors occur
57  *          o mgr_launch_pdm        }
58  *          o mgr_shutdown_scan     }
59  *
60  *    -> dispatch_mbox
61  *          o find_rec              }
62  *          o mbox_initialize       }  request for
63  *          o mbox_build            }  mailbox
64  *          o mbox_reply            }
65  *          o mgr_shutdown_scan     }
66  *       or
67  *          o find_rec_by_mbox_win  }  receive incoming
68  *          o mbox_receive          }  mail
69  *          o mgr_shutdown_scan     }
70  *
71  *    => xtkick_proc (SIGCLD write to pipe handler causes this)
72  *          o mgr_shutdown_scan
73  *
74  *    => message_pipe_handler
75  *          o child's stderr to pipe to malloc'ed buffer
76  *          o trap EOF on pipe
77  *          o mgr_shutdown_scan
78  *
79  *    ~> SIGCLD (not really dispatched)
80  *          o the handler notes which child, and exit status,
81  *            then writes a byte to tickle the xtkick_proc
82  *
83  * Note the final usage of:
84  *
85  *    mgr_shutdown_scan
86  *       o possibly pdm_launch_reply
87  *       o possibly pdm_shutdown_reply
88  *       o as appropriate, delete_rec
89  */
90
91 /******************************************************************************
92  *
93  * XIO Error Handling Strategy:
94  *
95  * XIO errors can occur from up to 3 display connections:
96  *
97  *    o sel_dpy (aka prop_dpy)
98  *         - always active.  If this display connection goes down,
99  *           then the dtpdmd will not be able to service any more
100  *           pdm requests.
101  *
102  *    o print_dpy (usually equal to sel_dpy)
103  *         - within the pdm, on a per client basis, only active
104  *           long enough to 1) fetch the dt-pdm-command attribute,
105  *           and to 2) send the final ClientMessage with OK/Cancel.
106  *
107  *           XIO strategy: wrap setjmp/longjmp around the usages
108  *           of XOpenDisplay on print_dpy.
109  *
110  *           XIO result: For case #1, set dt-pdm-command using
111  *           built in defaults, thus ignoring XpGetOneAttribute.
112  *
113  *           For case #2, the best that can be done is to log
114  *           a message to the errorlog.
115  *
116  *    o video_dpy
117  *         - within the pdm, on a per client basis, only active
118  *           long enough to 1) run a test connection to verify
119  *           authorization.
120  *
121  *           XIO strategy: wrap setjmp/longjmp around the one
122  *           XOpenDisplay of video_dpy.
123  *
124  *           XIO result: act as if authorization failed.
125  */
126 #define DTPDMD_DOT_C
127
128 #include "dtpdmdP.h"
129 #include "nlmsg.h"
130
131 /********************************************************************
132  *
133  * Globals.
134  */
135 XpPdmGlobals g;                 /* global to all modules */
136
137 static int xtkick_pipeG[2];     /* global to this module */
138
139 /********************************************************************
140  *
141  * pusage
142  */
143 static void pusage( char *prog_name )
144 {
145     fprintf(stderr, "\n");
146     fprintf( stderr, PDMD_MSG_1, prog_name, "PDM_MANAGER", DEFAULT_PDM_EXECUTABLE );
147     fprintf(stderr, "\n");
148     fprintf(stderr, "\n");
149 }
150
151
152 /******************************************************************************
153  *
154  * generic_error_handler
155  *
156  *****************************************************************************/
157
158 static int generic_error_handler( edpy, eevent )
159     Display     *edpy;
160     XErrorEvent *eevent;
161 {
162     g.xerrno  = eevent->error_code;
163     g.xerrreq = eevent->request_code;
164     g.xerrmin = eevent->minor_code;
165
166     return 0; /* XSetErrorHandler handlers return values are ignored */
167 }
168
169 /******************************************************************************
170  *
171  * handle_SIGCLD
172  *
173  *****************************************************************************/
174 static void
175 #if defined(__aix) || defined(linux)
176 handle_SIGCLD(int sigNum)
177 #else
178 handle_SIGCLD(void)
179 #endif /* __aix */
180 {
181     int exitStatus, i;
182     pid_t pid;
183
184     /*
185      * Query why the SIGCLD happened - a true termination or just
186      * a stopage.  We only care about terminations.
187      */
188     pid = wait(&exitStatus);
189
190     if (pid == -1) {
191         /*
192          * No specific child found with wait() - punt.
193          */
194     }
195     else if (!WIFSTOPPED(exitStatus)) {
196         /*
197          * The SIGCLD was *not* the result of being stopped, so the child
198          * has indeed terminated.  Look for its tracking record and mark
199          * accordingly for later shutdown.
200          */
201         for ( i = 0; i < g.serviceRecNum; i++ ) {
202             if ( g.serviceRecs[i]->pid == pid ) {
203                 /*
204                  * Update tracking record.
205                  */
206                 g.serviceRecs[i]->exit_received = True;
207                 g.serviceRecs[i]->exit_code = (int) WEXITSTATUS(exitStatus);
208
209                 /*
210                  * Figure out who will deliver the "tickle" to XtAppNextEvent
211                  * that will allow this child's status to be rediscovered
212                  * so that a subsequent shutdown can be done.
213                  *
214                  *    - if the child's message_pipe is still up,
215                  *      let its upcoming disconnection be the tickle.
216                  *
217                  *    - if the child's message pipe is aleady down,
218                  *      then this is our last event related to the
219                  *      child, so tickle the "Xt Signal Pipe" we
220                  *      installed.
221                  *
222                  *    - if the Xt Signal Pipe is down, then we'll have
223                  *      to rely upon a 3rd party to deliver an event
224                  *      that will reactivate the Xt Main Loop.
225                  */
226                 if ( g.serviceRecs[i]->message_pipe[0] == -1 ) {
227                     /*
228                      * Tickle our "Xt Signal Pipe".
229                      */
230                     write( xtkick_pipeG[1], (char *) "", 1 );
231                 }
232
233                 break;
234             }
235         }
236     }
237 }
238
239 static void xtkick_proc( XtPointer w, int *source, XtInputId *id)
240 {
241     char buffer[128];
242
243     /*
244      * Drain off the kicker bytes.  Don't care how many, since
245      * we'll look at all client records.
246      */
247     if ( read(*source, buffer, sizeof (buffer) - 1) <= 0 ) {
248         close (*source);   /* aka xtkick_pipeG[0] */
249         XtRemoveInput (*id);
250
251         xtkick_pipeG[0] = -1;   /* mark the pipe as invalid */
252         xtkick_pipeG[1] = -1;
253     }
254
255     /*
256      * Scan client records and see who is ready to be
257      * shut down.
258      */
259     mgr_shutdown_scan();
260 }
261
262 /******************************************************************************
263  *
264  * main
265  */
266 int
267 main( argc, argv )
268     int argc;
269     char **argv;
270 {
271     int tscreen;
272     XtInputId xtid;
273     Window sel_window;
274     Display *sel_display;
275     char *display_str, *auth_file;
276     Bool security_flag;
277     XEvent report;
278     struct sigaction svec;
279
280
281     g.serviceRecNum = 0;
282     g.maxServiceRecNum = 0;
283
284     g.prog_name = argv[0];
285     g.alt_selection = "PDM_MANAGER";
286     g.default_pdm = DEFAULT_PDM_EXECUTABLE;
287     g.override_pdm = (char *) NULL;
288     display_str = getenv("DISPLAY");
289     auth_file = (char *) NULL;
290     g.log_file  = (char *) NULL;
291     security_flag  = False;
292
293     /*
294      * Parse command line arguments.
295      */
296     while (*++argv) {
297         if (!strcmp (*argv, "-a")) {
298             g.alt_selection = *++argv;
299         }
300         else if (!strncmp (*argv, "-d", 2)) {
301             display_str = *++argv;
302         }
303         else if (!strcmp (*argv, "-p")) {
304             g.default_pdm = *++argv;
305         }
306         else if (!strcmp (*argv, "-P")) {
307             g.override_pdm = *++argv;
308         }
309         else if (!strcmp (*argv, "-s")) {
310             security_flag = True;
311         }
312         else if (!strcmp (*argv, "-f")) {
313             auth_file = *++argv;
314         }
315         else if (!strcmp (*argv, "-l")) {
316             g.log_file = *++argv;
317         }
318         else if (!strncmp (*argv, "-h", 2)) {
319             pusage( g.prog_name );
320             exit(1);
321         }
322         else {
323             /*
324              * Ignore unknown options.
325              */
326         }
327     }
328
329
330     /*
331      * Open a connection to the X-Server.
332      */
333     XtToolkitInitialize ();
334     g.context = XtCreateApplicationContext();
335     if ( (sel_display = XtOpenDisplay( g.context, display_str,
336                                         "dtpdmd", "Dtpdmd",
337                                         0, 0, &argc, argv )) == NULL ) {
338         fprintf( stderr , "\n" );
339         fprintf( stderr , PDMD_MSG_2, g.prog_name, display_str );
340         fprintf( stderr , "\n" );
341         fprintf( stderr , "\n" );
342         exit(0);
343     }
344
345     /*
346      * Create master PDM window upon which selections
347      * will be created.
348      */
349     tscreen = DefaultScreen( sel_display );
350
351     sel_window = XCreateSimpleWindow( sel_display,
352                                    DefaultRootWindow( sel_display ),
353                                    0, 0, 1, 1, 1,
354                                    BlackPixel(sel_display, tscreen),
355                                    WhitePixel(sel_display, tscreen) );
356
357     /*
358      * Setup PDM_MANAGER selection
359      */
360     if ( ! _PdmMgrSetup( sel_display, sel_window, security_flag ) ) {
361         fprintf( stderr , "\n" );
362         fprintf( stderr , PDMD_MSG_3, g.prog_name , g.alt_selection );
363         fprintf( stderr , "\n" );
364         fprintf( stderr , "\n" );
365         exit(0);
366     }
367
368
369     /*
370      * Install the "Xt Signal Pipe" Kicker handler.
371      */
372     if ( pipe(xtkick_pipeG) == -1 ) {
373         fprintf( stderr , "\n" );
374         fprintf( stderr , PDMD_MSG_4, g.prog_name );
375         fprintf( stderr , "\n" );
376         fprintf( stderr , "\n" );
377         exit(0);
378     }
379     xtid = XtAppAddInput( g.context, xtkick_pipeG[0],
380                           (XtPointer) XtInputReadMask,
381                           xtkick_proc, (XtPointer) NULL );
382
383     /*
384      * Install signal handers.
385      */
386     sigemptyset(&svec.sa_mask);
387     svec.sa_flags   = 0;
388     svec.sa_handler = handle_SIGCLD;
389     (void) sigaction(SIGCHLD, &svec, (struct sigaction *) NULL);
390
391     /*
392      * After this point, we need to trap all X and XIO errors.
393      *
394      * XIO trap handlers are installed at critical points, and
395      * the following generic X trap handler is used to set
396      * globals.
397      */
398     XSetErrorHandler( generic_error_handler );
399
400     /*
401      * MASTER EVENT LOOP
402      */
403     while (1) {
404         /*
405          * XtAppNextEvent breaks for several reasons:
406          *    - X event received
407          *
408          * XtAppNextEvent will dispatch for several reasons:
409          *    - Alt input occurs on a pdm message pipe
410          *    - Alt input occurs because a pdm message pipe was disconnected
411          *    - Alt input occurs on our "Xt Signal Pipe" and we need to
412          *      rediscover what happened as a result of that signal.
413          */
414         XtAppNextEvent( g.context, &report );
415         switch (report.type) {
416
417             case ClientMessage:
418                 if (report.xclient.message_type == g.pdm_mail) {
419                     dispatch_mbox( &report );
420                 }
421                 else {
422                     /* ignore/pitch the event */
423                 }
424                 break;
425
426             case SelectionRequest:
427                 if (report.xselectionrequest.selection == g.pdm_selection) {
428                     if (report.xselectionrequest.target == g.pdm_start) {
429                         dispatch_mgr( &report );
430                     }
431                     else if (report.xselectionrequest.target==g.pdm_targets) {
432                         dispatch_targets( &report );
433                     }
434                     else if (report.xselectionrequest.target==g.pdm_multiple){
435                         dispatch_multiple( &report );
436                     }
437                     else if (report.xselectionrequest.target==g.pdm_timestamp){
438                         dispatch_timestamp( &report );
439                     }
440                     else if (report.xselectionrequest.target==g.pdm_mbox) {
441                         dispatch_mbox( &report );
442                     }
443                     else {
444                         dispatch_not_supported( &report );
445                     }
446                 }
447                 else {
448                     /* ignore/pitch the event */
449                 }
450                 break;
451
452             case SelectionNotify:
453                 /* pitch the event */
454                 break;
455
456             case SelectionClear:
457                 /*
458                  * Someone is trying to tear away the selection.
459                  * REACT by trying to reclaim it and logging an
460                  * error.
461                  */
462                 break;
463
464             default:
465                 break;
466         }
467
468         /*
469          * Use the opportunity to check for freshly finished
470          * PDMs, and close them out.
471          */
472         mgr_shutdown_scan();
473     }
474
475     XDestroyWindow( sel_display, sel_window );
476
477     XtCloseDisplay( sel_display );
478
479     exit(0);
480 }
481