2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
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)
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
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
23 /* $XConsortium: dtpdmd.c /main/9 1996/10/30 19:10:08 cde-hp $ */
25 /******************************************************************************
26 ******************************************************************************
30 ** Description: main file for the implementation of the dtpdmd.
32 ** (c) Copyright 1995, 1996 Hewlett-Packard Company, all rights reserved.
34 ******************************************************************************
35 *****************************************************************************/
37 /******************************************************************************
41 * Other than setup, one event loop runs the show.
45 * -> means XtAppNextEvent breaks out with an event, and a
46 * case statement figures out where the event should go.
48 * => means XtAppNextEvent dispatches the handler for
55 * o mgr_initialize } mgr_launch_reply and delete_rec
56 * o mgr_fetch_pdm } called as soon as any errors occur
58 * o mgr_shutdown_scan }
62 * o mbox_initialize } request for
63 * o mbox_build } mailbox
65 * o mgr_shutdown_scan }
67 * o find_rec_by_mbox_win } receive incoming
68 * o mbox_receive } mail
69 * o mgr_shutdown_scan }
71 * => xtkick_proc (SIGCLD write to pipe handler causes this)
74 * => message_pipe_handler
75 * o child's stderr to pipe to malloc'ed buffer
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
83 * Note the final usage of:
86 * o possibly pdm_launch_reply
87 * o possibly pdm_shutdown_reply
88 * o as appropriate, delete_rec
91 /******************************************************************************
93 * XIO Error Handling Strategy:
95 * XIO errors can occur from up to 3 display connections:
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
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.
107 * XIO strategy: wrap setjmp/longjmp around the usages
108 * of XOpenDisplay on print_dpy.
110 * XIO result: For case #1, set dt-pdm-command using
111 * built in defaults, thus ignoring XpGetOneAttribute.
113 * For case #2, the best that can be done is to log
114 * a message to the errorlog.
117 * - within the pdm, on a per client basis, only active
118 * long enough to 1) run a test connection to verify
121 * XIO strategy: wrap setjmp/longjmp around the one
122 * XOpenDisplay of video_dpy.
124 * XIO result: act as if authorization failed.
131 /********************************************************************
135 XpPdmGlobals g; /* global to all modules */
137 static int xtkick_pipeG[2]; /* global to this module */
139 /********************************************************************
143 static void pusage( char *prog_name )
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");
152 /******************************************************************************
154 * generic_error_handler
156 *****************************************************************************/
158 static int generic_error_handler(Display *edpy, XErrorEvent *eevent)
160 g.xerrno = eevent->error_code;
161 g.xerrreq = eevent->request_code;
162 g.xerrmin = eevent->minor_code;
164 return 0; /* XSetErrorHandler handlers return values are ignored */
167 /******************************************************************************
171 *****************************************************************************/
173 #if defined(__aix) || defined(__linux__)
174 handle_SIGCLD(int sigNum)
183 * Query why the SIGCLD happened - a true termination or just
184 * a stopage. We only care about terminations.
186 pid = wait(&exitStatus);
190 * No specific child found with wait() - punt.
193 else if (!WIFSTOPPED(exitStatus)) {
195 * The SIGCLD was *not* the result of being stopped, so the child
196 * has indeed terminated. Look for its tracking record and mark
197 * accordingly for later shutdown.
199 for ( i = 0; i < g.serviceRecNum; i++ ) {
200 if ( g.serviceRecs[i]->pid == pid ) {
202 * Update tracking record.
204 g.serviceRecs[i]->exit_received = True;
205 g.serviceRecs[i]->exit_code = (int) WEXITSTATUS(exitStatus);
208 * Figure out who will deliver the "tickle" to XtAppNextEvent
209 * that will allow this child's status to be rediscovered
210 * so that a subsequent shutdown can be done.
212 * - if the child's message_pipe is still up,
213 * let its upcoming disconnection be the tickle.
215 * - if the child's message pipe is aleady down,
216 * then this is our last event related to the
217 * child, so tickle the "Xt Signal Pipe" we
220 * - if the Xt Signal Pipe is down, then we'll have
221 * to rely upon a 3rd party to deliver an event
222 * that will reactivate the Xt Main Loop.
224 if ( g.serviceRecs[i]->message_pipe[0] == -1 ) {
226 * Tickle our "Xt Signal Pipe".
228 write( xtkick_pipeG[1], (char *) "", 1 );
237 static void xtkick_proc( XtPointer w, int *source, XtInputId *id)
242 * Drain off the kicker bytes. Don't care how many, since
243 * we'll look at all client records.
245 if ( read(*source, buffer, sizeof (buffer) - 1) <= 0 ) {
246 close (*source); /* aka xtkick_pipeG[0] */
249 xtkick_pipeG[0] = -1; /* mark the pipe as invalid */
250 xtkick_pipeG[1] = -1;
254 * Scan client records and see who is ready to be
260 /******************************************************************************
265 main(int argc, char **argv)
270 Display *sel_display;
271 char *display_str, *auth_file;
274 struct sigaction svec;
278 g.maxServiceRecNum = 0;
280 g.prog_name = argv[0];
281 g.alt_selection = "PDM_MANAGER";
282 g.default_pdm = DEFAULT_PDM_EXECUTABLE;
283 g.override_pdm = (char *) NULL;
284 display_str = getenv("DISPLAY");
285 auth_file = (char *) NULL;
286 g.log_file = (char *) NULL;
287 security_flag = False;
290 * Parse command line arguments.
293 if (!strcmp (*argv, "-a")) {
294 g.alt_selection = *++argv;
296 else if (!strncmp (*argv, "-d", 2)) {
297 display_str = *++argv;
299 else if (!strcmp (*argv, "-p")) {
300 g.default_pdm = *++argv;
302 else if (!strcmp (*argv, "-P")) {
303 g.override_pdm = *++argv;
305 else if (!strcmp (*argv, "-s")) {
306 security_flag = True;
308 else if (!strcmp (*argv, "-f")) {
311 else if (!strcmp (*argv, "-l")) {
312 g.log_file = *++argv;
314 else if (!strncmp (*argv, "-h", 2)) {
315 pusage( g.prog_name );
320 * Ignore unknown options.
327 * Open a connection to the X-Server.
329 XtToolkitInitialize ();
330 g.context = XtCreateApplicationContext();
331 if ( (sel_display = XtOpenDisplay( g.context, display_str,
333 0, 0, &argc, argv )) == NULL ) {
334 fprintf( stderr , "\n" );
335 fprintf( stderr , PDMD_MSG_2, g.prog_name, display_str );
336 fprintf( stderr , "\n" );
337 fprintf( stderr , "\n" );
342 * Create master PDM window upon which selections
345 tscreen = DefaultScreen( sel_display );
347 sel_window = XCreateSimpleWindow( sel_display,
348 DefaultRootWindow( sel_display ),
350 BlackPixel(sel_display, tscreen),
351 WhitePixel(sel_display, tscreen) );
354 * Setup PDM_MANAGER selection
356 if ( ! _PdmMgrSetup( sel_display, sel_window, security_flag ) ) {
357 fprintf( stderr , "\n" );
358 fprintf( stderr , PDMD_MSG_3, g.prog_name , g.alt_selection );
359 fprintf( stderr , "\n" );
360 fprintf( stderr , "\n" );
366 * Install the "Xt Signal Pipe" Kicker handler.
368 if ( pipe(xtkick_pipeG) == -1 ) {
369 fprintf( stderr , "\n" );
370 fprintf( stderr , PDMD_MSG_4, g.prog_name );
371 fprintf( stderr , "\n" );
372 fprintf( stderr , "\n" );
375 xtid = XtAppAddInput( g.context, xtkick_pipeG[0],
376 (XtPointer) XtInputReadMask,
377 xtkick_proc, (XtPointer) NULL );
380 * Install signal handers.
382 sigemptyset(&svec.sa_mask);
384 svec.sa_handler = handle_SIGCLD;
385 (void) sigaction(SIGCHLD, &svec, (struct sigaction *) NULL);
388 * After this point, we need to trap all X and XIO errors.
390 * XIO trap handlers are installed at critical points, and
391 * the following generic X trap handler is used to set
394 XSetErrorHandler( generic_error_handler );
401 * XtAppNextEvent breaks for several reasons:
404 * XtAppNextEvent will dispatch for several reasons:
405 * - Alt input occurs on a pdm message pipe
406 * - Alt input occurs because a pdm message pipe was disconnected
407 * - Alt input occurs on our "Xt Signal Pipe" and we need to
408 * rediscover what happened as a result of that signal.
410 XtAppNextEvent( g.context, &report );
411 switch (report.type) {
414 if (report.xclient.message_type == g.pdm_mail) {
415 dispatch_mbox( &report );
418 /* ignore/pitch the event */
422 case SelectionRequest:
423 if (report.xselectionrequest.selection == g.pdm_selection) {
424 if (report.xselectionrequest.target == g.pdm_start) {
425 dispatch_mgr( &report );
427 else if (report.xselectionrequest.target==g.pdm_targets) {
428 dispatch_targets( &report );
430 else if (report.xselectionrequest.target==g.pdm_multiple){
431 dispatch_multiple( &report );
433 else if (report.xselectionrequest.target==g.pdm_timestamp){
434 dispatch_timestamp( &report );
436 else if (report.xselectionrequest.target==g.pdm_mbox) {
437 dispatch_mbox( &report );
440 dispatch_not_supported( &report );
444 /* ignore/pitch the event */
448 case SelectionNotify:
449 /* pitch the event */
454 * Someone is trying to tear away the selection.
455 * REACT by trying to reclaim it and logging an
465 * Use the opportunity to check for freshly finished
466 * PDMs, and close them out.
471 XDestroyWindow( sel_display, sel_window );
473 XtCloseDisplay( sel_display );