1 /*
2 * Copyright (C) 2010-2011 Robert Ancell.
3 * Author: Robert Ancell <robert.ancell@canonical.com>
4 *
5 * This program is free software: you can redistribute it and/or modify it under
6 * the terms of the GNU General Public License as published by the Free Software
7 * Foundation, either version 3 of the License, or (at your option) any later
8 * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
9 * license.
10 */
11
12 #include <stdlib.h>
13 #include <string.h>
14 #include <sys/wait.h>
15
16 #include "seat.h"
17 #include "configuration.h"
18 #include "guest-account.h"
19 #include "greeter-session.h"
20 #include "session-config.h"
21
22 enum {
23 SESSION_ADDED,
24 RUNNING_USER_SESSION,
25 SESSION_REMOVED,
26 STOPPED,
27 LAST_SIGNAL
28 };
29 static guint signals[LAST_SIGNAL] = { 0 };
30
31 typedef struct
32 {
33 /* XDG name for this seat */
34 gchar *name;
35
36 /* Configuration for this seat */
37 GHashTable *properties;
38
39 /* TRUE if this seat can run multiple sessions at once */
40 gboolean supports_multi_session;
41
42 /* TRUE if display server can be shared for sessions */
43 gboolean share_display_server;
44
45 /* The display servers on this seat */
46 GList *display_servers;
47
48 /* The sessions on this seat */
49 GList *sessions;
50
51 /* The last session set to active */
52 Session *active_session;
53
54 /* The session belonging to the active greeter user */
55 Session *next_session;
56
57 /* The session to set active when it starts */
58 Session *session_to_activate;
59
60 /* TRUE once we have started */
61 gboolean started;
62
63 /* TRUE if stopping this seat (waiting for displays to stop) */
64 gboolean stopping;
65
66 /* TRUE if stopped */
67 gboolean stopped;
68
69 /* The greeter to be started to replace the current one */
70 GreeterSession *replacement_greeter;
71 } SeatPrivate;
72
73 static void seat_logger_iface_init (LoggerInterface *iface);
74
75 G_DEFINE_TYPE_WITH_CODE (Seat, seat, G_TYPE_OBJECT,
76 G_ADD_PRIVATE (Seat)
77 G_IMPLEMENT_INTERFACE (
78 LOGGER_TYPE, seat_logger_iface_init))
79
80 typedef struct
81 {
82 gchar *name;
83 GType type;
84 } SeatModule;
85 static GHashTable *seat_modules = NULL;
86
87 // FIXME: Make a get_display_server() that re-uses display servers if supported
88 static DisplayServer *create_display_server (Seat *seat, Session *session);
89 static gboolean start_display_server (Seat *seat, DisplayServer *display_server);
90 static GreeterSession *create_greeter_session (Seat *seat);
91 static void start_session (Seat *seat, Session *session);
92
93 static void
free_seat_module(gpointer data)94 free_seat_module (gpointer data)
95 {
96 SeatModule *module = data;
97 g_free (module->name);
98 g_free (module);
99 }
100
101 void
seat_register_module(const gchar * name,GType type)102 seat_register_module (const gchar *name, GType type)
103 {
104 if (!seat_modules)
105 seat_modules = g_hash_table_new_full (g_str_hash, g_str_equal, free_seat_module, NULL);
106
107 g_debug ("Registered seat module %s", name);
108
109 SeatModule *module = g_malloc0 (sizeof (SeatModule));
110 module->name = g_strdup (name);
111 module->type = type;
112 g_hash_table_insert (seat_modules, g_strdup (name), module);
113 }
114
115 Seat *
seat_new(const gchar * module_name)116 seat_new (const gchar *module_name)
117 {
118 g_return_val_if_fail (module_name != NULL, NULL);
119
120 SeatModule *m = NULL;
121 if (seat_modules)
122 m = g_hash_table_lookup (seat_modules, module_name);
123 if (!m)
124 return NULL;
125
126 return g_object_new (m->type, NULL);
127 }
128
129 void
seat_set_name(Seat * seat,const gchar * name)130 seat_set_name (Seat *seat, const gchar *name)
131 {
132 SeatPrivate *priv = seat_get_instance_private (seat);
133
134 g_return_if_fail (seat != NULL);
135 g_free (priv->name);
136 priv->name = g_strdup (name);
137 }
138
139 void
seat_set_property(Seat * seat,const gchar * name,const gchar * value)140 seat_set_property (Seat *seat, const gchar *name, const gchar *value)
141 {
142 SeatPrivate *priv = seat_get_instance_private (seat);
143 g_return_if_fail (seat != NULL);
144 g_hash_table_insert (priv->properties, g_strdup (name), g_strdup (value));
145 }
146
147 const gchar *
seat_get_string_property(Seat * seat,const gchar * name)148 seat_get_string_property (Seat *seat, const gchar *name)
149 {
150 SeatPrivate *priv = seat_get_instance_private (seat);
151 g_return_val_if_fail (seat != NULL, NULL);
152 return g_hash_table_lookup (priv->properties, name);
153 }
154
155 gchar **
seat_get_string_list_property(Seat * seat,const gchar * name)156 seat_get_string_list_property (Seat *seat, const gchar *name)
157 {
158 SeatPrivate *priv = seat_get_instance_private (seat);
159 g_return_val_if_fail (seat != NULL, NULL);
160 return g_strsplit (g_hash_table_lookup (priv->properties, name), ";", 0);
161 }
162
163 gboolean
seat_get_boolean_property(Seat * seat,const gchar * name)164 seat_get_boolean_property (Seat *seat, const gchar *name)
165 {
166 const gchar *value = seat_get_string_property (seat, name);
167 if (!value)
168 return FALSE;
169
170 /* Count the number of non-whitespace characters */
171 gint length = 0;
172 for (gint i = 0; value[i]; i++)
173 if (!g_ascii_isspace (value[i]))
174 length = i + 1;
175
176 return strncmp (value, "true", MAX (length, 4)) == 0;
177 }
178
179 gint
seat_get_integer_property(Seat * seat,const gchar * name)180 seat_get_integer_property (Seat *seat, const gchar *name)
181 {
182 const gchar *value = seat_get_string_property (seat, name);
183 return value ? atoi (value) : 0;
184 }
185
186 const gchar *
seat_get_name(Seat * seat)187 seat_get_name (Seat *seat)
188 {
189 SeatPrivate *priv = seat_get_instance_private (seat);
190 g_return_val_if_fail (seat != NULL, NULL);
191 return priv->name;
192 }
193
194 void
seat_set_supports_multi_session(Seat * seat,gboolean supports_multi_session)195 seat_set_supports_multi_session (Seat *seat, gboolean supports_multi_session)
196 {
197 SeatPrivate *priv = seat_get_instance_private (seat);
198 g_return_if_fail (seat != NULL);
199 priv->supports_multi_session = supports_multi_session;
200 }
201
202 void
seat_set_share_display_server(Seat * seat,gboolean share_display_server)203 seat_set_share_display_server (Seat *seat, gboolean share_display_server)
204 {
205 SeatPrivate *priv = seat_get_instance_private (seat);
206 g_return_if_fail (seat != NULL);
207 priv->share_display_server = share_display_server;
208 }
209
210 gboolean
seat_start(Seat * seat)211 seat_start (Seat *seat)
212 {
213 SeatPrivate *priv = seat_get_instance_private (seat);
214
215 g_return_val_if_fail (seat != NULL, FALSE);
216
217 l_debug (seat, "Starting");
218
219 SEAT_GET_CLASS (seat)->setup (seat);
220 priv->started = SEAT_GET_CLASS (seat)->start (seat);
221
222 return priv->started;
223 }
224
225 GList *
seat_get_sessions(Seat * seat)226 seat_get_sessions (Seat *seat)
227 {
228 SeatPrivate *priv = seat_get_instance_private (seat);
229 g_return_val_if_fail (seat != NULL, NULL);
230 return priv->sessions;
231 }
232
233 static gboolean
set_greeter_idle(gpointer greeter)234 set_greeter_idle (gpointer greeter)
235 {
236 greeter_idle (GREETER (greeter));
237 return FALSE;
238 }
239
240 void
seat_set_active_session(Seat * seat,Session * session)241 seat_set_active_session (Seat *seat, Session *session)
242 {
243 SeatPrivate *priv = seat_get_instance_private (seat);
244
245 g_return_if_fail (seat != NULL);
246
247 SEAT_GET_CLASS (seat)->set_active_session (seat, session);
248
249 /* Stop any greeters */
250 for (GList *link = priv->sessions; link; link = link->next)
251 {
252 Session *s = link->data;
253
254 if (s == session || session_get_is_stopping (s))
255 continue;
256
257 if (IS_GREETER_SESSION (s))
258 {
259 Greeter *greeter = greeter_session_get_greeter (GREETER_SESSION (s));
260 if (greeter_get_resettable (greeter))
261 {
262 if (priv->active_session == s)
263 {
264 l_debug (seat, "Idling greeter");
265 /* Do this in an idle callback, because we might very well
266 be in the middle of responding to a START_SESSION
267 request by a greeter. So they won't expect an IDLE
268 call during that. Plus, this isn't time-sensitive. */
269 g_idle_add (set_greeter_idle, greeter);
270 }
271 }
272 else
273 {
274 l_debug (seat, "Stopping greeter");
275 session_stop (s);
276 }
277 }
278 }
279
280 /* Lock previous sessions */
281 if (priv->active_session && session != priv->active_session && !IS_GREETER_SESSION (priv->active_session))
282 session_lock (priv->active_session);
283
284 session_activate (session);
285 g_clear_object (&priv->active_session);
286 priv->active_session = g_object_ref (session);
287 }
288
289 Session *
seat_get_active_session(Seat * seat)290 seat_get_active_session (Seat *seat)
291 {
292 g_return_val_if_fail (seat != NULL, NULL);
293 return SEAT_GET_CLASS (seat)->get_active_session (seat);
294 }
295
296 Session *
seat_get_next_session(Seat * seat)297 seat_get_next_session (Seat *seat)
298 {
299 SeatPrivate *priv = seat_get_instance_private (seat);
300 g_return_val_if_fail (seat != NULL, NULL);
301 return priv->next_session;
302 }
303
304 /**
305 * Obtains the active session which lightdm expects to be active.
306 *
307 * This function is different from seat_get_active_session() in that the
308 * later (in the case of local seats) dynamically finds the session that is
309 * really active (based on the active VT), whereas this function returns the
310 * session that lightdm activated last by itself, which may not be the actual
311 * active session (i.e. VT changes).
312 */
313 Session *
seat_get_expected_active_session(Seat * seat)314 seat_get_expected_active_session (Seat *seat)
315 {
316 SeatPrivate *priv = seat_get_instance_private (seat);
317 g_return_val_if_fail (seat != NULL, NULL);
318 return priv->active_session;
319 }
320
321 /**
322 * Sets the active session which lightdm expects to be active.
323 *
324 * This function is different from seat_set_active_session() in that the
325 * later performs an actual session activation, whereas this function just
326 * updates the active session after the session has been activated by some
327 * means external to lightdm (i.e. VT changes).
328 */
329 void
seat_set_externally_activated_session(Seat * seat,Session * session)330 seat_set_externally_activated_session (Seat *seat, Session *session)
331 {
332 SeatPrivate *priv = seat_get_instance_private (seat);
333 g_return_if_fail (seat != NULL);
334 g_clear_object (&priv->active_session);
335 priv->active_session = g_object_ref (session);
336 }
337
338 Session *
seat_find_session_by_login1_id(Seat * seat,const gchar * login1_session_id)339 seat_find_session_by_login1_id (Seat *seat, const gchar *login1_session_id)
340 {
341 SeatPrivate *priv = seat_get_instance_private (seat);
342
343 for (GList *session_link = priv->sessions; session_link; session_link = session_link->next)
344 {
345 Session *session = session_link->data;
346 if (g_strcmp0 (login1_session_id, session_get_login1_session_id (session)) == 0)
347 return session;
348 }
349
350 return NULL;
351 }
352
353 gboolean
seat_get_can_switch(Seat * seat)354 seat_get_can_switch (Seat *seat)
355 {
356 SeatPrivate *priv = seat_get_instance_private (seat);
357 g_return_val_if_fail (seat != NULL, FALSE);
358 return seat_get_boolean_property (seat, "allow-user-switching") && priv->supports_multi_session;
359 }
360
361 gboolean
seat_get_allow_guest(Seat * seat)362 seat_get_allow_guest (Seat *seat)
363 {
364 g_return_val_if_fail (seat != NULL, FALSE);
365 return seat_get_boolean_property (seat, "allow-guest") && guest_account_is_installed ();
366 }
367
368 static gboolean
run_script(Seat * seat,DisplayServer * display_server,const gchar * script_name,User * user)369 run_script (Seat *seat, DisplayServer *display_server, const gchar *script_name, User *user)
370 {
371 g_autoptr(Process) script = process_new (NULL, NULL);
372
373 process_set_command (script, script_name);
374
375 /* Set POSIX variables */
376 process_set_clear_environment (script, TRUE);
377 process_set_env (script, "SHELL", "/bin/sh");
378
379 if (g_getenv ("LD_PRELOAD"))
380 process_set_env (script, "LD_PRELOAD", g_getenv ("LD_PRELOAD"));
381 if (g_getenv ("LD_LIBRARY_PATH"))
382 process_set_env (script, "LD_LIBRARY_PATH", g_getenv ("LD_LIBRARY_PATH"));
383 if (g_getenv ("PATH"))
384 process_set_env (script, "PATH", g_getenv ("PATH"));
385
386 /* Variables required for regression tests */
387 if (g_getenv ("LIGHTDM_TEST_ROOT"))
388 process_set_env (script, "LIGHTDM_TEST_ROOT", g_getenv ("LIGHTDM_TEST_ROOT"));
389
390 process_set_env (script, "XDG_SEAT", seat_get_name (seat));
391
392 if (user)
393 {
394 process_set_env (script, "USER", user_get_name (user));
395 process_set_env (script, "LOGNAME", user_get_name (user));
396 process_set_env (script, "HOME", user_get_home_directory (user));
397 }
398 else
399 process_set_env (script, "HOME", "/");
400
401 SEAT_GET_CLASS (seat)->run_script (seat, display_server, script);
402
403 gboolean result = FALSE;
404 if (process_start (script, TRUE))
405 {
406 int exit_status = process_get_exit_status (script);
407 if (WIFEXITED (exit_status))
408 {
409 l_debug (seat, "Exit status of %s: %d", script_name, WEXITSTATUS (exit_status));
410 result = WEXITSTATUS (exit_status) == EXIT_SUCCESS;
411 }
412 }
413
414 return result;
415 }
416
417 static void
seat_real_run_script(Seat * seat,DisplayServer * display_server,Process * process)418 seat_real_run_script (Seat *seat, DisplayServer *display_server, Process *process)
419 {
420 }
421
422 static void
emit_upstart_signal(const gchar * signal)423 emit_upstart_signal (const gchar *signal)
424 {
425 g_return_if_fail (signal != NULL);
426 g_return_if_fail (signal[0] != 0);
427
428 if (getuid () != 0)
429 return;
430
431 /* OK if it fails, probably not installed or not running upstart */
432 g_autoptr(GSubprocess) p = g_subprocess_new (G_SUBPROCESS_FLAGS_STDERR_SILENCE, NULL, "initctl", "-q", "emit", signal, "DISPLAY_MANAGER=lightdm", NULL);
433 }
434
435 static void
check_stopped(Seat * seat)436 check_stopped (Seat *seat)
437 {
438 SeatPrivate *priv = seat_get_instance_private (seat);
439
440 if (priv->stopping &&
441 !priv->stopped &&
442 g_list_length (priv->display_servers) == 0 &&
443 g_list_length (priv->sessions) == 0)
444 {
445 priv->stopped = TRUE;
446 l_debug (seat, "Stopped");
447 g_signal_emit (seat, signals[STOPPED], 0);
448 }
449 }
450
451 static void
display_server_stopped_cb(DisplayServer * display_server,Seat * seat)452 display_server_stopped_cb (DisplayServer *display_server, Seat *seat)
453 {
454 SeatPrivate *priv = seat_get_instance_private (seat);
455
456 l_debug (seat, "Display server stopped");
457
458 /* Run a script right after stopping the display server */
459 const gchar *script = seat_get_string_property (seat, "display-stopped-script");
460 if (script)
461 run_script (seat, NULL, script, NULL);
462
463 g_signal_handlers_disconnect_matched (display_server, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, seat);
464 priv->display_servers = g_list_remove (priv->display_servers, display_server);
465
466 if (priv->stopping || !priv->started)
467 {
468 check_stopped (seat);
469 g_object_unref (display_server);
470 return;
471 }
472
473 /* Stop all sessions on this display server */
474 GList *list = g_list_copy (priv->sessions);
475 for (GList *link = list; link; link = link->next)
476 g_object_ref (link->data);
477 for (GList *link = list; link; link = link->next)
478 {
479 Session *session = link->data;
480
481 if (session_get_display_server (session) != display_server || session_get_is_stopping (session))
482 continue;
483
484 gboolean is_failed_greeter = IS_GREETER_SESSION (session) && !session_get_is_started (session);
485
486 l_debug (seat, "Stopping session");
487 session_stop (session);
488
489 /* Stop seat if this is the only display server and it failed to start a greeter */
490 if (is_failed_greeter &&
491 g_list_length (priv->display_servers) == 0)
492 {
493 l_debug (seat, "Stopping; greeter display server failed to start");
494 seat_stop (seat);
495 }
496 }
497 g_list_free_full (list, g_object_unref);
498
499 if (!priv->stopping)
500 {
501 /* If we were the active session, switch to a greeter */
502 Session *active_session = seat_get_active_session (seat);
503 if (!active_session || session_get_display_server (active_session) == display_server)
504 {
505 l_debug (seat, "Active display server stopped, starting greeter");
506 if (!seat_switch_to_greeter (seat))
507 {
508 l_debug (seat, "Stopping; failed to start a greeter");
509 seat_stop (seat);
510 }
511 }
512 }
513
514 g_object_unref (display_server);
515 }
516
517 static gboolean
can_share_display_server(Seat * seat,DisplayServer * display_server)518 can_share_display_server (Seat *seat, DisplayServer *display_server)
519 {
520 SeatPrivate *priv = seat_get_instance_private (seat);
521 return priv->share_display_server && display_server_get_can_share (display_server);
522 }
523
524 static GreeterSession *
find_greeter_session(Seat * seat)525 find_greeter_session (Seat *seat)
526 {
527 SeatPrivate *priv = seat_get_instance_private (seat);
528
529 for (GList *link = priv->sessions; link; link = link->next)
530 {
531 Session *session = link->data;
532 if (!session_get_is_stopping (session) && IS_GREETER_SESSION (session))
533 return GREETER_SESSION (session);
534 }
535
536 return NULL;
537 }
538
539 static GreeterSession *
find_resettable_greeter(Seat * seat)540 find_resettable_greeter (Seat *seat)
541 {
542 SeatPrivate *priv = seat_get_instance_private (seat);
543
544 for (GList *link = priv->sessions; link; link = link->next)
545 {
546 Session *session = link->data;
547 if (!session_get_is_stopping (session) && IS_GREETER_SESSION (session) &&
548 greeter_get_resettable (greeter_session_get_greeter (GREETER_SESSION (session))))
549 return GREETER_SESSION (session);
550 }
551
552 return NULL;
553 }
554
555 static void
set_greeter_hints(Seat * seat,Greeter * greeter)556 set_greeter_hints (Seat *seat, Greeter *greeter)
557 {
558 greeter_clear_hints (greeter);
559 greeter_set_hint (greeter, "default-session", seat_get_string_property (seat, "user-session"));
560 greeter_set_hint (greeter, "hide-users", seat_get_boolean_property (seat, "greeter-hide-users") ? "true" : "false");
561 greeter_set_hint (greeter, "show-manual-login", seat_get_boolean_property (seat, "greeter-show-manual-login") ? "true" : "false");
562 greeter_set_hint (greeter, "show-remote-login", seat_get_boolean_property (seat, "greeter-show-remote-login") ? "true" : "false");
563 greeter_set_hint (greeter, "has-guest-account", seat_get_allow_guest (seat) && seat_get_boolean_property (seat, "greeter-allow-guest") ? "true" : "false");
564 }
565
566 static void
switch_to_greeter_from_failed_session(Seat * seat,Session * session)567 switch_to_greeter_from_failed_session (Seat *seat, Session *session)
568 {
569 SeatPrivate *priv = seat_get_instance_private (seat);
570
571 /* Switch to greeter if one open */
572 GreeterSession *greeter_session = find_resettable_greeter (seat);
573 gboolean existing = FALSE;
574 if (greeter_session)
575 {
576 l_debug (seat, "Switching to existing greeter");
577 set_greeter_hints (seat, greeter_session_get_greeter (greeter_session));
578 existing = TRUE;
579 }
580 else
581 {
582 greeter_session = create_greeter_session (seat);
583 }
584 Greeter *greeter = greeter_session_get_greeter (greeter_session);
585
586 if (session_get_is_guest (session))
587 greeter_set_hint (greeter, "select-guest", "true");
588 else
589 greeter_set_hint (greeter, "select-user", session_get_username (session));
590
591 if (existing)
592 {
593 greeter_reset (greeter);
594 seat_set_active_session (seat, SESSION (greeter_session));
595 }
596 else
597 {
598 g_clear_object (&priv->session_to_activate);
599 priv->session_to_activate = g_object_ref (SESSION (greeter_session));
600
601 if (can_share_display_server (seat, session_get_display_server (session)))
602 session_set_display_server (SESSION (greeter_session), session_get_display_server (session));
603 else
604 {
605 DisplayServer *display_server = create_display_server (seat, session);
606 session_set_display_server (session, display_server);
607 if (!start_display_server (seat, display_server))
608 {
609 l_debug (seat, "Failed to start display server for greeter");
610 seat_stop (seat);
611 }
612 }
613
614 start_session (seat, SESSION (greeter_session));
615 }
616
617 /* Stop failed session */
618 session_stop (session);
619 }
620
621 static void
start_session(Seat * seat,Session * session)622 start_session (Seat *seat, Session *session)
623 {
624 /* Use system location for greeter log file */
625 if (IS_GREETER_SESSION (session))
626 {
627 g_autofree gchar *log_dir = config_get_string (config_get_instance (), "LightDM", "log-directory");
628 g_autofree gchar *filename = g_strdup_printf ("%s-greeter.log", seat_get_name (seat));
629 g_autofree gchar *log_filename = g_build_filename (log_dir, filename, NULL);
630 gboolean backup_logs = config_get_boolean (config_get_instance (), "LightDM", "backup-logs");
631 session_set_log_file (session, log_filename, backup_logs ? LOG_MODE_BACKUP_AND_TRUNCATE : LOG_MODE_APPEND);
632 }
633
634 if (session_start (session))
635 return;
636
637 if (IS_GREETER_SESSION (session))
638 {
639 l_debug (seat, "Failed to start greeter");
640 display_server_stop (session_get_display_server (session));
641 return;
642 }
643
644 l_debug (seat, "Failed to start session, starting greeter");
645 switch_to_greeter_from_failed_session (seat, session);
646 }
647
648 static void
run_session(Seat * seat,Session * session)649 run_session (Seat *seat, Session *session)
650 {
651 SeatPrivate *priv = seat_get_instance_private (seat);
652
653 const gchar *script;
654 if (IS_GREETER_SESSION (session))
655 script = seat_get_string_property (seat, "greeter-setup-script");
656 else
657 script = seat_get_string_property (seat, "session-setup-script");
658 if (script && !run_script (seat, session_get_display_server (session), script, session_get_user (session)))
659 {
660 l_debug (seat, "Switching to greeter due to failed setup script");
661 switch_to_greeter_from_failed_session (seat, session);
662 return;
663 }
664
665 if (!IS_GREETER_SESSION (session))
666 {
667 g_signal_emit (seat, signals[RUNNING_USER_SESSION], 0, session);
668 emit_upstart_signal ("desktop-session-start");
669 }
670
671 session_run (session);
672
673 // FIXME: Wait until the session is ready
674
675 if (session == priv->session_to_activate)
676 {
677 seat_set_active_session (seat, session);
678 g_clear_object (&priv->session_to_activate);
679 }
680 else if (priv->active_session)
681 {
682 /* Multiple sessions can theoretically be on the same VT (especially
683 if using Mir). If a new session appears on an existing active VT,
684 logind will mark it as active, while ConsoleKit will re-mark the
685 oldest session as active. In either case, that may not be the
686 session that we want to be active. So let's be explicit and
687 re-activate the correct session whenever a new session starts.
688 There's no harm to do this in seats that enforce separate VTs. */
689 session_activate (priv->active_session);
690 }
691 }
692
693 static Session *
find_user_session(Seat * seat,const gchar * username,Session * ignore_session)694 find_user_session (Seat *seat, const gchar *username, Session *ignore_session)
695 {
696 SeatPrivate *priv = seat_get_instance_private (seat);
697
698 if (!username)
699 return NULL;
700
701 for (GList *link = priv->sessions; link; link = link->next)
702 {
703 Session *session = link->data;
704
705 if (session == ignore_session)
706 continue;
707
708 if (!session_get_is_stopping (session) && g_strcmp0 (session_get_username (session), username) == 0)
709 return session;
710 }
711
712 return NULL;
713 }
714
715 static void
greeter_active_username_changed_cb(Greeter * greeter,GParamSpec * pspec,Seat * seat)716 greeter_active_username_changed_cb (Greeter *greeter, GParamSpec *pspec, Seat *seat)
717 {
718 SeatPrivate *priv = seat_get_instance_private (seat);
719 Session *session = find_user_session (seat, greeter_get_active_username (greeter), priv->active_session);
720
721 g_clear_object (&priv->next_session);
722 priv->next_session = session ? g_object_ref (session) : NULL;
723
724 SEAT_GET_CLASS (seat)->set_next_session (seat, session);
725 }
726
727 static void
session_authentication_complete_cb(Session * session,Seat * seat)728 session_authentication_complete_cb (Session *session, Seat *seat)
729 {
730 if (session_get_is_authenticated (session))
731 {
732 Session *s = find_user_session (seat, session_get_username (session), session);
733 if (s)
734 {
735 l_debug (seat, "Session authenticated, switching to existing user session");
736 seat_set_active_session (seat, s);
737 session_stop (session);
738 }
739 else
740 {
741 l_debug (seat, "Session authenticated, running command");
742 run_session (seat, session);
743 }
744 }
745 else if (!IS_GREETER_SESSION (session))
746 {
747 l_debug (seat, "Switching to greeter due to failed authentication");
748 switch_to_greeter_from_failed_session (seat, session);
749 }
750 else
751 {
752 l_debug (seat, "Stopping session that failed authentication");
753 session_stop (session);
754 }
755 }
756
757 static void
session_stopped_cb(Session * session,Seat * seat)758 session_stopped_cb (Session *session, Seat *seat)
759 {
760 SeatPrivate *priv = seat_get_instance_private (seat);
761
762 l_debug (seat, "Session stopped");
763
764 g_signal_handlers_disconnect_matched (session, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, seat);
765 priv->sessions = g_list_remove (priv->sessions, session);
766 if (session == priv->active_session)
767 g_clear_object (&priv->active_session);
768 if (session == priv->next_session)
769 g_clear_object (&priv->next_session);
770 if (session == priv->session_to_activate)
771 g_clear_object (&priv->session_to_activate);
772
773 DisplayServer *display_server = session_get_display_server (session);
774
775 /* Cleanup */
776 if (!IS_GREETER_SESSION (session))
777 {
778 const gchar *script = seat_get_string_property (seat, "session-cleanup-script");
779 if (script)
780 run_script (seat, display_server, script, session_get_user (session));
781 }
782
783 /* We were waiting for this session, but it didn't start :( */
784 // FIXME: Start a greeter on this?
785 if (session == priv->session_to_activate)
786 g_clear_object (&priv->session_to_activate);
787
788 if (priv->stopping)
789 {
790 check_stopped (seat);
791 g_object_unref (session);
792 return;
793 }
794
795 /* If there is a pending replacement greeter, start it */
796 if (IS_GREETER_SESSION (session) && priv->replacement_greeter)
797 {
798 GreeterSession *replacement_greeter = priv->replacement_greeter;
799 priv->replacement_greeter = NULL;
800
801 if (session_get_is_authenticated (SESSION (replacement_greeter)))
802 {
803 l_debug (seat, "Greeter stopped, running session");
804 run_session (seat, SESSION (replacement_greeter));
805 }
806 else
807 {
808 l_debug (seat, "Greeter stopped, starting session authentication");
809 start_session (seat, SESSION (replacement_greeter));
810 }
811
812 g_object_unref (replacement_greeter);
813 }
814 /* If this is the greeter session then re-use this display server */
815 else if (IS_GREETER_SESSION (session) &&
816 can_share_display_server (seat, display_server) &&
817 greeter_get_start_session (greeter_session_get_greeter (GREETER_SESSION (session))))
818 {
819 for (GList *link = priv->sessions; link; link = link->next)
820 {
821 Session *s = link->data;
822
823 /* Skip this session and sessions on other display servers */
824 if (s == session || session_get_display_server (s) != display_server || session_get_is_stopping (s))
825 continue;
826
827 if (session_get_is_authenticated (s))
828 {
829 l_debug (seat, "Greeter stopped, running session");
830 run_session (seat, s);
831 }
832 else
833 {
834 l_debug (seat, "Greeter stopped, starting session authentication");
835 start_session (seat, s);
836 }
837 break;
838 }
839 }
840 /* If this is the greeter and nothing else is running then stop the seat */
841 else if (IS_GREETER_SESSION (session) &&
842 !greeter_get_start_session (greeter_session_get_greeter (GREETER_SESSION (session))) &&
843 g_list_length (priv->display_servers) == 1 &&
844 g_list_nth_data (priv->display_servers, 0) == display_server)
845 {
846 l_debug (seat, "Stopping; failed to start a greeter");
847 seat_stop (seat);
848 }
849 /* If we were the active session, switch to a greeter */
850 else if (!IS_GREETER_SESSION (session) && session == seat_get_active_session (seat))
851 {
852 l_debug (seat, "Active session stopped, starting greeter");
853 if (!seat_switch_to_greeter (seat))
854 {
855 l_debug (seat, "Stopping; failed to start a greeter");
856 seat_stop (seat);
857 }
858 }
859
860 g_signal_emit (seat, signals[SESSION_REMOVED], 0, session);
861 g_object_unref (session);
862
863 /* Stop the display server if no-longer required */
864 if (display_server && !display_server_get_is_stopping (display_server) &&
865 !SEAT_GET_CLASS (seat)->display_server_is_used (seat, display_server))
866 {
867 l_debug (seat, "Stopping display server, no sessions require it");
868 display_server_stop (display_server);
869 }
870 }
871
872 static void
set_session_env(Session * session)873 set_session_env (Session *session)
874 {
875 /* Connect using the session bus */
876 if (getuid () != 0)
877 {
878 if (g_getenv ("DBUS_SESSION_BUS_ADDRESS"))
879 session_set_env (session, "DBUS_SESSION_BUS_ADDRESS", g_getenv ("DBUS_SESSION_BUS_ADDRESS"));
880 session_set_env (session, "LDM_BUS", "SESSION");
881 }
882
883 /* Variables required for regression tests */
884 if (g_getenv ("LIGHTDM_TEST_ROOT"))
885 {
886 session_set_env (session, "LIGHTDM_TEST_ROOT", g_getenv ("LIGHTDM_TEST_ROOT"));
887 session_set_env (session, "DBUS_SYSTEM_BUS_ADDRESS", g_getenv ("DBUS_SYSTEM_BUS_ADDRESS"));
888 session_set_env (session, "DBUS_SESSION_BUS_ADDRESS", g_getenv ("DBUS_SESSION_BUS_ADDRESS"));
889 session_set_env (session, "GI_TYPELIB_PATH", g_getenv ("GI_TYPELIB_PATH"));
890 }
891
892 if (g_getenv ("LD_PRELOAD"))
893 session_set_env (session, "LD_PRELOAD", g_getenv ("LD_PRELOAD"));
894 if (g_getenv ("LD_LIBRARY_PATH"))
895 session_set_env (session, "LD_LIBRARY_PATH", g_getenv ("LD_LIBRARY_PATH"));
896 }
897
898 static Session *
create_session(Seat * seat,gboolean autostart)899 create_session (Seat *seat, gboolean autostart)
900 {
901 SeatPrivate *priv = seat_get_instance_private (seat);
902
903 Session *session = SEAT_GET_CLASS (seat)->create_session (seat);
904 priv->sessions = g_list_append (priv->sessions, session);
905 if (autostart)
906 g_signal_connect (session, SESSION_SIGNAL_AUTHENTICATION_COMPLETE, G_CALLBACK (session_authentication_complete_cb), seat);
907 g_signal_connect (session, SESSION_SIGNAL_STOPPED, G_CALLBACK (session_stopped_cb), seat);
908
909 set_session_env (session);
910
911 g_signal_emit (seat, signals[SESSION_ADDED], 0, session);
912
913 return session;
914 }
915
916 static gchar **
get_session_argv(Seat * seat,SessionConfig * session_config,const gchar * session_wrapper)917 get_session_argv (Seat *seat, SessionConfig *session_config, const gchar *session_wrapper)
918 {
919 /* If configured, run sessions through a wrapper */
920 if (session_wrapper)
921 {
922 gchar **argv = g_malloc (sizeof (gchar *) * 3);
923 g_autofree gchar *path = g_find_program_in_path (session_wrapper);
924 argv[0] = path ? g_steal_pointer (&path) : g_strdup (session_wrapper);
925 argv[1] = g_strdup (session_config_get_command (session_config));
926 argv[2] = NULL;
927 return argv;
928 }
929
930 /* Split command into an array listing and make command absolute */
931 int argc;
932 g_auto(GStrv) argv = NULL;
933 g_autoptr(GError) error = NULL;
934 gboolean result = g_shell_parse_argv (session_config_get_command (session_config), &argc, &argv, &error);
935 if (error)
936 l_debug (seat, "Invalid session command '%s': %s", session_config_get_command (session_config), error->message);
937 if (!result)
938 return NULL;
939 g_autofree gchar *path = g_find_program_in_path (argv[0]);
940 if (path)
941 {
942 g_free (argv[0]);
943 argv[0] = g_steal_pointer (&path);
944 }
945
946 return g_steal_pointer (&argv);
947 }
948
949 static SessionConfig *
find_session_config(Seat * seat,const gchar * sessions_dir,const gchar * session_name)950 find_session_config (Seat *seat, const gchar *sessions_dir, const gchar *session_name)
951 {
952 g_return_val_if_fail (sessions_dir != NULL, NULL);
953 g_return_val_if_fail (session_name != NULL, NULL);
954
955 g_auto(GStrv) dirs = g_strsplit (sessions_dir, ":", -1);
956 for (int i = 0; dirs[i]; i++)
957 {
958 const gchar *default_session_type = "x";
959 if (strcmp (dirs[i], WAYLAND_SESSIONS_DIR) == 0)
960 default_session_type = "wayland";
961
962 g_autofree gchar *filename = g_strdup_printf ("%s.desktop", session_name);
963 g_autofree gchar *path = g_build_filename (dirs[i], filename, NULL);
964 g_autoptr(GError) error = NULL;
965 SessionConfig *session_config = session_config_new_from_file (path, default_session_type, &error);
966 if (session_config)
967 return session_config;
968 }
969
970 l_debug (seat, "Failed to find session configuration %s", session_name);
971
972 return NULL;
973 }
974
975 static void
configure_session(Session * session,SessionConfig * config,const gchar * session_name,const gchar * language)976 configure_session (Session *session, SessionConfig *config, const gchar *session_name, const gchar *language)
977 {
978 session_set_config (session, config);
979 session_set_env (session, "XDG_SESSION_DESKTOP", session_name);
980 session_set_env (session, "DESKTOP_SESSION", session_name);
981 session_set_env (session, "GDMSESSION", session_name);
982 gchar **desktop_names = session_config_get_desktop_names (config);
983 if (desktop_names)
984 {
985 g_autofree gchar *value = g_strjoinv (":", desktop_names);
986 session_set_env (session, "XDG_CURRENT_DESKTOP", value);
987 }
988 if (language && language[0] != '\0')
989 {
990 session_set_env (session, "LANG", language);
991 session_set_env (session, "GDM_LANG", language);
992 }
993 }
994
995 static Session *
create_user_session(Seat * seat,const gchar * username,gboolean autostart)996 create_user_session (Seat *seat, const gchar *username, gboolean autostart)
997 {
998 l_debug (seat, "Creating user session");
999
1000 /* Load user preferences */
1001 g_autoptr(User) user = accounts_get_user_by_name (username);
1002 if (!user)
1003 {
1004 l_debug (seat, "Can't login unknown user '%s'", username);
1005 return NULL;
1006 }
1007 const gchar *session_name = user_get_xsession (user);
1008 const gchar *language = user_get_language (user);
1009
1010 /* Override session for autologin if configured */
1011 if (autostart)
1012 {
1013 const gchar *autologin_session_name = seat_get_string_property (seat, "autologin-session");
1014 if (autologin_session_name)
1015 session_name = autologin_session_name;
1016 }
1017
1018 if (!session_name)
1019 session_name = seat_get_string_property (seat, "user-session");
1020 g_autofree gchar *sessions_dir = config_get_string (config_get_instance (), "LightDM", "sessions-directory");
1021 g_autoptr(SessionConfig) session_config = find_session_config (seat, sessions_dir, session_name);
1022 if (!session_config)
1023 {
1024 l_debug (seat, "Can't find session '%s'", session_name);
1025 return NULL;
1026 }
1027
1028 g_autoptr(Session) session = create_session (seat, autostart);
1029 configure_session (session, session_config, session_name, language);
1030 session_set_username (session, username);
1031 session_set_do_authenticate (session, TRUE);
1032 g_auto(GStrv) argv = get_session_argv (seat, session_config, seat_get_string_property (seat, "session-wrapper"));
1033 session_set_argv (session, argv);
1034
1035 return g_steal_pointer (&session);
1036 }
1037
1038 static void
prepend_argv(gchar *** argv,const gchar * value)1039 prepend_argv (gchar ***argv, const gchar *value)
1040 {
1041 gchar **old_argv = *argv;
1042 gchar **new_argv = g_malloc (sizeof (gchar *) * (g_strv_length (*argv) + 2));
1043 new_argv[0] = g_strdup (value);
1044 gint i;
1045 for (i = 0; old_argv[i]; i++)
1046 new_argv[i + 1] = old_argv[i];
1047 new_argv[i + 1] = NULL;
1048
1049 g_free (*argv);
1050 *argv = new_argv;
1051 }
1052
1053 static Session *
create_guest_session(Seat * seat,const gchar * session_name)1054 create_guest_session (Seat *seat, const gchar *session_name)
1055 {
1056 if (!session_name)
1057 session_name = seat_get_string_property (seat, "guest-session");
1058 if (!session_name)
1059 session_name = seat_get_string_property (seat, "user-session");
1060 g_autofree gchar *sessions_dir = config_get_string (config_get_instance (), "LightDM", "sessions-directory");
1061 g_autoptr(SessionConfig) session_config = find_session_config (seat, sessions_dir, session_name);
1062 if (!session_config)
1063 {
1064 l_debug (seat, "Can't find session '%s'", session_name);
1065 return NULL;
1066 }
1067
1068 g_autoptr(Session) session = create_session (seat, TRUE);
1069 configure_session (session, session_config, session_name, NULL);
1070 session_set_do_authenticate (session, TRUE);
1071 session_set_is_guest (session, TRUE);
1072 g_auto(GStrv) argv = get_session_argv (seat, session_config, seat_get_string_property (seat, "session-wrapper"));
1073 const gchar *guest_wrapper = seat_get_string_property (seat, "guest-wrapper");
1074 if (guest_wrapper)
1075 {
1076 g_autofree gchar *path = g_find_program_in_path (guest_wrapper);
1077 prepend_argv (&argv, path ? path : guest_wrapper);
1078 }
1079
1080 session_set_argv (session, argv);
1081
1082 return g_steal_pointer (&session);
1083 }
1084
1085 // FIXME: This is inefficient and we already know the greeter session when we set the callbacks...
1086 static Session *
get_greeter_session(Seat * seat,Greeter * greeter)1087 get_greeter_session (Seat *seat, Greeter *greeter)
1088 {
1089 SeatPrivate *priv = seat_get_instance_private (seat);
1090
1091 /* Stop any greeters */
1092 for (GList *link = priv->sessions; link; link = link->next)
1093 {
1094 Session *session = link->data;
1095
1096 if (IS_GREETER_SESSION (session) && greeter_session_get_greeter (GREETER_SESSION (session)))
1097 return session;
1098 }
1099
1100 return NULL;
1101 }
1102
1103 static Session *
greeter_create_session_cb(Greeter * greeter,Seat * seat)1104 greeter_create_session_cb (Greeter *greeter, Seat *seat)
1105 {
1106 Session *greeter_session, *session;
1107
1108 greeter_session = get_greeter_session (seat, greeter);
1109 session = create_session (seat, FALSE);
1110 session_set_config (session, session_get_config (greeter_session));
1111 session_set_display_server (session, session_get_display_server (greeter_session));
1112
1113 return g_object_ref (session);
1114 }
1115
1116 static gboolean
greeter_start_session_cb(Greeter * greeter,SessionType type,const gchar * session_name,Seat * seat)1117 greeter_start_session_cb (Greeter *greeter, SessionType type, const gchar *session_name, Seat *seat)
1118 {
1119 SeatPrivate *priv = seat_get_instance_private (seat);
1120
1121 /* Get the session to use */
1122 Session *session;
1123 if (greeter_get_guest_authenticated (greeter))
1124 {
1125 session = g_object_ref (create_guest_session (seat, session_name));
1126 if (!session)
1127 return FALSE;
1128 session_set_pam_service (session, seat_get_string_property (seat, "pam-autologin-service"));
1129 }
1130 else
1131 {
1132 session = greeter_take_authentication_session (greeter);
1133
1134 /* Get session command to run */
1135 g_autofree gchar *sessions_dir = NULL;
1136 switch (type)
1137 {
1138 case SESSION_TYPE_LOCAL:
1139 sessions_dir = config_get_string (config_get_instance (), "LightDM", "sessions-directory");
1140 break;
1141 case SESSION_TYPE_REMOTE:
1142 sessions_dir = config_get_string (config_get_instance (), "LightDM", "remote-sessions-directory");
1143 break;
1144 }
1145
1146 /* Load user preferences */
1147 const gchar *language = NULL;
1148 User *user = session_get_user (session);
1149 if (user)
1150 {
1151 const gchar *autologin_username;
1152
1153 /* Override session for autologin if configured */
1154 autologin_username = seat_get_string_property (seat, "autologin-user");
1155 if (!session_name && g_strcmp0 (user_get_name (user), autologin_username) == 0)
1156 session_name = seat_get_string_property (seat, "autologin-session");
1157
1158 if (!session_name)
1159 session_name = user_get_xsession (user);
1160 language = user_get_language (user);
1161 }
1162
1163 if (!session_name)
1164 session_name = seat_get_string_property (seat, "user-session");
1165 if (user)
1166 user_set_xsession (session_get_user (session), session_name);
1167
1168 g_autoptr(SessionConfig) session_config = find_session_config (seat, sessions_dir, session_name);
1169 if (!session_config)
1170 {
1171 l_debug (seat, "Can't find session '%s'", session_name);
1172 return FALSE;
1173 }
1174
1175 configure_session (session, session_config, session_name, language);
1176 g_auto(GStrv) argv = get_session_argv (seat, session_config, seat_get_string_property (seat, "session-wrapper"));
1177 session_set_argv (session, argv);
1178 }
1179
1180 /* Switch to this session when it is ready */
1181 g_clear_object (&priv->session_to_activate);
1182 priv->session_to_activate = session;
1183
1184 /* Return to existing session if it is open */
1185 const gchar *username = session_get_username (session);
1186 Session *existing_session = find_user_session (seat, username, NULL);
1187 if (existing_session && session != existing_session)
1188 {
1189 l_debug (seat, "Returning to existing user session %s", username);
1190 session_stop (session);
1191 session_unlock (existing_session);
1192 seat_set_active_session (seat, existing_session);
1193 return TRUE;
1194 }
1195
1196 /* If can re-use the display server, stop the greeter first */
1197 Session *greeter_session = get_greeter_session (seat, greeter);
1198 if (greeter_session)
1199 {
1200 DisplayServer *display_server = session_get_display_server (greeter_session);
1201 if (display_server &&
1202 !greeter_get_resettable (greeter) &&
1203 can_share_display_server (seat, display_server) &&
1204 strcmp (display_server_get_session_type (display_server), session_get_session_type (session)) == 0)
1205 {
1206 l_debug (seat, "Stopping greeter; display server will be re-used for user session");
1207
1208 /* Run on the same display server after the greeter has stopped */
1209 session_set_display_server (session, display_server);
1210
1211 /* Stop the greeter */
1212 session_stop (greeter_session);
1213
1214 return TRUE;
1215 }
1216 }
1217
1218 /* Otherwise start a new display server for this session */
1219 DisplayServer *display_server = create_display_server (seat, session);
1220 session_set_display_server (session, display_server);
1221 if (!start_display_server (seat, display_server))
1222 {
1223 l_debug (seat, "Failed to start display server for new session");
1224 return FALSE;
1225 }
1226
1227 return TRUE;
1228 }
1229
1230 static GreeterSession *
create_greeter_session(Seat * seat)1231 create_greeter_session (Seat *seat)
1232 {
1233 SeatPrivate *priv = seat_get_instance_private (seat);
1234
1235 l_debug (seat, "Creating greeter session");
1236
1237 g_autofree gchar *sessions_dir = config_get_string (config_get_instance (), "LightDM", "greeters-directory");
1238 g_autoptr(SessionConfig) session_config = find_session_config (seat, sessions_dir, seat_get_string_property (seat, "greeter-session"));
1239 if (!session_config)
1240 return NULL;
1241
1242 g_auto(GStrv) argv = get_session_argv (seat, session_config, NULL);
1243 const gchar *greeter_wrapper = seat_get_string_property (seat, "greeter-wrapper");
1244 if (greeter_wrapper)
1245 {
1246 g_autofree gchar *path = g_find_program_in_path (greeter_wrapper);
1247 prepend_argv (&argv, path ? path : greeter_wrapper);
1248 }
1249
1250 GreeterSession *greeter_session = SEAT_GET_CLASS (seat)->create_greeter_session (seat);
1251 Greeter *greeter = greeter_session_get_greeter (greeter_session);
1252 session_set_config (SESSION (greeter_session), session_config);
1253 priv->sessions = g_list_append (priv->sessions, SESSION (greeter_session));
1254 g_signal_connect (greeter, GREETER_SIGNAL_ACTIVE_USERNAME_CHANGED, G_CALLBACK (greeter_active_username_changed_cb), seat);
1255 g_signal_connect (greeter_session, SESSION_SIGNAL_AUTHENTICATION_COMPLETE, G_CALLBACK (session_authentication_complete_cb), seat);
1256 g_signal_connect (greeter_session, SESSION_SIGNAL_STOPPED, G_CALLBACK (session_stopped_cb), seat);
1257
1258 set_session_env (SESSION (greeter_session));
1259 session_set_env (SESSION (greeter_session), "XDG_SESSION_CLASS", "greeter");
1260
1261 session_set_pam_service (SESSION (greeter_session), seat_get_string_property (seat, "pam-greeter-service"));
1262 if (getuid () == 0)
1263 {
1264 g_autofree gchar *greeter_user = config_get_string (config_get_instance (), "LightDM", "greeter-user");
1265 session_set_username (SESSION (greeter_session), greeter_user);
1266 }
1267 else
1268 {
1269 /* In test mode run the greeter as ourself */
1270 session_set_username (SESSION (greeter_session), user_get_name (accounts_get_current_user ()));
1271 }
1272 session_set_argv (SESSION (greeter_session), argv);
1273
1274 greeter_set_pam_services (greeter,
1275 seat_get_string_property (seat, "pam-service"),
1276 seat_get_string_property (seat, "pam-autologin-service"));
1277 g_signal_connect (greeter, GREETER_SIGNAL_CREATE_SESSION, G_CALLBACK (greeter_create_session_cb), seat);
1278 g_signal_connect (greeter, GREETER_SIGNAL_START_SESSION, G_CALLBACK (greeter_start_session_cb), seat);
1279
1280 /* Set hints to greeter */
1281 greeter_set_allow_guest (greeter, seat_get_allow_guest (seat));
1282 set_greeter_hints (seat, greeter);
1283
1284 /* Configure for automatic login */
1285 const gchar *autologin_username = seat_get_string_property (seat, "autologin-user");
1286 if (g_strcmp0 (autologin_username, "") == 0)
1287 autologin_username = NULL;
1288 const gchar *autologin_session = seat_get_string_property (seat, "autologin-session");
1289 if (g_strcmp0 (autologin_session, "") == 0)
1290 autologin_session = NULL;
1291 int autologin_timeout = seat_get_integer_property (seat, "autologin-user-timeout");
1292 gboolean autologin_guest = seat_get_boolean_property (seat, "autologin-guest");
1293 if (autologin_timeout > 0)
1294 {
1295 g_autofree gchar *value = g_strdup_printf ("%d", autologin_timeout);
1296 greeter_set_hint (greeter, "autologin-timeout", value);
1297 if (autologin_username)
1298 greeter_set_hint (greeter, "autologin-user", autologin_username);
1299 if (autologin_session)
1300 greeter_set_hint (greeter, "autologin-session", autologin_session);
1301 if (autologin_guest)
1302 greeter_set_hint (greeter, "autologin-guest", "true");
1303 }
1304
1305 return greeter_session;
1306 }
1307
1308 static Session *
find_session_for_display_server(Seat * seat,DisplayServer * display_server)1309 find_session_for_display_server (Seat *seat, DisplayServer *display_server)
1310 {
1311 SeatPrivate *priv = seat_get_instance_private (seat);
1312
1313 for (GList *link = priv->sessions; link; link = link->next)
1314 {
1315 Session *session = link->data;
1316
1317 if (session_get_display_server (session) == display_server &&
1318 !session_get_is_stopping (session) &&
1319 !session_get_is_run (session))
1320 return session;
1321 }
1322
1323 return NULL;
1324 }
1325
1326 static void
display_server_ready_cb(DisplayServer * display_server,Seat * seat)1327 display_server_ready_cb (DisplayServer *display_server, Seat *seat)
1328 {
1329 /* Run setup script */
1330 const gchar *script = seat_get_string_property (seat, "display-setup-script");
1331 if (script && !run_script (seat, display_server, script, NULL))
1332 {
1333 l_debug (seat, "Stopping display server due to failed setup script");
1334 display_server_stop (display_server);
1335 return;
1336 }
1337
1338 emit_upstart_signal ("login-session-start");
1339
1340 /* Start the session waiting for this display server */
1341 Session *session = find_session_for_display_server (seat, display_server);
1342 if (session)
1343 {
1344 if (session_get_is_authenticated (session))
1345 {
1346 l_debug (seat, "Display server ready, running session");
1347 run_session (seat, session);
1348 }
1349 else
1350 {
1351 l_debug (seat, "Display server ready, starting session authentication");
1352 start_session (seat, session);
1353 }
1354 }
1355 else
1356 {
1357 l_debug (seat, "Stopping not required display server");
1358 display_server_stop (display_server);
1359 }
1360 }
1361
1362 static DisplayServer *
create_display_server(Seat * seat,Session * session)1363 create_display_server (Seat *seat, Session *session)
1364 {
1365 SeatPrivate *priv = seat_get_instance_private (seat);
1366
1367 l_debug (seat, "Creating display server of type %s", session_get_session_type (session));
1368
1369 DisplayServer *display_server = SEAT_GET_CLASS (seat)->create_display_server (seat, session);
1370 if (!display_server)
1371 return NULL;
1372
1373 /* Remember this display server */
1374 if (!g_list_find (priv->display_servers, display_server))
1375 {
1376 priv->display_servers = g_list_append (priv->display_servers, display_server);
1377 g_signal_connect (display_server, DISPLAY_SERVER_SIGNAL_READY, G_CALLBACK (display_server_ready_cb), seat);
1378 g_signal_connect (display_server, DISPLAY_SERVER_SIGNAL_STOPPED, G_CALLBACK (display_server_stopped_cb), seat);
1379 }
1380
1381 return display_server;
1382 }
1383
1384 static gboolean
start_display_server(Seat * seat,DisplayServer * display_server)1385 start_display_server (Seat *seat, DisplayServer *display_server)
1386 {
1387 if (display_server_get_is_ready (display_server))
1388 {
1389 display_server_ready_cb (display_server, seat);
1390 return TRUE;
1391 }
1392 else
1393 return display_server_start (display_server);
1394 }
1395
1396 gboolean
seat_switch_to_greeter(Seat * seat)1397 seat_switch_to_greeter (Seat *seat)
1398 {
1399 SeatPrivate *priv = seat_get_instance_private (seat);
1400
1401 g_return_val_if_fail (seat != NULL, FALSE);
1402
1403 if (!seat_get_can_switch (seat) && priv->sessions != NULL)
1404 return FALSE;
1405
1406 /* Switch to greeter if one open */
1407 GreeterSession *greeter_session = find_greeter_session (seat);
1408 if (greeter_session)
1409 {
1410 l_debug (seat, "Switching to existing greeter");
1411 seat_set_active_session (seat, SESSION (greeter_session));
1412 return TRUE;
1413 }
1414
1415 greeter_session = create_greeter_session (seat);
1416 if (!greeter_session)
1417 return FALSE;
1418
1419 g_clear_object (&priv->session_to_activate);
1420 priv->session_to_activate = g_object_ref (SESSION (greeter_session));
1421
1422 DisplayServer *display_server = create_display_server (seat, SESSION (greeter_session));
1423 if (!display_server) {
1424 g_clear_object (&priv->session_to_activate);
1425 return FALSE;
1426 }
1427 session_set_display_server (SESSION (greeter_session), display_server);
1428
1429 return start_display_server (seat, display_server);
1430 }
1431
1432 static void
switch_authentication_complete_cb(Session * session,Seat * seat)1433 switch_authentication_complete_cb (Session *session, Seat *seat)
1434 {
1435 SeatPrivate *priv = seat_get_instance_private (seat);
1436
1437 /* If authenticated, then unlock existing session or start new one */
1438 if (session_get_is_authenticated (session))
1439 {
1440 Session *s = find_user_session (seat, session_get_username (session), session);
1441 if (s)
1442 {
1443 l_debug (seat, "Session authenticated, switching to existing user session");
1444 session_unlock (s);
1445 seat_set_active_session (seat, s);
1446 session_stop (session);
1447 }
1448 else
1449 {
1450 l_debug (seat, "Session authenticated, starting display server");
1451 g_clear_object (&priv->session_to_activate);
1452 priv->session_to_activate = g_object_ref (session);
1453 DisplayServer *display_server = create_display_server (seat, session);
1454 session_set_display_server (session, display_server);
1455 start_display_server (seat, display_server);
1456 }
1457
1458 return;
1459 }
1460
1461 session_stop (session);
1462
1463 /* See if we already have a greeter up and reuse it if so */
1464 GreeterSession *greeter_session = find_resettable_greeter (seat);
1465 gboolean existing = FALSE;
1466 if (greeter_session)
1467 {
1468 l_debug (seat, "Switching to existing greeter to authenticate session");
1469 set_greeter_hints (seat, greeter_session_get_greeter (greeter_session));
1470 existing = TRUE;
1471 }
1472 else
1473 {
1474 l_debug (seat, "Starting greeter to authenticate session");
1475 greeter_session = create_greeter_session (seat);
1476 }
1477 Greeter *greeter = greeter_session_get_greeter (greeter_session);
1478
1479 if (session_get_is_guest (session))
1480 greeter_set_hint (greeter, "select-guest", "true");
1481 else
1482 greeter_set_hint (greeter, "select-user", session_get_username (session));
1483
1484 if (existing)
1485 {
1486 greeter_reset (greeter);
1487 seat_set_active_session (seat, SESSION (greeter_session));
1488 }
1489 else
1490 {
1491 g_clear_object (&priv->session_to_activate);
1492 priv->session_to_activate = g_object_ref (SESSION (greeter_session));
1493
1494 DisplayServer *display_server = create_display_server (seat, SESSION (greeter_session));
1495 session_set_display_server (SESSION (greeter_session), display_server);
1496 start_display_server (seat, display_server);
1497 }
1498 }
1499
1500 gboolean
seat_switch_to_user(Seat * seat,const gchar * username,const gchar * session_name)1501 seat_switch_to_user (Seat *seat, const gchar *username, const gchar *session_name)
1502 {
1503 SeatPrivate *priv = seat_get_instance_private (seat);
1504
1505 g_return_val_if_fail (seat != NULL, FALSE);
1506 g_return_val_if_fail (username != NULL, FALSE);
1507
1508 if (!seat_get_can_switch (seat))
1509 return FALSE;
1510
1511 /* If we're already on this session, then ignore */
1512 Session *session = find_user_session (seat, username, NULL);
1513 if (session && session == priv->active_session)
1514 return TRUE;
1515
1516 l_debug (seat, "Switching to user %s", username);
1517
1518 /* Attempt to authenticate them */
1519 session = create_user_session (seat, username, FALSE);
1520 g_signal_connect (session, SESSION_SIGNAL_AUTHENTICATION_COMPLETE, G_CALLBACK (switch_authentication_complete_cb), seat);
1521 session_set_pam_service (session, seat_get_string_property (seat, "pam-service"));
1522
1523 return session_start (session);
1524 }
1525
1526 static Session *
find_guest_session(Seat * seat)1527 find_guest_session (Seat *seat)
1528 {
1529 SeatPrivate *priv = seat_get_instance_private (seat);
1530
1531 for (GList *link = priv->sessions; link; link = link->next)
1532 {
1533 Session *session = link->data;
1534 if (!session_get_is_stopping (session) && session_get_is_guest (session))
1535 return session;
1536 }
1537
1538 return NULL;
1539 }
1540
1541 gboolean
seat_switch_to_guest(Seat * seat,const gchar * session_name)1542 seat_switch_to_guest (Seat *seat, const gchar *session_name)
1543 {
1544 SeatPrivate *priv = seat_get_instance_private (seat);
1545
1546 g_return_val_if_fail (seat != NULL, FALSE);
1547
1548 if (!seat_get_can_switch (seat) || !seat_get_allow_guest (seat))
1549 return FALSE;
1550
1551 /* Switch to session if one open */
1552 Session *session = find_guest_session (seat);
1553 if (session)
1554 {
1555 l_debug (seat, "Switching to existing guest account %s", session_get_username (session));
1556 seat_set_active_session (seat, session);
1557 return TRUE;
1558 }
1559
1560 session = create_guest_session (seat, session_name);
1561 if (!session)
1562 return FALSE;
1563
1564 DisplayServer *display_server = create_display_server (seat, session);
1565
1566 g_clear_object (&priv->session_to_activate);
1567 priv->session_to_activate = g_object_ref (session);
1568 session_set_pam_service (session, seat_get_string_property (seat, "pam-autologin-service"));
1569 session_set_display_server (session, display_server);
1570
1571 return start_display_server (seat, display_server);
1572 }
1573
1574 gboolean
seat_lock(Seat * seat,const gchar * username)1575 seat_lock (Seat *seat, const gchar *username)
1576 {
1577 SeatPrivate *priv = seat_get_instance_private (seat);
1578
1579 g_return_val_if_fail (seat != NULL, FALSE);
1580
1581 if (!seat_get_can_switch (seat))
1582 return FALSE;
1583
1584 // FIXME: If already locked then don't bother...
1585
1586 l_debug (seat, "Locking");
1587
1588 /* Switch to greeter we can reuse */
1589 gboolean reset_existing = FALSE;
1590 gboolean reuse_xserver = FALSE;
1591 DisplayServer *display_server = NULL;
1592 GreeterSession *greeter_session = find_resettable_greeter (seat);
1593 if (greeter_session)
1594 {
1595 l_debug (seat, "Switching to existing greeter");
1596 set_greeter_hints (seat, greeter_session_get_greeter (greeter_session));
1597 reset_existing = TRUE;
1598 }
1599 else
1600 {
1601 /* If the existing greeter can't be reused, stop it and reuse its display server */
1602 greeter_session = find_greeter_session (seat);
1603 if (greeter_session)
1604 {
1605 display_server = session_get_display_server (SESSION (greeter_session));
1606 if (!session_get_is_stopping (SESSION (greeter_session)))
1607 {
1608 l_debug (seat, "Stopping session");
1609 session_stop (SESSION (greeter_session));
1610 }
1611 reuse_xserver = TRUE;
1612 }
1613
1614 greeter_session = create_greeter_session (seat);
1615 if (!greeter_session)
1616 return FALSE;
1617 }
1618 Greeter *greeter = greeter_session_get_greeter (greeter_session);
1619
1620 greeter_set_hint (greeter, "lock-screen", "true");
1621 if (username)
1622 greeter_set_hint (greeter, "select-user", username);
1623
1624 if (reset_existing)
1625 {
1626 greeter_reset (greeter);
1627 seat_set_active_session (seat, SESSION (greeter_session));
1628 return TRUE;
1629 }
1630 else
1631 {
1632 if (!reuse_xserver)
1633 display_server = create_display_server (seat, SESSION (greeter_session));
1634 session_set_display_server (SESSION (greeter_session), display_server);
1635
1636 g_clear_object (&priv->session_to_activate);
1637 priv->session_to_activate = g_object_ref (SESSION (greeter_session));
1638
1639 if (reuse_xserver)
1640 {
1641 g_clear_object (&priv->replacement_greeter);
1642 priv->replacement_greeter = g_object_ref (greeter_session);
1643 return TRUE;
1644 }
1645 else
1646 return start_display_server (seat, display_server);
1647 }
1648 }
1649
1650 void
seat_stop(Seat * seat)1651 seat_stop (Seat *seat)
1652 {
1653 SeatPrivate *priv = seat_get_instance_private (seat);
1654
1655 g_return_if_fail (seat != NULL);
1656
1657 if (priv->stopping)
1658 return;
1659
1660 l_debug (seat, "Stopping");
1661 priv->stopping = TRUE;
1662 SEAT_GET_CLASS (seat)->stop (seat);
1663 }
1664
1665 gboolean
seat_get_is_stopping(Seat * seat)1666 seat_get_is_stopping (Seat *seat)
1667 {
1668 SeatPrivate *priv = seat_get_instance_private (seat);
1669 g_return_val_if_fail (seat != NULL, FALSE);
1670 return priv->stopping;
1671 }
1672
1673 static void
seat_real_setup(Seat * seat)1674 seat_real_setup (Seat *seat)
1675 {
1676 }
1677
1678 static gboolean
seat_real_start(Seat * seat)1679 seat_real_start (Seat *seat)
1680 {
1681 SeatPrivate *priv = seat_get_instance_private (seat);
1682
1683 /* Get autologin settings */
1684 const gchar *autologin_username = seat_get_string_property (seat, "autologin-user");
1685 if (g_strcmp0 (autologin_username, "") == 0)
1686 autologin_username = NULL;
1687 int autologin_timeout = seat_get_integer_property (seat, "autologin-user-timeout");
1688 gboolean autologin_guest = seat_get_boolean_property (seat, "autologin-guest");
1689 gboolean autologin_in_background = seat_get_boolean_property (seat, "autologin-in-background");
1690
1691 /* Autologin if configured */
1692 Session *session = NULL, *background_session = NULL;
1693 if (autologin_timeout == 0 || autologin_in_background)
1694 {
1695 if (autologin_guest)
1696 session = create_guest_session (seat, NULL);
1697 else if (autologin_username != NULL)
1698 session = create_user_session (seat, autologin_username, TRUE);
1699
1700 if (session)
1701 session_set_pam_service (session, seat_get_string_property (seat, "pam-autologin-service"));
1702
1703 /* Load in background if required */
1704 if (autologin_in_background && session)
1705 {
1706 background_session = session;
1707 session = NULL;
1708 }
1709
1710 if (session)
1711 {
1712 g_clear_object (&priv->session_to_activate);
1713 priv->session_to_activate = g_object_ref (session);
1714
1715 DisplayServer *display_server = create_display_server (seat, session);
1716 session_set_display_server (session, display_server);
1717 if (!display_server || !start_display_server (seat, display_server))
1718 {
1719 l_debug (seat, "Can't create display server for automatic login");
1720 session_stop (session);
1721 if (display_server)
1722 display_server_stop (display_server);
1723 session = NULL;
1724 }
1725 }
1726 }
1727
1728 /* Fallback to a greeter */
1729 if (!session)
1730 {
1731 GreeterSession *greeter_session = create_greeter_session (seat);
1732 if (!greeter_session)
1733 {
1734 l_debug (seat, "Failed to create greeter session");
1735 return FALSE;
1736 }
1737
1738 g_clear_object (&priv->session_to_activate);
1739 session = SESSION (greeter_session);
1740 priv->session_to_activate = g_object_ref (session);
1741
1742 DisplayServer *display_server = create_display_server (seat, session);
1743 session_set_display_server (session, display_server);
1744 if (!display_server || !start_display_server (seat, display_server))
1745 {
1746 l_debug (seat, "Can't create display server for greeter");
1747 session_stop (session);
1748 if (display_server)
1749 display_server_stop (display_server);
1750 session = NULL;
1751 }
1752 }
1753
1754 /* Fail if can't start a session */
1755 if (!session)
1756 {
1757 seat_stop (seat);
1758 return FALSE;
1759 }
1760
1761 /* Start background session */
1762 if (background_session)
1763 {
1764 DisplayServer *background_display_server = create_display_server (seat, background_session);
1765 session_set_display_server (background_session, background_display_server);
1766 if (!start_display_server (seat, background_display_server))
1767 l_warning (seat, "Failed to start display server for background session");
1768 }
1769
1770 return TRUE;
1771 }
1772
1773 static DisplayServer *
seat_real_create_display_server(Seat * seat,Session * session)1774 seat_real_create_display_server (Seat *seat, Session *session)
1775 {
1776 return NULL;
1777 }
1778
1779 static gboolean
seat_real_display_server_is_used(Seat * seat,DisplayServer * display_server)1780 seat_real_display_server_is_used (Seat *seat, DisplayServer *display_server)
1781 {
1782 SeatPrivate *priv = seat_get_instance_private (seat);
1783
1784 for (GList *link = priv->sessions; link; link = link->next)
1785 {
1786 Session *session = link->data;
1787
1788 DisplayServer *d = session_get_display_server (session);
1789 if (!d)
1790 continue;
1791
1792 if (d == display_server || display_server_get_parent (d) == display_server)
1793 return TRUE;
1794 }
1795
1796 return FALSE;
1797 }
1798
1799 static GreeterSession *
seat_real_create_greeter_session(Seat * seat)1800 seat_real_create_greeter_session (Seat *seat)
1801 {
1802 return greeter_session_new ();
1803 }
1804
1805 static Session *
create_session_cb(Greeter * greeter,Seat * seat)1806 create_session_cb (Greeter *greeter, Seat *seat)
1807 {
1808 return g_object_ref (create_session (seat, FALSE));
1809 }
1810
1811 static Greeter *
create_greeter_cb(Session * session,Seat * seat)1812 create_greeter_cb (Session *session, Seat *seat)
1813 {
1814 g_autoptr(Greeter) greeter = greeter_new ();
1815
1816 greeter_set_pam_services (greeter,
1817 seat_get_string_property (seat, "pam-service"),
1818 seat_get_string_property (seat, "pam-autologin-service"));
1819 g_signal_connect (greeter, GREETER_SIGNAL_CREATE_SESSION, G_CALLBACK (create_session_cb), seat);
1820 g_signal_connect (greeter, GREETER_SIGNAL_START_SESSION, G_CALLBACK (greeter_start_session_cb), seat);
1821
1822 /* Set hints to greeter */
1823 greeter_set_allow_guest (greeter, seat_get_allow_guest (seat));
1824 set_greeter_hints (seat, greeter);
1825
1826 return g_steal_pointer (&greeter);
1827 }
1828
1829 static Session *
seat_real_create_session(Seat * seat)1830 seat_real_create_session (Seat *seat)
1831 {
1832 g_autoptr(Session) session = session_new ();
1833 g_signal_connect (session, SESSION_SIGNAL_CREATE_GREETER, G_CALLBACK (create_greeter_cb), seat);
1834
1835 return g_steal_pointer (&session);
1836 }
1837
1838 static void
seat_real_set_active_session(Seat * seat,Session * session)1839 seat_real_set_active_session (Seat *seat, Session *session)
1840 {
1841 }
1842
1843 static void
seat_real_set_next_session(Seat * seat,Session * session)1844 seat_real_set_next_session (Seat *seat, Session *session)
1845 {
1846 }
1847
1848 static Session *
seat_real_get_active_session(Seat * seat)1849 seat_real_get_active_session (Seat *seat)
1850 {
1851 return NULL;
1852 }
1853
1854 static void
seat_real_stop(Seat * seat)1855 seat_real_stop (Seat *seat)
1856 {
1857 SeatPrivate *priv = seat_get_instance_private (seat);
1858
1859 check_stopped (seat);
1860 if (priv->stopped)
1861 return;
1862
1863 /* Stop all the display servers and sessions on the seat. Copy the list as
1864 * it might be modified if a display server / session stops during this loop */
1865 GList *list = g_list_copy (priv->display_servers);
1866 for (GList *link = list; link; link = link->next)
1867 g_object_ref (link->data);
1868 for (GList *link = list; link; link = link->next)
1869 {
1870 DisplayServer *display_server = link->data;
1871 if (!display_server_get_is_stopping (display_server))
1872 {
1873 l_debug (seat, "Stopping display server");
1874 display_server_stop (display_server);
1875 }
1876 }
1877 g_list_free_full (list, g_object_unref);
1878 list = g_list_copy (priv->sessions);
1879 for (GList *link = list; link; link = link->next)
1880 g_object_ref (link->data);
1881 for (GList *link = list; link; link = link->next)
1882 {
1883 Session *session = link->data;
1884 if (!session_get_is_stopping (session))
1885 {
1886 l_debug (seat, "Stopping session");
1887 session_stop (session);
1888 }
1889 }
1890 g_list_free_full (list, g_object_unref);
1891 }
1892
1893 static void
seat_init(Seat * seat)1894 seat_init (Seat *seat)
1895 {
1896 SeatPrivate *priv = seat_get_instance_private (seat);
1897
1898 priv->properties = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
1899 priv->share_display_server = TRUE;
1900 }
1901
1902 static void
seat_finalize(GObject * object)1903 seat_finalize (GObject *object)
1904 {
1905 Seat *self = SEAT (object);
1906 SeatPrivate *priv = seat_get_instance_private (SEAT (self));
1907
1908 g_free (priv->name);
1909 g_hash_table_unref (priv->properties);
1910 for (GList *link = priv->display_servers; link; link = link->next)
1911 {
1912 DisplayServer *display_server = link->data;
1913 g_signal_handlers_disconnect_matched (display_server, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, self);
1914 }
1915 g_list_free_full (priv->display_servers, g_object_unref);
1916 for (GList *link = priv->sessions; link; link = link->next)
1917 {
1918 Session *session = link->data;
1919 g_signal_handlers_disconnect_matched (session, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, self);
1920 }
1921 g_list_free_full (priv->sessions, g_object_unref);
1922 g_clear_object (&priv->active_session);
1923 g_clear_object (&priv->next_session);
1924 g_clear_object (&priv->session_to_activate);
1925 g_clear_object (&priv->replacement_greeter);
1926
1927 G_OBJECT_CLASS (seat_parent_class)->finalize (object);
1928 }
1929
1930 static void
seat_class_init(SeatClass * klass)1931 seat_class_init (SeatClass *klass)
1932 {
1933 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1934
1935 klass->setup = seat_real_setup;
1936 klass->start = seat_real_start;
1937 klass->create_display_server = seat_real_create_display_server;
1938 klass->display_server_is_used = seat_real_display_server_is_used;
1939 klass->create_greeter_session = seat_real_create_greeter_session;
1940 klass->create_session = seat_real_create_session;
1941 klass->set_active_session = seat_real_set_active_session;
1942 klass->get_active_session = seat_real_get_active_session;
1943 klass->set_next_session = seat_real_set_next_session;
1944 klass->run_script = seat_real_run_script;
1945 klass->stop = seat_real_stop;
1946
1947 object_class->finalize = seat_finalize;
1948
1949 signals[SESSION_ADDED] =
1950 g_signal_new (SEAT_SIGNAL_SESSION_ADDED,
1951 G_TYPE_FROM_CLASS (klass),
1952 G_SIGNAL_RUN_LAST,
1953 G_STRUCT_OFFSET (SeatClass, session_added),
1954 NULL, NULL,
1955 NULL,
1956 G_TYPE_NONE, 1, SESSION_TYPE);
1957 signals[RUNNING_USER_SESSION] =
1958 g_signal_new (SEAT_SIGNAL_RUNNING_USER_SESSION,
1959 G_TYPE_FROM_CLASS (klass),
1960 G_SIGNAL_RUN_LAST,
1961 G_STRUCT_OFFSET (SeatClass, running_user_session),
1962 NULL, NULL,
1963 NULL,
1964 G_TYPE_NONE, 1, SESSION_TYPE);
1965 signals[SESSION_REMOVED] =
1966 g_signal_new (SEAT_SIGNAL_SESSION_REMOVED,
1967 G_TYPE_FROM_CLASS (klass),
1968 G_SIGNAL_RUN_LAST,
1969 G_STRUCT_OFFSET (SeatClass, session_removed),
1970 NULL, NULL,
1971 NULL,
1972 G_TYPE_NONE, 1, SESSION_TYPE);
1973 signals[STOPPED] =
1974 g_signal_new (SEAT_SIGNAL_STOPPED,
1975 G_TYPE_FROM_CLASS (klass),
1976 G_SIGNAL_RUN_LAST,
1977 G_STRUCT_OFFSET (SeatClass, stopped),
1978 NULL, NULL,
1979 NULL,
1980 G_TYPE_NONE, 0);
1981 }
1982
1983 static gint
seat_real_logprefix(Logger * self,gchar * buf,gulong buflen)1984 seat_real_logprefix (Logger *self, gchar *buf, gulong buflen)
1985 {
1986 return g_snprintf (buf, buflen, "Seat %s: ", seat_get_name (SEAT (self)));
1987 }
1988
1989 static void
seat_logger_iface_init(LoggerInterface * iface)1990 seat_logger_iface_init (LoggerInterface *iface)
1991 {
1992 iface->logprefix = &seat_real_logprefix;
1993 }
1994