1 /* $XConsortium: dtpdmd.c /main/9 1996/10/30 19:10:08 cde-hp $ */
3 /******************************************************************************
4 ******************************************************************************
8 ** Description: main file for the implementation of the dtpdmd.
10 ** (c) Copyright 1995, 1996 Hewlett-Packard Company, all rights reserved.
12 ******************************************************************************
13 *****************************************************************************/
15 /******************************************************************************
19 * Other than setup, one event loop runs the show.
23 * -> means XtAppNextEvent breaks out with an event, and a
24 * case statement figures out where the event should go.
26 * => means XtAppNextEvent dispatches the handler for
33 * o mgr_initialize } mgr_launch_reply and delete_rec
34 * o mgr_fetch_pdm } called as soon as any errors occur
36 * o mgr_shutdown_scan }
40 * o mbox_initialize } request for
41 * o mbox_build } mailbox
43 * o mgr_shutdown_scan }
45 * o find_rec_by_mbox_win } receive incoming
46 * o mbox_receive } mail
47 * o mgr_shutdown_scan }
49 * => xtkick_proc (SIGCLD write to pipe handler causes this)
52 * => message_pipe_handler
53 * o child's stderr to pipe to malloc'ed buffer
57 * ~> SIGCLD (not really dispatched)
58 * o the handler notes which child, and exit status,
59 * then writes a byte to tickle the xtkick_proc
61 * Note the final usage of:
64 * o possibly pdm_launch_reply
65 * o possibly pdm_shutdown_reply
66 * o as appropriate, delete_rec
69 /******************************************************************************
71 * XIO Error Handling Strategy:
73 * XIO errors can occur from up to 3 display connections:
75 * o sel_dpy (aka prop_dpy)
76 * - always active. If this display connection goes down,
77 * then the dtpdmd will not be able to service any more
80 * o print_dpy (usually equal to sel_dpy)
81 * - within the pdm, on a per client basis, only active
82 * long enough to 1) fetch the dt-pdm-command attribute,
83 * and to 2) send the final ClientMessage with OK/Cancel.
85 * XIO strategy: wrap setjmp/longjmp around the usages
86 * of XOpenDisplay on print_dpy.
88 * XIO result: For case #1, set dt-pdm-command using
89 * built in defaults, thus ignoring XpGetOneAttribute.
91 * For case #2, the best that can be done is to log
92 * a message to the errorlog.
95 * - within the pdm, on a per client basis, only active
96 * long enough to 1) run a test connection to verify
99 * XIO strategy: wrap setjmp/longjmp around the one
100 * XOpenDisplay of video_dpy.
102 * XIO result: act as if authorization failed.
109 /********************************************************************
113 XpPdmGlobals g; /* global to all modules */
115 static int xtkick_pipeG[2]; /* global to this module */
117 /********************************************************************
121 static void pusage( char *prog_name )
123 fprintf(stderr, "\n");
124 fprintf( stderr, PDMD_MSG_1, prog_name, "PDM_MANAGER", DEFAULT_PDM_EXECUTABLE );
125 fprintf(stderr, "\n");
126 fprintf(stderr, "\n");
130 /******************************************************************************
132 * generic_error_handler
134 *****************************************************************************/
136 static int generic_error_handler( edpy, eevent )
140 g.xerrno = eevent->error_code;
141 g.xerrreq = eevent->request_code;
142 g.xerrmin = eevent->minor_code;
145 /******************************************************************************
149 *****************************************************************************/
152 handle_SIGCLD(int sigNum)
161 * Query why the SIGCLD happened - a true termination or just
162 * a stopage. We only care about terminations.
164 pid = wait(&exitStatus);
168 * No specific child found with wait() - punt.
171 else if (!WIFSTOPPED(exitStatus)) {
173 * The SIGCLD was *not* the result of being stopped, so the child
174 * has indeed terminated. Look for its tracking record and mark
175 * accordingly for later shutdown.
177 for ( i = 0; i < g.serviceRecNum; i++ ) {
178 if ( g.serviceRecs[i]->pid == pid ) {
180 * Update tracking record.
182 g.serviceRecs[i]->exit_received = True;
183 g.serviceRecs[i]->exit_code = (int) WEXITSTATUS(exitStatus);
186 * Figure out who will deliver the "tickle" to XtAppNextEvent
187 * that will allow this child's status to be rediscovered
188 * so that a subsequent shutdown can be done.
190 * - if the child's message_pipe is still up,
191 * let its upcoming disconnection be the tickle.
193 * - if the child's message pipe is aleady down,
194 * then this is our last event related to the
195 * child, so tickle the "Xt Signal Pipe" we
198 * - if the Xt Signal Pipe is down, then we'll have
199 * to rely upon a 3rd party to deliver an event
200 * that will reactivate the Xt Main Loop.
202 if ( g.serviceRecs[i]->message_pipe[0] == -1 ) {
204 * Tickle our "Xt Signal Pipe".
206 write( xtkick_pipeG[1], (char *) "", 1 );
215 static void xtkick_proc( XtPointer w, int *source, XtInputId *id)
220 * Drain off the kicker bytes. Don't care how many, since
221 * we'll look at all client records.
223 if ( read(*source, buffer, sizeof (buffer) - 1) <= 0 ) {
224 close (*source); /* aka xtkick_pipeG[0] */
227 xtkick_pipeG[0] = -1; /* mark the pipe as invalid */
228 xtkick_pipeG[1] = -1;
232 * Scan client records and see who is ready to be
238 /******************************************************************************
249 Display *sel_display;
250 char *display_str, *auth_file;
253 struct sigaction svec;
257 g.maxServiceRecNum = 0;
259 g.prog_name = argv[0];
260 g.alt_selection = "PDM_MANAGER";
261 g.default_pdm = DEFAULT_PDM_EXECUTABLE;
262 g.override_pdm = (char *) NULL;
263 display_str = getenv("DISPLAY");
264 auth_file = (char *) NULL;
265 g.log_file = (char *) NULL;
266 security_flag = False;
269 * Parse command line arguments.
272 if (!strcmp (*argv, "-a")) {
273 g.alt_selection = *++argv;
275 else if (!strncmp (*argv, "-d", 2)) {
276 display_str = *++argv;
278 else if (!strcmp (*argv, "-p")) {
279 g.default_pdm = *++argv;
281 else if (!strcmp (*argv, "-P")) {
282 g.override_pdm = *++argv;
284 else if (!strcmp (*argv, "-s")) {
285 security_flag = True;
287 else if (!strcmp (*argv, "-f")) {
290 else if (!strcmp (*argv, "-l")) {
291 g.log_file = *++argv;
293 else if (!strncmp (*argv, "-h", 2)) {
294 pusage( g.prog_name );
299 * Ignore unknown options.
306 * Open a connection to the X-Server.
308 XtToolkitInitialize ();
309 g.context = XtCreateApplicationContext();
310 if ( (sel_display = XtOpenDisplay( g.context, display_str,
312 0, 0, &argc, argv )) == NULL ) {
313 fprintf( stderr , "\n" );
314 fprintf( stderr , PDMD_MSG_2, g.prog_name, display_str );
315 fprintf( stderr , "\n" );
316 fprintf( stderr , "\n" );
321 * Create master PDM window upon which selections
324 tscreen = DefaultScreen( sel_display );
326 sel_window = XCreateSimpleWindow( sel_display,
327 DefaultRootWindow( sel_display ),
329 BlackPixel(sel_display, tscreen),
330 WhitePixel(sel_display, tscreen) );
333 * Setup PDM_MANAGER selection
335 if ( ! _PdmMgrSetup( sel_display, sel_window, security_flag ) ) {
336 fprintf( stderr , "\n" );
337 fprintf( stderr , PDMD_MSG_3, g.prog_name , g.alt_selection );
338 fprintf( stderr , "\n" );
339 fprintf( stderr , "\n" );
345 * Install the "Xt Signal Pipe" Kicker handler.
347 if ( pipe(xtkick_pipeG) == -1 ) {
348 fprintf( stderr , "\n" );
349 fprintf( stderr , PDMD_MSG_4, g.prog_name );
350 fprintf( stderr , "\n" );
351 fprintf( stderr , "\n" );
354 xtid = XtAppAddInput( g.context, xtkick_pipeG[0],
355 (XtPointer) XtInputReadMask,
356 xtkick_proc, (XtPointer) NULL );
359 * Install signal handers.
361 sigemptyset(&svec.sa_mask);
363 svec.sa_handler = handle_SIGCLD;
364 (void) sigaction(SIGCLD, &svec, (struct sigaction *) NULL);
367 * After this point, we need to trap all X and XIO errors.
369 * XIO trap handlers are installed at critical points, and
370 * the following generic X trap handler is used to set
373 XSetErrorHandler( generic_error_handler );
380 * XtAppNextEvent breaks for several reasons:
383 * XtAppNextEvent will dispatch for several reasons:
384 * - Alt input occurs on a pdm message pipe
385 * - Alt input occurs because a pdm message pipe was disconnected
386 * - Alt input occurs on our "Xt Signal Pipe" and we need to
387 * rediscover what happened as a result of that signal.
389 XtAppNextEvent( g.context, &report );
390 switch (report.type) {
393 if (report.xclient.message_type == g.pdm_mail) {
394 dispatch_mbox( &report );
397 /* ignore/pitch the event */
401 case SelectionRequest:
402 if (report.xselectionrequest.selection == g.pdm_selection) {
403 if (report.xselectionrequest.target == g.pdm_start) {
404 dispatch_mgr( &report );
406 else if (report.xselectionrequest.target==g.pdm_targets) {
407 dispatch_targets( &report );
409 else if (report.xselectionrequest.target==g.pdm_multiple){
410 dispatch_multiple( &report );
412 else if (report.xselectionrequest.target==g.pdm_timestamp){
413 dispatch_timestamp( &report );
415 else if (report.xselectionrequest.target==g.pdm_mbox) {
416 dispatch_mbox( &report );
419 dispatch_not_supported( &report );
423 /* ignore/pitch the event */
427 case SelectionNotify:
428 /* pitch the event */
433 * Someone is trying to tear away the selection.
434 * REACT by trying to reclaim it and logging an
444 * Use the opportunity to check for freshly finished
445 * PDMs, and close them out.
450 XDestroyWindow( sel_display, sel_window );
452 XtCloseDisplay( sel_display );