1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2 *
3 * Copyright (C) 2008 Jon McCann <jmccann@redhat.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include "config.h"
20
21 #include <errno.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <unistd.h>
25 #include <sys/types.h>
26 #include <pwd.h>
27
28 #include <glib.h>
29 #include <glib-object.h>
30 #include <glib/gi18n.h>
31 #include <gio/gio.h>
32 #include <gio/gunixfdlist.h>
33
34 #include "gsm-system.h"
35 #include "gsm-consolekit.h"
36
37 #define CK_NAME "org.freedesktop.ConsoleKit"
38
39 #define CK_MANAGER_PATH "/org/freedesktop/ConsoleKit/Manager"
40 #define CK_MANAGER_INTERFACE CK_NAME ".Manager"
41 #define CK_SEAT_INTERFACE CK_NAME ".Seat"
42 #define CK_SESSION_INTERFACE CK_NAME ".Session"
43
44
45 struct _GsmConsolekitPrivate
46 {
47 GDBusProxy *ck_proxy;
48 GDBusProxy *ck_session_proxy;
49
50 char *session_id;
51 gchar *session_path;
52
53 const gchar *inhibit_locks;
54 gint inhibit_fd;
55
56 gboolean is_active;
57
58 gint delay_inhibit_fd;
59 gboolean prepare_for_shutdown_expected;
60 };
61
62 enum {
63 PROP_0,
64 PROP_ACTIVE
65 };
66
67 static void gsm_consolekit_system_init (GsmSystemInterface *iface);
68
G_DEFINE_TYPE_WITH_CODE(GsmConsolekit,gsm_consolekit,G_TYPE_OBJECT,G_IMPLEMENT_INTERFACE (GSM_TYPE_SYSTEM,gsm_consolekit_system_init))69 G_DEFINE_TYPE_WITH_CODE (GsmConsolekit, gsm_consolekit, G_TYPE_OBJECT,
70 G_IMPLEMENT_INTERFACE (GSM_TYPE_SYSTEM,
71 gsm_consolekit_system_init))
72
73 static void
74 drop_system_inhibitor (GsmConsolekit *manager)
75 {
76 if (manager->priv->inhibit_fd != -1) {
77 g_debug ("GsmConsolekit: Dropping system inhibitor fd %d", manager->priv->inhibit_fd);
78 close (manager->priv->inhibit_fd);
79 manager->priv->inhibit_fd = -1;
80 }
81 }
82
83 static void
drop_delay_inhibitor(GsmConsolekit * manager)84 drop_delay_inhibitor (GsmConsolekit *manager)
85 {
86 if (manager->priv->delay_inhibit_fd != -1) {
87 g_debug ("GsmConsolekit: Dropping delay inhibitor");
88 close (manager->priv->delay_inhibit_fd);
89 manager->priv->delay_inhibit_fd = -1;
90 }
91 }
92
93 static void
gsm_consolekit_finalize(GObject * object)94 gsm_consolekit_finalize (GObject *object)
95 {
96 GsmConsolekit *consolekit = GSM_CONSOLEKIT (object);
97
98 g_clear_object (&consolekit->priv->ck_proxy);
99 g_clear_object (&consolekit->priv->ck_session_proxy);
100 free (consolekit->priv->session_id);
101 g_free (consolekit->priv->session_path);
102
103 drop_system_inhibitor (consolekit);
104 drop_delay_inhibitor (consolekit);
105
106 G_OBJECT_CLASS (gsm_consolekit_parent_class)->finalize (object);
107 }
108
109 static void
gsm_consolekit_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)110 gsm_consolekit_set_property (GObject *object,
111 guint prop_id,
112 const GValue *value,
113 GParamSpec *pspec)
114 {
115 GsmConsolekit *self = GSM_CONSOLEKIT (object);
116
117 switch (prop_id) {
118 case PROP_ACTIVE:
119 self->priv->is_active = g_value_get_boolean (value);
120 break;
121 default:
122 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
123 }
124 }
125
126 static void
gsm_consolekit_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)127 gsm_consolekit_get_property (GObject *object,
128 guint prop_id,
129 GValue *value,
130 GParamSpec *pspec)
131 {
132 GsmConsolekit *self = GSM_CONSOLEKIT (object);
133
134 switch (prop_id) {
135 case PROP_ACTIVE:
136 g_value_set_boolean (value, self->priv->is_active);
137 break;
138 default:
139 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
140 break;
141 }
142 }
143
144 static void
gsm_consolekit_class_init(GsmConsolekitClass * manager_class)145 gsm_consolekit_class_init (GsmConsolekitClass *manager_class)
146 {
147 GObjectClass *object_class;
148
149 object_class = G_OBJECT_CLASS (manager_class);
150
151 object_class->get_property = gsm_consolekit_get_property;
152 object_class->set_property = gsm_consolekit_set_property;
153 object_class->finalize = gsm_consolekit_finalize;
154
155 g_object_class_override_property (object_class, PROP_ACTIVE, "active");
156
157 g_type_class_add_private (manager_class, sizeof (GsmConsolekitPrivate));
158 }
159
160 static void ck_session_proxy_signal_cb (GDBusProxy *proxy,
161 const gchar *sender_name,
162 const gchar *signal_name,
163 GVariant *parameters,
164 gpointer user_data);
165
166 static void ck_proxy_signal_cb (GDBusProxy *proxy,
167 const gchar *sender_name,
168 const gchar *signal_name,
169 GVariant *parameters,
170 gpointer user_data);
171
172 static void
ck_pid_get_session(GsmConsolekit * manager,pid_t pid,gchar ** session_id)173 ck_pid_get_session (GsmConsolekit *manager,
174 pid_t pid,
175 gchar **session_id)
176 {
177 GVariant *res;
178
179 *session_id = NULL;
180
181 if (pid < 0) {
182 g_warning ("Calling GetSessionForUnixProcess failed."
183 "Invalid pid.");
184 return;
185 }
186
187 res = g_dbus_proxy_call_sync (manager->priv->ck_proxy,
188 "GetSessionForUnixProcess",
189 g_variant_new ("(u)", pid),
190 0,
191 -1,
192 NULL,
193 NULL);
194 if (!res) {
195 g_warning ("Calling GetSessionForUnixProcess failed."
196 "Check that ConsoleKit is properly installed.");
197 return;
198 }
199
200 g_variant_get (res, "(o)", session_id);
201 g_variant_unref (res);
202 }
203
204 static void
gsm_consolekit_init(GsmConsolekit * manager)205 gsm_consolekit_init (GsmConsolekit *manager)
206 {
207 GError *error = NULL;
208 GDBusConnection *bus;
209 GVariant *res;
210
211 manager->priv = G_TYPE_INSTANCE_GET_PRIVATE (manager,
212 GSM_TYPE_CONSOLEKIT,
213 GsmConsolekitPrivate);
214
215 manager->priv->inhibit_fd = -1;
216 manager->priv->delay_inhibit_fd = -1;
217
218 bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
219 if (bus == NULL)
220 g_error ("Failed to connect to system bus: %s",
221 error->message);
222 manager->priv->ck_proxy =
223 g_dbus_proxy_new_sync (bus,
224 0,
225 NULL,
226 CK_NAME,
227 CK_MANAGER_PATH,
228 CK_MANAGER_INTERFACE,
229 NULL,
230 &error);
231 if (manager->priv->ck_proxy == NULL) {
232 g_warning ("Failed to connect to consolekit: %s",
233 error->message);
234 g_clear_error (&error);
235 }
236
237 g_signal_connect (manager->priv->ck_proxy, "g-signal",
238 G_CALLBACK (ck_proxy_signal_cb), manager);
239
240 ck_pid_get_session (manager, getpid (), &manager->priv->session_id);
241
242 if (manager->priv->session_id == NULL) {
243 g_warning ("Could not get session id for session. Check that ConsoleKit is "
244 "properly installed.");
245 return;
246 }
247
248 /* in ConsoleKit, the session id is the session path */
249 manager->priv->session_path = g_strdup (manager->priv->session_id);
250
251 manager->priv->ck_session_proxy =
252 g_dbus_proxy_new_sync (bus,
253 0,
254 NULL,
255 CK_NAME,
256 manager->priv->session_path,
257 CK_SESSION_INTERFACE,
258 NULL,
259 &error);
260 if (manager->priv->ck_proxy == NULL) {
261 g_warning ("Failed to connect to consolekit session: %s",
262 error->message);
263 g_clear_error (&error);
264 }
265
266 g_signal_connect (manager->priv->ck_session_proxy, "g-signal",
267 G_CALLBACK (ck_session_proxy_signal_cb), manager);
268
269 g_object_unref (bus);
270 }
271
272 static void
emit_restart_complete(GsmConsolekit * manager,GError * error)273 emit_restart_complete (GsmConsolekit *manager,
274 GError *error)
275 {
276 GError *call_error;
277
278 call_error = NULL;
279
280 if (error != NULL) {
281 call_error = g_error_new_literal (GSM_SYSTEM_ERROR,
282 GSM_SYSTEM_ERROR_RESTARTING,
283 error->message);
284 }
285
286 g_signal_emit_by_name (G_OBJECT (manager),
287 "request_completed", call_error);
288
289 if (call_error != NULL) {
290 g_error_free (call_error);
291 }
292 }
293
294 static void
emit_stop_complete(GsmConsolekit * manager,GError * error)295 emit_stop_complete (GsmConsolekit *manager,
296 GError *error)
297 {
298 GError *call_error;
299
300 call_error = NULL;
301
302 if (error != NULL) {
303 call_error = g_error_new_literal (GSM_SYSTEM_ERROR,
304 GSM_SYSTEM_ERROR_STOPPING,
305 error->message);
306 }
307
308 g_signal_emit_by_name (G_OBJECT (manager),
309 "request_completed", call_error);
310
311 if (call_error != NULL) {
312 g_error_free (call_error);
313 }
314 }
315
316 static void
restart_done(GObject * source,GAsyncResult * result,gpointer user_data)317 restart_done (GObject *source,
318 GAsyncResult *result,
319 gpointer user_data)
320 {
321 GDBusProxy *proxy = G_DBUS_PROXY (source);
322 GsmConsolekit *manager = user_data;
323 GError *error = NULL;
324 GVariant *res;
325
326 res = g_dbus_proxy_call_finish (proxy, result, &error);
327
328 if (!res) {
329 g_warning ("Unable to restart system: %s", error->message);
330 emit_restart_complete (manager, error);
331 g_error_free (error);
332 } else {
333 emit_restart_complete (manager, NULL);
334 g_variant_unref (res);
335 }
336 }
337
338 static void
gsm_consolekit_attempt_restart(GsmSystem * system)339 gsm_consolekit_attempt_restart (GsmSystem *system)
340 {
341 GsmConsolekit *manager = GSM_CONSOLEKIT (system);
342
343 /* Use Restart instead of Reboot because it will work on
344 * both CK and CK2 */
345 g_dbus_proxy_call (manager->priv->ck_proxy,
346 "Restart",
347 g_variant_new ("()"),
348 0,
349 G_MAXINT,
350 NULL,
351 restart_done,
352 manager);
353 }
354
355 static void
stop_done(GObject * source,GAsyncResult * result,gpointer user_data)356 stop_done (GObject *source,
357 GAsyncResult *result,
358 gpointer user_data)
359 {
360 GDBusProxy *proxy = G_DBUS_PROXY (source);
361 GsmConsolekit *manager = user_data;
362 GError *error = NULL;
363 GVariant *res;
364
365 res = g_dbus_proxy_call_finish (proxy, result, &error);
366
367 if (!res) {
368 g_warning ("Unable to stop system: %s", error->message);
369 emit_stop_complete (manager, error);
370 g_error_free (error);
371 } else {
372 emit_stop_complete (manager, NULL);
373 g_variant_unref (res);
374 }
375 }
376
377 static void
gsm_consolekit_attempt_stop(GsmSystem * system)378 gsm_consolekit_attempt_stop (GsmSystem *system)
379 {
380 GsmConsolekit *manager = GSM_CONSOLEKIT (system);
381
382 /* Use Stop insetad of PowerOff because it will work with
383 * Ck and CK2. */
384 g_dbus_proxy_call (manager->priv->ck_proxy,
385 "Stop",
386 g_variant_new ("()"),
387 0,
388 G_MAXINT,
389 NULL,
390 stop_done,
391 manager);
392 }
393
394 static void
gsm_consolekit_set_session_idle(GsmSystem * system,gboolean is_idle)395 gsm_consolekit_set_session_idle (GsmSystem *system,
396 gboolean is_idle)
397 {
398 GsmConsolekit *manager = GSM_CONSOLEKIT (system);
399
400 g_debug ("Updating consolekit idle status: %d", is_idle);
401 g_dbus_proxy_call_sync (manager->priv->ck_session_proxy,
402 "SetIdleHint",
403 g_variant_new ("(b)", is_idle),
404 0,
405 G_MAXINT,
406 NULL, NULL);
407 }
408
409 static void
ck_session_get_seat(GsmConsolekit * manager,gchar ** seat)410 ck_session_get_seat (GsmConsolekit *manager,
411 gchar **seat)
412 {
413 GVariant *res;
414
415 *seat = NULL;
416
417 res = g_dbus_proxy_call_sync (manager->priv->ck_session_proxy,
418 "GetSeatId",
419 g_variant_new ("()"),
420 0,
421 -1,
422 NULL, NULL);
423 if (!res) {
424 g_warning ("GsmConsoleKit: Calling GetSeatId failed.");
425 return;
426 }
427
428 g_variant_get (res, "(o)", seat);
429 g_variant_unref (res);
430 }
431
432 /* returns -1 on failure
433 * 0 seat is multi-session
434 * 1 seat is not multi-session
435 */
436 static gint
ck_seat_can_multi_session(GsmConsolekit * manager,const gchar * seat)437 ck_seat_can_multi_session (GsmConsolekit *manager,
438 const gchar *seat)
439 {
440 GDBusConnection *bus;
441 GVariant *res;
442 gboolean can_activate;
443
444
445 bus = g_dbus_proxy_get_connection (manager->priv->ck_proxy);
446 res = g_dbus_connection_call_sync (bus,
447 CK_NAME,
448 seat,
449 CK_SEAT_INTERFACE,
450 "CanActivateSessions",
451 g_variant_new ("()"),
452 G_VARIANT_TYPE_BOOLEAN,
453 0,
454 -1,
455 NULL, NULL);
456 if (!res) {
457 g_warning ("GsmConsoleKit: Calling GetSeatId failed.");
458 return -1;
459 }
460
461 g_variant_get (res, "(b)", &can_activate);
462 g_variant_unref (res);
463
464 return can_activate == TRUE ? 1 : 0;
465 }
466
467 static gboolean
gsm_consolekit_can_switch_user(GsmSystem * system)468 gsm_consolekit_can_switch_user (GsmSystem *system)
469 {
470 GsmConsolekit *manager = GSM_CONSOLEKIT (system);
471 gchar *seat;
472 gint ret;
473
474 ck_session_get_seat (manager, &seat);
475 ret = ck_seat_can_multi_session (manager, seat);
476 free (seat);
477
478 return ret > 0;
479 }
480
481 static gboolean
gsm_consolekit_can_restart(GsmSystem * system)482 gsm_consolekit_can_restart (GsmSystem *system)
483 {
484 GsmConsolekit *manager = GSM_CONSOLEKIT (system);
485 GVariant *res;
486 gboolean can_restart;
487
488 res = g_dbus_proxy_call_sync (manager->priv->ck_proxy,
489 "CanRestart",
490 g_variant_new ("()"),
491 0,
492 G_MAXINT,
493 NULL,
494 NULL);
495 if (!res) {
496 g_warning ("Calling CanRestart failed. Check that ConsoleKit is "
497 "properly installed.");
498 return FALSE;
499 }
500
501 g_variant_get (res, "(b)", &can_restart);
502 g_variant_unref (res);
503
504 return can_restart;
505 }
506
507 static gboolean
gsm_consolekit_can_stop(GsmSystem * system)508 gsm_consolekit_can_stop (GsmSystem *system)
509 {
510 GsmConsolekit *manager = GSM_CONSOLEKIT (system);
511 GVariant *res;
512 gboolean can_stop;
513
514 res = g_dbus_proxy_call_sync (manager->priv->ck_proxy,
515 "CanStop",
516 g_variant_new ("()"),
517 0,
518 G_MAXINT,
519 NULL,
520 NULL);
521 if (!res) {
522 g_warning ("Calling CanStop failed. Check that ConsoleKit is "
523 "properly installed.");
524 return FALSE;
525 }
526
527 g_variant_get (res, "(b)", &can_stop);
528 g_variant_unref (res);
529
530 return can_stop;
531 }
532
533 /* returns -1 on failure, 0 on success */
534 static gint
ck_session_get_class(GsmConsolekit * manager,gchar ** session_class)535 ck_session_get_class (GsmConsolekit *manager,
536 gchar **session_class)
537 {
538 GVariant *res;
539
540 *session_class = NULL;
541
542 res = g_dbus_proxy_call_sync (manager->priv->ck_session_proxy,
543 "GetSessionClass",
544 g_variant_new ("()"),
545 0,
546 -1,
547 NULL, NULL);
548 if (!res) {
549 g_warning ("GsmConsoleKit: Calling GetSessionClass failed.");
550 return -1;
551 }
552
553 g_variant_get (res, "(s)", session_class);
554 g_variant_unref (res);
555
556 return 0;
557 }
558
559 static gboolean
gsm_consolekit_is_login_session(GsmSystem * system)560 gsm_consolekit_is_login_session (GsmSystem *system)
561 {
562 GsmConsolekit *manager = GSM_CONSOLEKIT (system);
563 int res;
564 gboolean ret;
565 gchar *session_class = NULL;
566
567 ret = FALSE;
568
569 if (manager->priv->session_id == NULL) {
570 return ret;
571 }
572
573 res = ck_session_get_class (manager, &session_class);
574 if (res < 0) {
575 g_warning ("Could not get session class: %s", strerror (-res));
576 return FALSE;
577 }
578 ret = (g_strcmp0 (session_class, "greeter") == 0);
579 g_free (session_class);
580
581 return ret;
582 }
583
584 static gboolean
gsm_consolekit_can_suspend(GsmSystem * system)585 gsm_consolekit_can_suspend (GsmSystem *system)
586 {
587 GsmConsolekit *manager = GSM_CONSOLEKIT (system);
588 gchar *rv;
589 GVariant *res;
590 gboolean can_suspend;
591
592 res = g_dbus_proxy_call_sync (manager->priv->ck_proxy,
593 "CanSuspend",
594 NULL,
595 0,
596 G_MAXINT,
597 NULL,
598 NULL);
599 if (!res) {
600 g_warning ("Calling CanSuspend failed. Check that ConsoleKit is "
601 "properly installed.");
602 return FALSE;
603 }
604
605 g_variant_get (res, "(s)", &rv);
606 g_variant_unref (res);
607
608 can_suspend = g_strcmp0 (rv, "yes") == 0 ||
609 g_strcmp0 (rv, "challenge") == 0;
610
611 g_free (rv);
612
613 return can_suspend;
614 }
615
616 static gboolean
gsm_consolekit_can_hibernate(GsmSystem * system)617 gsm_consolekit_can_hibernate (GsmSystem *system)
618 {
619 GsmConsolekit *manager = GSM_CONSOLEKIT (system);
620 gchar *rv;
621 GVariant *res;
622 gboolean can_hibernate;
623
624 res = g_dbus_proxy_call_sync (manager->priv->ck_proxy,
625 "CanHibernate",
626 NULL,
627 0,
628 G_MAXINT,
629 NULL,
630 NULL);
631 if (!res) {
632 g_warning ("Calling CanHibernate failed. Check that ConsoleKit is "
633 "properly installed.");
634 return FALSE;
635 }
636
637 g_variant_get (res, "(s)", &rv);
638 g_variant_unref (res);
639
640 can_hibernate = g_strcmp0 (rv, "yes") == 0 ||
641 g_strcmp0 (rv, "challenge") == 0;
642
643 g_free (rv);
644
645 return can_hibernate;
646 }
647
648 static void
suspend_done(GObject * source,GAsyncResult * result,gpointer user_data)649 suspend_done (GObject *source,
650 GAsyncResult *result,
651 gpointer user_data)
652 {
653 GDBusProxy *proxy = G_DBUS_PROXY (source);
654 GError *error = NULL;
655 GVariant *res;
656
657 res = g_dbus_proxy_call_finish (proxy, result, &error);
658
659 if (!res) {
660 g_warning ("Unable to suspend system: %s", error->message);
661 g_error_free (error);
662 } else {
663 g_variant_unref (res);
664 }
665 }
666
667 static void
hibernate_done(GObject * source,GAsyncResult * result,gpointer user_data)668 hibernate_done (GObject *source,
669 GAsyncResult *result,
670 gpointer user_data)
671 {
672 GDBusProxy *proxy = G_DBUS_PROXY (source);
673 GError *error = NULL;
674 GVariant *res;
675
676 res = g_dbus_proxy_call_finish (proxy, result, &error);
677
678 if (!res) {
679 g_warning ("Unable to hibernate system: %s", error->message);
680 g_error_free (error);
681 } else {
682 g_variant_unref (res);
683 }
684 }
685
686 static void
gsm_consolekit_suspend(GsmSystem * system)687 gsm_consolekit_suspend (GsmSystem *system)
688 {
689 GsmConsolekit *manager = GSM_CONSOLEKIT (system);
690
691 g_dbus_proxy_call (manager->priv->ck_proxy,
692 "Suspend",
693 g_variant_new ("(b)", TRUE),
694 0,
695 G_MAXINT,
696 NULL,
697 suspend_done,
698 manager);
699 }
700
701 static void
gsm_consolekit_hibernate(GsmSystem * system)702 gsm_consolekit_hibernate (GsmSystem *system)
703 {
704 GsmConsolekit *manager = GSM_CONSOLEKIT (system);
705
706 g_dbus_proxy_call (manager->priv->ck_proxy,
707 "Hibernate",
708 g_variant_new ("(b)", TRUE),
709 0,
710 G_MAXINT,
711 NULL,
712 hibernate_done,
713 manager);
714 }
715
716 static void
inhibit_done(GObject * source,GAsyncResult * result,gpointer user_data)717 inhibit_done (GObject *source,
718 GAsyncResult *result,
719 gpointer user_data)
720 {
721 GDBusProxy *proxy = G_DBUS_PROXY (source);
722 GsmConsolekit *manager = GSM_CONSOLEKIT (user_data);
723 GError *error = NULL;
724 GVariant *res;
725 GUnixFDList *fd_list = NULL;
726 gint idx;
727
728 /* Drop any previous inhibit before recording the new one */
729 drop_system_inhibitor (manager);
730
731 res = g_dbus_proxy_call_with_unix_fd_list_finish (proxy, &fd_list, result, &error);
732
733 if (!res) {
734 g_warning ("Unable to inhibit system: %s", error->message);
735 g_error_free (error);
736 } else {
737 g_variant_get (res, "(h)", &idx);
738 manager->priv->inhibit_fd = g_unix_fd_list_get (fd_list, idx, &error);
739 if (manager->priv->inhibit_fd == -1) {
740 g_warning ("Failed to receive system inhibitor fd: %s", error->message);
741 g_error_free (error);
742 }
743 g_debug ("System inhibitor fd is %d", manager->priv->inhibit_fd);
744 g_object_unref (fd_list);
745 g_variant_unref (res);
746 }
747
748 /* Handle a race condition, where locks got unset during dbus call */
749 if (manager->priv->inhibit_locks == NULL) {
750 drop_system_inhibitor (manager);
751 }
752 }
753
754 static void
gsm_consolekit_set_inhibitors(GsmSystem * system,GsmInhibitorFlag flags)755 gsm_consolekit_set_inhibitors (GsmSystem *system,
756 GsmInhibitorFlag flags)
757 {
758 GsmConsolekit *manager = GSM_CONSOLEKIT (system);
759 const gchar *locks = NULL;
760 gboolean inhibit_logout;
761 gboolean inhibit_suspend;
762
763 inhibit_logout = (flags & GSM_INHIBITOR_FLAG_LOGOUT) != 0;
764 inhibit_suspend = (flags & GSM_INHIBITOR_FLAG_SUSPEND) != 0;
765
766 if (inhibit_logout && inhibit_suspend) {
767 locks = "sleep:shutdown";
768 } else if (inhibit_logout) {
769 locks = "shutdown";
770 } else if (inhibit_suspend) {
771 locks = "sleep";
772 }
773 manager->priv->inhibit_locks = locks;
774
775 if (locks != NULL) {
776 g_debug ("Adding system inhibitor on %s", locks);
777 g_dbus_proxy_call_with_unix_fd_list (manager->priv->ck_proxy,
778 "Inhibit",
779 g_variant_new ("(ssss)",
780 locks,
781 g_get_user_name (),
782 "user session inhibited",
783 "block"),
784 0,
785 G_MAXINT,
786 NULL,
787 NULL,
788 inhibit_done,
789 manager);
790 } else {
791 drop_system_inhibitor (manager);
792 }
793 }
794
795 static void
reboot_or_poweroff_done(GObject * source,GAsyncResult * res,gpointer user_data)796 reboot_or_poweroff_done (GObject *source,
797 GAsyncResult *res,
798 gpointer user_data)
799 {
800 GsmConsolekit *consolekit = user_data;
801 GVariant *result;
802 GError *error = NULL;
803
804 result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source),
805 res,
806 &error);
807
808 if (result == NULL) {
809 if (!g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_ACCESS_DENIED)) {
810 g_warning ("Shutdown failed: %s", error->message);
811 }
812 g_error_free (error);
813 drop_delay_inhibitor (consolekit);
814 g_debug ("GsmConsolekit: shutdown preparation failed");
815 consolekit->priv->prepare_for_shutdown_expected = FALSE;
816 g_signal_emit_by_name (consolekit, "shutdown-prepared", FALSE);
817 } else {
818 g_variant_unref (result);
819 }
820 }
821
822 static void
gsm_consolekit_prepare_shutdown(GsmSystem * system,gboolean restart)823 gsm_consolekit_prepare_shutdown (GsmSystem *system,
824 gboolean restart)
825 {
826 GsmConsolekit *consolekit = GSM_CONSOLEKIT (system);
827 GUnixFDList *fd_list;
828 GVariant *res;
829 GError *error = NULL;
830 gint idx;
831
832 g_debug ("GsmConsolekit: prepare shutdown");
833
834 res = g_dbus_proxy_call_with_unix_fd_list_sync (consolekit->priv->ck_proxy,
835 "Inhibit",
836 g_variant_new ("(ssss)",
837 "shutdown",
838 g_get_user_name (),
839 "Preparing to end the session",
840 "delay"),
841 0,
842 G_MAXINT,
843 NULL,
844 &fd_list,
845 NULL,
846 &error);
847 if (res == NULL) {
848 g_warning ("Failed to get delay inhibitor: %s", error->message);
849 g_error_free (error);
850 /* We may fail here with CK and that's ok */
851 } else {
852 g_variant_get (res, "(h)", &idx);
853
854 consolekit->priv->delay_inhibit_fd = g_unix_fd_list_get (fd_list, idx, NULL);
855
856 g_debug ("GsmConsolekit: got delay inhibitor, fd = %d", consolekit->priv->delay_inhibit_fd);
857
858 g_variant_unref (res);
859 g_object_unref (fd_list);
860 }
861
862 consolekit->priv->prepare_for_shutdown_expected = TRUE;
863
864 g_dbus_proxy_call (consolekit->priv->ck_proxy,
865 restart ? "Reboot" : "PowerOff",
866 g_variant_new ("(b)", TRUE),
867 0,
868 G_MAXINT,
869 NULL,
870 reboot_or_poweroff_done,
871 consolekit);
872 }
873
874 static void
gsm_consolekit_complete_shutdown(GsmSystem * system)875 gsm_consolekit_complete_shutdown (GsmSystem *system)
876 {
877 GsmConsolekit *consolekit = GSM_CONSOLEKIT (system);
878
879 /* remove delay inhibitor, if any */
880 drop_delay_inhibitor (consolekit);
881 }
882
883 static gboolean
gsm_consolekit_is_last_session_for_user(GsmSystem * system)884 gsm_consolekit_is_last_session_for_user (GsmSystem *system)
885 {
886 return FALSE;
887 }
888
889 static void
gsm_consolekit_system_init(GsmSystemInterface * iface)890 gsm_consolekit_system_init (GsmSystemInterface *iface)
891 {
892 iface->can_switch_user = gsm_consolekit_can_switch_user;
893 iface->can_stop = gsm_consolekit_can_stop;
894 iface->can_restart = gsm_consolekit_can_restart;
895 iface->can_suspend = gsm_consolekit_can_suspend;
896 iface->can_hibernate = gsm_consolekit_can_hibernate;
897 iface->attempt_stop = gsm_consolekit_attempt_stop;
898 iface->attempt_restart = gsm_consolekit_attempt_restart;
899 iface->suspend = gsm_consolekit_suspend;
900 iface->hibernate = gsm_consolekit_hibernate;
901 iface->set_session_idle = gsm_consolekit_set_session_idle;
902 iface->is_login_session = gsm_consolekit_is_login_session;
903 iface->set_inhibitors = gsm_consolekit_set_inhibitors;
904 iface->prepare_shutdown = gsm_consolekit_prepare_shutdown;
905 iface->complete_shutdown = gsm_consolekit_complete_shutdown;
906 iface->is_last_session_for_user = gsm_consolekit_is_last_session_for_user;
907 }
908
909 GsmConsolekit *
gsm_consolekit_new(void)910 gsm_consolekit_new (void)
911 {
912 GsmConsolekit *manager;
913
914 manager = g_object_new (GSM_TYPE_CONSOLEKIT, NULL);
915
916 return manager;
917 }
918
919 static void
ck_proxy_signal_cb(GDBusProxy * proxy,const gchar * sender_name,const gchar * signal_name,GVariant * parameters,gpointer user_data)920 ck_proxy_signal_cb (GDBusProxy *proxy,
921 const gchar *sender_name,
922 const gchar *signal_name,
923 GVariant *parameters,
924 gpointer user_data)
925 {
926 GsmConsolekit *consolekit = user_data;
927 gboolean is_about_to_shutdown;
928
929 g_debug ("GsmConsolekit: received ConsoleKit signal: %s", signal_name);
930
931 if (g_strcmp0 (signal_name, "PrepareForShutdown") != 0) {
932 g_debug ("GsmConsolekit: ignoring %s signal", signal_name);
933 return;
934 }
935
936 g_variant_get (parameters, "(b)", &is_about_to_shutdown);
937 if (!is_about_to_shutdown) {
938 g_debug ("GsmConsolekit: ignoring %s signal since about-to-shutdown is FALSE", signal_name);
939 return;
940 }
941
942 if (consolekit->priv->prepare_for_shutdown_expected) {
943 g_debug ("GsmConsolekit: shutdown successfully prepared");
944 g_signal_emit_by_name (consolekit, "shutdown-prepared", TRUE);
945 consolekit->priv->prepare_for_shutdown_expected = FALSE;
946 }
947 }
948
949 static void
ck_session_proxy_signal_cb(GDBusProxy * proxy,const gchar * sender_name,const gchar * signal_name,GVariant * parameters,gpointer user_data)950 ck_session_proxy_signal_cb (GDBusProxy *proxy,
951 const gchar *sender_name,
952 const gchar *signal_name,
953 GVariant *parameters,
954 gpointer user_data)
955 {
956 GsmConsolekit *consolekit = user_data;
957 gboolean is_active;
958
959 g_debug ("GsmConsolekit: received ConsoleKit signal: %s", signal_name);
960
961 if (g_strcmp0 (signal_name, "ActiveChanged") != 0) {
962 g_debug ("GsmConsolekit: ignoring %s signal", signal_name);
963 return;
964 }
965
966 g_variant_get (parameters, "(b)", &is_active);
967 if (consolekit->priv->is_active != is_active) {
968 g_debug ("GsmConsolekit: session state changed");
969 consolekit->priv->is_active = is_active;
970 g_object_notify (G_OBJECT (consolekit), "active");
971 }
972 }
973