1 /* $Id$ */
2 /*-
3  * Copyright (c) 2003-2006 Benedikt Meurer <benny@xfce.org>
4  * Copyright (c) 2008 Brian Tarricone <bjt23@cornell.edu>
5  * All rights reserved.
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2, or (at your option)
10  * any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
20  * MA 02110-1301 USA.
21  */
22 
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 
27 #ifdef HAVE_ERRNO_H
28 #include <errno.h>
29 #endif
30 #ifdef HAVE_MEMORY_H
31 #include <memory.h>
32 #endif
33 #ifdef HAVE_STDIO_H
34 #include <stdio.h>
35 #endif
36 #ifdef HAVE_STDLIB_H
37 #include <stdlib.h>
38 #endif
39 #ifdef HAVE_STRING_H
40 #include <string.h>
41 #endif
42 #ifdef HAVE_TIME_H
43 #include <time.h>
44 #endif
45 #ifdef HAVE_UNISTD_H
46 #include <unistd.h>
47 #endif
48 #ifdef HAVE_SYS_TYPES_H
49 #include <sys/types.h>
50 #endif
51 #ifdef HAVE_SIGNAL_H
52 #include <signal.h>
53 #endif
54 
55 #include <glib/gstdio.h>
56 #include <gdk/gdkx.h>
57 #include <libxfce4ui/libxfce4ui.h>
58 
59 #include <libxfsm/xfsm-util.h>
60 
61 #include <xfce4-session/xfsm-compat-gnome.h>
62 #include <xfce4-session/xfsm-compat-kde.h>
63 #include <xfce4-session/xfsm-global.h>
64 #include <xfce4-session/xfsm-manager.h>
65 #include <xfce4-session/xfsm-systemd.h>
66 
67 #include <xfce4-session/xfsm-startup.h>
68 
69 
70 typedef struct
71 {
72   XfsmManager    *manager;
73   XfsmProperties *properties;
74 } XfsmStartupData;
75 
76 static gboolean xfsm_startup_session_next_prio_group (XfsmManager *manager);
77 
78 static void     xfsm_startup_data_free               (XfsmStartupData *sdata);
79 static void     xfsm_startup_child_watch             (GPid         pid,
80                                                       gint         status,
81                                                       gpointer     user_data);
82 static gboolean xfsm_startup_timeout                 (gpointer     data);
83 
84 static void     xfsm_startup_handle_failed_startup   (XfsmProperties *properties,
85                                                       XfsmManager    *manager);
86 
87 
88 static pid_t running_sshagent = -1;
89 static pid_t running_gpgagent = -1;
90 static gboolean gpgagent_ssh_enabled = FALSE;
91 
92 
93 
94 static pid_t
xfsm_gpg_agent_pid(const gchar * gpg_agent_info)95 xfsm_gpg_agent_pid (const gchar *gpg_agent_info)
96 {
97   pid_t        pid = -1;
98   gchar      **fields;
99 
100   if (gpg_agent_info == NULL || *gpg_agent_info == '\0')
101     return -1;
102 
103   fields = g_strsplit (gpg_agent_info, ":", 3);
104   if (fields != NULL)
105     {
106       /* second field of GPG_AGENT_INFO is a PID */
107       pid = atoi (fields[1]);
108       g_strfreev (fields);
109     }
110 
111   return pid;
112 }
113 
114 
115 
116 static pid_t
xfsm_ssh_agent_pid(const gchar * ssh_agent_pid)117 xfsm_ssh_agent_pid (const gchar *ssh_agent_pid)
118 {
119   if (ssh_agent_pid == NULL || *ssh_agent_pid == '\0')
120     return -1;
121 
122   return atoi (ssh_agent_pid);
123 }
124 
125 
126 
127 static pid_t
xfsm_startup_init_agent(const gchar * cmd,const gchar * agent,gboolean want_pid)128 xfsm_startup_init_agent (const gchar *cmd,
129                          const gchar *agent,
130                          gboolean want_pid)
131 {
132   gchar     *cmdoutput = NULL;
133   GError    *error = NULL;
134   gchar    **lines;
135   guint      i;
136   gchar     *p, *t;
137   gchar     *variable, *value;
138   pid_t      pid = -1;
139 
140   if (g_spawn_command_line_sync (cmd, &cmdoutput, NULL, NULL, &error))
141     {
142       if (G_UNLIKELY (cmdoutput == NULL))
143         {
144           g_message ("%s returned no variables to stdout", agent);
145           return -1;
146         }
147 
148       lines = g_strsplit (cmdoutput, "\n", -1);
149       g_assert (lines != NULL);
150       for (i = 0; lines[i] != NULL; i++)
151         {
152           p = strchr (lines[i], '=');
153           if (G_UNLIKELY (p == NULL))
154             continue;
155           t = strchr (p + 1, ';');
156           if (G_UNLIKELY (t == NULL))
157             continue;
158 
159           variable = g_strndup (lines[i], p - lines[i]);
160           value = g_strndup (p + 1, t - p - 1);
161 
162           /* try to get agent pid from the variable */
163           if (want_pid && pid <= 0)
164             {
165               if (g_strcmp0 (variable, "SSH_AGENT_PID") == 0)
166                 pid = xfsm_ssh_agent_pid (value);
167               else if (g_strcmp0 (variable, "GPG_AGENT_INFO") == 0)
168                 pid = xfsm_gpg_agent_pid (value);
169             }
170 
171           g_setenv (variable, value, TRUE);
172 
173           g_free (variable);
174           g_free (value);
175         }
176       g_strfreev (lines);
177     }
178   else
179     {
180       g_warning ("Failed to spawn %s: %s", agent, error->message);
181       g_error_free (error);
182 
183       return -1;
184     }
185 
186   g_free (cmdoutput);
187 
188   if (!want_pid)
189     pid = 1;
190 
191   if (pid <= 0)
192     g_warning ("%s returned no PID in the variables", agent);
193 
194   return pid;
195 }
196 
197 
xfsm_gpg_agent_shutdown(gboolean quiet)198 static void xfsm_gpg_agent_shutdown(gboolean quiet)
199 {
200       GError      *error = NULL;
201 
202       g_spawn_command_line_sync ("gpgconf --kill gpg-agent",
203                                  NULL, NULL, NULL, &error);
204       if (error)
205         {
206           if (!quiet)
207             g_warning ("failed to kill gpg-agent via gpgconf, error was %s",
208                        error->message);
209           g_error_free (error);
210         }
211 }
212 
213 
214 void
xfsm_startup_init(XfconfChannel * channel)215 xfsm_startup_init (XfconfChannel *channel)
216 {
217   gchar       *ssh_agent;
218   gchar       *ssh_agent_path = NULL;
219   gchar       *gpg_agent_path = NULL;
220   gchar       *cmd;
221   gchar       *cmdoutput = NULL;
222   GError      *error = NULL;
223   pid_t        agentpid;
224   gboolean     gnome_keyring_found;
225 
226       /* if GNOME compatibility is enabled and gnome-keyring-daemon
227        * is found, skip the gpg/ssh agent startup and wait for
228        * gnome-keyring, which is probably what the user wants */
229   if (xfconf_channel_get_bool (channel, "/compat/LaunchGNOME", FALSE))
230     {
231       cmd = g_find_program_in_path ("gnome-keyring-daemon");
232       gnome_keyring_found = (cmd != NULL);
233       g_free (cmd);
234 
235       if (gnome_keyring_found)
236         {
237           g_print ("xfce4-session: %s\n",
238                    "GNOME compatibility is enabled and gnome-keyring-daemon is "
239                    "found on the system. Skipping gpg/ssh-agent startup.");
240           return;
241         }
242     }
243 
244   if (xfconf_channel_get_bool (channel, "/startup/gpg-agent/enabled", TRUE))
245     {
246       gpg_agent_path = g_find_program_in_path ("gpg-agent");
247       if (gpg_agent_path == NULL)
248         g_printerr ("xfce4-session: %s\n",
249                     "No GPG agent found");
250     }
251 
252   if (xfconf_channel_get_bool (channel, "/startup/ssh-agent/enabled", TRUE))
253     {
254       ssh_agent = xfconf_channel_get_string (channel, "/startup/ssh-agent/type", NULL);
255 
256       if (ssh_agent == NULL
257           || g_strcmp0 (ssh_agent, "ssh-agent") == 0)
258         {
259           ssh_agent_path = g_find_program_in_path ("ssh-agent");
260           if (ssh_agent_path == NULL)
261             g_printerr ("xfce4-session: %s\n",
262                         "No SSH authentication agent found");
263         }
264       else if (g_strcmp0 (ssh_agent, "gpg-agent") == 0)
265         {
266           if (gpg_agent_path != NULL)
267              gpgagent_ssh_enabled = TRUE;
268            else
269                g_printerr ("xfce4-session: %s\n", "gpg-agent is configured as SSH agent, "
270                           "but gpg-agent is disabled or not found");
271         }
272       else
273         {
274           g_message ("Unknown SSH authentication agent \"%s\" set", ssh_agent);
275         }
276       g_free (ssh_agent);
277     }
278 
279   if (G_LIKELY (ssh_agent_path != NULL || gpgagent_ssh_enabled))
280     {
281       agentpid = xfsm_ssh_agent_pid (g_getenv ("SSH_AGENT_PID"));
282 
283       /* check if the pid is still responding (ie not stale) */
284       if (agentpid > 0 && kill (agentpid, 0) == 0)
285         {
286           g_message ("SSH authentication agent is already running");
287 
288           gpgagent_ssh_enabled = FALSE;
289           g_free (ssh_agent_path);
290           ssh_agent_path = NULL;
291         }
292       else
293         {
294           g_unsetenv ("SSH_AGENT_PID");
295           g_unsetenv ("SSH_AUTH_SOCK");
296         }
297 
298       if (ssh_agent_path != NULL)
299         {
300           cmd = g_strdup_printf ("%s -s", ssh_agent_path);
301           /* keep this around for shutdown */
302           running_sshagent = xfsm_startup_init_agent (cmd, "ssh-agent", TRUE);
303           g_free (cmd);
304 
305           /* update dbus environment */
306           if (LOGIND_RUNNING())
307             {
308               cmd = g_strdup_printf ("%s", "dbus-update-activation-environment --systemd SSH_AUTH_SOCK");
309             }
310           else
311             {
312               cmd = g_strdup_printf ("%s", "dbus-update-activation-environment SSH_AUTH_SOCK");
313             }
314           g_spawn_command_line_sync (cmd, &cmdoutput, NULL, NULL, &error);
315 
316           if (error)
317             {
318               g_warning ("failed to call dbus-update-activation-environment. Output was %s, error was %s",
319                          cmdoutput, error->message);
320             }
321 
322           g_free (cmd);
323           g_free (ssh_agent_path);
324           g_clear_pointer (&cmdoutput, g_free);
325           g_clear_error (&error);
326         }
327     }
328 
329   if (G_LIKELY (gpg_agent_path != NULL))
330     {
331       xfsm_gpg_agent_shutdown (TRUE);
332         {
333           gboolean want_pid;
334           gchar *cmd_tmp;
335           gchar *envfile;
336 
337           g_unsetenv ("GPG_AGENT_INFO");
338 
339           envfile = xfce_resource_save_location (XFCE_RESOURCE_CACHE, "gpg-agent-info", FALSE);
340 
341           cmd_tmp = g_strdup_printf ("%s --sh --daemon%s", gpg_agent_path,
342                                      gpgagent_ssh_enabled ?
343                                      " --enable-ssh-support" : "");
344 
345           cmd = cmd_tmp;
346           want_pid = FALSE;
347 
348           /* keep this around for shutdown */
349           running_gpgagent = xfsm_startup_init_agent (cmd, "gpg-agent",
350                                                       want_pid);
351 
352           g_free (cmd);
353           g_free (envfile);
354         }
355 
356       g_free (gpg_agent_path);
357     }
358 }
359 
360 
361 
362 void
xfsm_startup_shutdown(void)363 xfsm_startup_shutdown (void)
364 {
365   if (running_sshagent > 0)
366     {
367       if (kill (running_sshagent, SIGTERM) == 0)
368         {
369          /* make sure the env values are unset */
370          g_unsetenv ("SSH_AGENT_PID");
371          g_unsetenv ("SSH_AUTH_SOCK");
372         }
373       else
374         {
375           g_warning ("Failed to kill ssh-agent with pid %d", running_sshagent);
376         }
377     }
378 
379   if (running_gpgagent > 0)
380     {
381       xfsm_gpg_agent_shutdown (FALSE);
382     }
383 }
384 
385 
386 
387 static void
xfsm_startup_autostart(XfsmManager * manager)388 xfsm_startup_autostart (XfsmManager *manager)
389 {
390   xfsm_launch_desktop_files_on_login (FALSE);
391 }
392 
393 
394 
395 void
xfsm_startup_foreign(XfsmManager * manager)396 xfsm_startup_foreign (XfsmManager *manager)
397 {
398   if (xfsm_manager_get_compat_startup(manager, XFSM_MANAGER_COMPAT_KDE))
399     xfsm_compat_kde_startup ();
400 
401   if (xfsm_manager_get_compat_startup(manager, XFSM_MANAGER_COMPAT_GNOME))
402     xfsm_compat_gnome_startup ();
403 }
404 
405 
406 
407 static void
xfsm_startup_at_set_gtk_modules(void)408 xfsm_startup_at_set_gtk_modules (void)
409 {
410   const gchar  *old;
411   gchar       **modules;
412   guint         i;
413   gboolean      found_gail = FALSE;
414   gboolean      found_atk_bridge = FALSE;
415   GString      *new;
416 
417   old = g_getenv ("GTK_MODULES");
418   if (old != NULL && *old != '\0')
419     {
420       /* check which modules are already loaded */
421       modules = g_strsplit (old, ":", -1);
422       for (i = 0; modules[i] != NULL; i++)
423         {
424           if (strcmp (modules[i], "gail") == 0)
425             found_gail = TRUE;
426           else if (strcmp (modules[i], "atk-bridge") == 0)
427             found_atk_bridge = TRUE;
428         }
429       g_strfreev (modules);
430 
431       if (!found_gail || !found_atk_bridge)
432         {
433           /* append modules to old value */
434           new = g_string_new (old);
435           if (!found_gail)
436             new = g_string_append (new, ":gail");
437           if (!found_atk_bridge)
438             new = g_string_append (new, ":atk-bridge");
439 
440           g_setenv ("GTK_MODULES", new->str, TRUE);
441           g_string_free (new, TRUE);
442         }
443     }
444   else
445     {
446       g_setenv ("GTK_MODULES", "gail:atk-bridge", TRUE);
447     }
448 }
449 
450 
451 static gboolean
xfsm_startup_at_spi_ior_set(void)452 xfsm_startup_at_spi_ior_set (void)
453 {
454   Atom        AT_SPI_IOR;
455   GdkDisplay *display;
456   Atom        actual_type;
457   gint        actual_format;
458   guchar    *data = NULL;
459   gulong     nitems;
460   gulong     leftover;
461 
462   display = gdk_display_get_default ();
463   AT_SPI_IOR = XInternAtom (GDK_DISPLAY_XDISPLAY (display), "AT_SPI_IOR", False);
464   XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
465                       XDefaultRootWindow (GDK_DISPLAY_XDISPLAY (display)),
466                       AT_SPI_IOR, 0L,
467                       (long) BUFSIZ, False,
468                       (Atom) 31, &actual_type, &actual_format,
469                       &nitems, &leftover, &data);
470 
471   if (data == NULL)
472     return FALSE;
473   XFree (data);
474 
475   return TRUE;
476 }
477 
478 
479 static void
xfsm_startup_at(XfsmManager * manager)480 xfsm_startup_at (XfsmManager *manager)
481 {
482   gint n, i;
483 
484   /* start at-spi-dbus-bus and/or at-spi-registryd */
485   n = xfsm_launch_desktop_files_on_login (TRUE);
486 
487   if (n > 0)
488     {
489       xfsm_startup_at_set_gtk_modules ();
490 
491       /* wait for 2 seconds until the at-spi registered, not very nice
492        * but required to properly start an accessible desktop */
493       for (i = 0; i < 10; i++)
494         {
495           if (xfsm_startup_at_spi_ior_set ())
496             break;
497           xfsm_verbose ("Waiting for at-spi to register...\n");
498           g_usleep (G_USEC_PER_SEC / 5);
499         }
500     }
501   else
502     {
503       g_warning ("No assistive technology service provider was started!");
504     }
505 }
506 
507 
508 void
xfsm_startup_begin(XfsmManager * manager)509 xfsm_startup_begin (XfsmManager *manager)
510 {
511   /* start assistive technology before anything else */
512   if (xfsm_manager_get_start_at (manager))
513     xfsm_startup_at (manager);
514 
515   if (xfsm_manager_get_use_failsafe_mode (manager))
516     xfsm_verbose ("Starting the session in failsafe mode.\n");
517 
518   xfsm_startup_session_continue (manager);
519 }
520 
521 
522 gboolean
xfsm_startup_start_properties(XfsmProperties * properties,XfsmManager * manager)523 xfsm_startup_start_properties (XfsmProperties *properties,
524                                XfsmManager    *manager)
525 {
526   XfsmStartupData *child_watch_data;
527   XfsmStartupData *startup_timeout_data;
528   gchar          **restart_command;
529   gchar          **argv;
530   gint             argc;
531   gint             n;
532   const gchar     *current_directory;
533   GPid             pid;
534   GError          *error = NULL;
535 
536   /* release any possible old resources related to a previous startup */
537   xfsm_properties_set_default_child_watch (properties);
538 
539   /* generate the argument vector for the application (expanding variables) */
540   restart_command = xfsm_properties_get_strv (properties, SmRestartCommand);
541   argc = g_strv_length (restart_command);
542   argv = g_new (gchar *, argc + 1);
543   for (n = 0; n < argc; ++n)
544     argv[n] = xfce_expand_variables (restart_command[n], NULL);
545   argv[n] = NULL;
546 
547   current_directory = xfsm_properties_get_string (properties, SmCurrentDirectory);
548 
549   if (!g_spawn_async (current_directory,
550                       argv, NULL,
551                       G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH,
552                       NULL, NULL,
553                       &pid, &error))
554     {
555       g_warning ("Unable to launch \"%s\": %s",
556                  *argv, error->message);
557       g_error_free (error);
558       g_strfreev (argv);
559 
560       return FALSE;
561     }
562 
563   /* Don't waste time if we're not debugging, but if we are print the
564    * command + the arguments */
565   if (xfsm_is_verbose_enabled ())
566     {
567       gchar *command = g_strjoinv (" ", argv);
568       xfsm_verbose ("Launching command \"%s\" with PID %d\n", command, (gint) pid);
569       g_free (command);
570     }
571 
572   g_strfreev (argv);
573 
574   properties->pid = pid;
575 
576   /* set a watch to make sure the child doesn't quit before registering */
577   child_watch_data = g_new0 (XfsmStartupData, 1);
578   child_watch_data->manager = g_object_ref (manager);
579   child_watch_data->properties = properties;
580   child_watch_data->properties->child_watch_id =
581       g_child_watch_add_full (G_PRIORITY_LOW, properties->pid,
582                               xfsm_startup_child_watch, child_watch_data,
583                               (GDestroyNotify) xfsm_startup_data_free);
584 
585   /* set a timeout -- client must register in a a certain amount of time
586    * or it's assumed to be broken/have issues. */
587   startup_timeout_data = g_new (XfsmStartupData, 1);
588   startup_timeout_data->manager = g_object_ref (manager);
589   startup_timeout_data->properties = properties;
590   properties->startup_timeout_id = g_timeout_add_full (G_PRIORITY_DEFAULT,
591                                                        STARTUP_TIMEOUT,
592                                                        xfsm_startup_timeout,
593                                                        startup_timeout_data,
594                                                        (GDestroyNotify) xfsm_startup_data_free);
595 
596   return TRUE;
597 }
598 
599 
600 void
xfsm_startup_session_continue(XfsmManager * manager)601 xfsm_startup_session_continue (XfsmManager *manager)
602 {
603   GQueue  *pending_properties = xfsm_manager_get_queue (manager, XFSM_MANAGER_QUEUE_PENDING_PROPS);
604   gboolean client_started = FALSE;
605 
606   /* try to start some clients.  if we fail to start anything in the current
607    * priority group, move right to the next one.  if we *did* start something,
608    * the failed/registered handlers will take care of moving us on to the
609    * next priority group */
610   while (client_started == FALSE && g_queue_peek_head (pending_properties) != NULL)
611     client_started = xfsm_startup_session_next_prio_group (manager);
612 
613   if (G_UNLIKELY (client_started == FALSE && g_queue_peek_head (pending_properties) == NULL))
614     {
615       /* we failed to start anything, and we don't have anything else,
616        * to start, so just move on to the autostart items and signal
617        * the manager that we're finished */
618       xfsm_verbose ("Nothing started and nothing to start, moving to autostart items\n");
619       xfsm_startup_autostart (manager);
620       xfsm_manager_signal_startup_done (manager);
621     }
622 }
623 
624 
625 /* returns TRUE if we started anything, FALSE if we didn't */
626 static gboolean
xfsm_startup_session_next_prio_group(XfsmManager * manager)627 xfsm_startup_session_next_prio_group (XfsmManager *manager)
628 {
629   GQueue         *pending_properties = xfsm_manager_get_queue (manager, XFSM_MANAGER_QUEUE_PENDING_PROPS);
630   GQueue         *starting_properties = xfsm_manager_get_queue (manager, XFSM_MANAGER_QUEUE_STARTING_PROPS);
631   XfsmProperties *properties;
632   gint            cur_prio_group;
633   gboolean        client_started = FALSE;
634 
635   properties = (XfsmProperties *) g_queue_peek_head (pending_properties);
636   if (properties == NULL)
637     return FALSE;
638 
639   cur_prio_group = xfsm_properties_get_uchar (properties, GsmPriority, 50);
640 
641   xfsm_verbose ("Starting apps in prio group %d\n (%d)", cur_prio_group, g_queue_get_length (pending_properties));
642 
643   while ((properties = g_queue_pop_head (pending_properties)))
644     {
645       /* quit if we've hit all the clients in the current prio group */
646       if (xfsm_properties_get_uchar (properties, GsmPriority, 50) != cur_prio_group)
647         {
648           /* we're not starting this one yet; put it back */
649           g_queue_push_head (pending_properties, properties);
650           break;
651         }
652 
653       /* as clients cannot be uniquely identified in failsafe mode we at least count
654          how many per priority group have registered */
655       if (xfsm_manager_get_use_failsafe_mode (manager))
656         xfsm_manager_increase_failsafe_pending_clients (manager);
657 
658       if (G_LIKELY (xfsm_startup_start_properties (properties, manager)))
659         {
660           g_queue_push_tail (starting_properties, properties);
661           client_started = TRUE;
662         }
663       else
664         {
665           /* if starting the app failed, let the manager handle it */
666           if (xfsm_manager_handle_failed_properties (manager, properties) == FALSE)
667             xfsm_properties_free (properties);
668         }
669     }
670 
671   return client_started;
672 }
673 
674 
675 static void
xfsm_startup_data_free(XfsmStartupData * sdata)676 xfsm_startup_data_free (XfsmStartupData *sdata)
677 {
678   g_object_unref (sdata->manager);
679   g_free (sdata);
680 }
681 
682 
683 static void
xfsm_startup_child_watch(GPid pid,gint status,gpointer user_data)684 xfsm_startup_child_watch (GPid     pid,
685                           gint     status,
686                           gpointer user_data)
687 {
688   XfsmStartupData *cwdata = user_data;
689   GQueue          *starting_properties;
690 
691   xfsm_verbose ("Client Id = %s, PID %d exited with status %d\n",
692                 cwdata->properties->client_id, (gint)pid, status);
693 
694   cwdata->properties->child_watch_id = 0;
695   cwdata->properties->pid = -1;
696 
697   starting_properties = xfsm_manager_get_queue (cwdata->manager, XFSM_MANAGER_QUEUE_STARTING_PROPS);
698   if (g_queue_find (starting_properties, cwdata->properties) != NULL)
699     {
700       xfsm_verbose ("Client Id = %s died while starting up\n",
701                     cwdata->properties->client_id);
702       xfsm_startup_handle_failed_startup (cwdata->properties, cwdata->manager);
703     }
704 
705   /* NOTE: cwdata->properties could have been freed by
706    * xfsm_startup_handle_failed_startup() above, so don't try to access
707    * any of its members here. */
708 
709   g_spawn_close_pid (pid);
710 }
711 
712 
713 static gboolean
xfsm_startup_timeout(gpointer data)714 xfsm_startup_timeout (gpointer data)
715 {
716   XfsmStartupData *stdata = data;
717 
718   xfsm_verbose ("Client Id = %s failed to register in time\n",
719                 stdata->properties->client_id);
720 
721   stdata->properties->startup_timeout_id = 0;
722   xfsm_startup_handle_failed_startup (stdata->properties, stdata->manager);
723 
724   return FALSE;
725 }
726 
727 
728 static void
xfsm_startup_handle_failed_startup(XfsmProperties * properties,XfsmManager * manager)729 xfsm_startup_handle_failed_startup (XfsmProperties *properties,
730                                     XfsmManager    *manager)
731 {
732   GQueue *starting_properties = xfsm_manager_get_queue (manager, XFSM_MANAGER_QUEUE_STARTING_PROPS);
733 
734   xfsm_verbose ("Client Id = %s failed to start\n", properties->client_id);
735 
736   /* if our timer hasn't run out yet, kill it */
737   if (properties->startup_timeout_id > 0)
738     {
739       g_source_remove (properties->startup_timeout_id);
740       properties->startup_timeout_id = 0;
741     }
742 
743   xfsm_properties_set_default_child_watch (properties);
744 
745   /* not starting anymore, so remove it from the list.  tell the manager
746    * it failed, and let it do its thing. */
747   g_queue_remove (starting_properties, properties);
748   if (xfsm_manager_handle_failed_properties (manager, properties) == FALSE)
749       xfsm_properties_free (properties);
750 
751   if (g_queue_peek_head (starting_properties) == NULL
752       && xfsm_manager_get_state (manager) == XFSM_MANAGER_STARTUP)
753     {
754       /* everything has finished starting or failed; continue startup */
755       xfsm_startup_session_continue (manager);
756     }
757 }
758