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 #ifdef HAVE_OLD_UPOWER
35 #define UPOWER_ENABLE_DEPRECATED 1
36 #include <upower.h>
37 #endif
38
39 #include "csm-system.h"
40 #include "csm-consolekit.h"
41
42 #define CK_NAME "org.freedesktop.ConsoleKit"
43
44 #define CK_MANAGER_PATH "/org/freedesktop/ConsoleKit/Manager"
45 #define CK_MANAGER_INTERFACE CK_NAME ".Manager"
46 #define CK_SEAT_INTERFACE CK_NAME ".Seat"
47 #define CK_SESSION_INTERFACE CK_NAME ".Session"
48
49
50 struct _CsmConsolekitPrivate
51 {
52 GDBusProxy *ck_proxy;
53 GDBusProxy *ck_session_proxy;
54 #ifdef HAVE_OLD_UPOWER
55 UpClient *up_client;
56 #endif
57 char *session_id;
58 gchar *session_path;
59
60 GSList *inhibitors;
61 gint inhibit_fd;
62
63 gboolean is_active;
64
65 gint delay_inhibit_fd;
66 gboolean prepare_for_shutdown_expected;
67 };
68
69 enum {
70 PROP_0,
71 PROP_ACTIVE
72 };
73
74 static void csm_consolekit_system_init (CsmSystemInterface *iface);
75
G_DEFINE_TYPE_WITH_CODE(CsmConsolekit,csm_consolekit,G_TYPE_OBJECT,G_IMPLEMENT_INTERFACE (CSM_TYPE_SYSTEM,csm_consolekit_system_init))76 G_DEFINE_TYPE_WITH_CODE (CsmConsolekit, csm_consolekit, G_TYPE_OBJECT,
77 G_IMPLEMENT_INTERFACE (CSM_TYPE_SYSTEM,
78 csm_consolekit_system_init))
79
80 static void
81 drop_system_inhibitor (CsmConsolekit *manager)
82 {
83 if (manager->priv->inhibit_fd != -1) {
84 g_debug ("CsmConsolekit: Dropping system inhibitor");
85 close (manager->priv->inhibit_fd);
86 manager->priv->inhibit_fd = -1;
87 }
88 }
89
90 static void
drop_delay_inhibitor(CsmConsolekit * manager)91 drop_delay_inhibitor (CsmConsolekit *manager)
92 {
93 if (manager->priv->delay_inhibit_fd != -1) {
94 g_debug ("CsmConsolekit: Dropping delay inhibitor");
95 close (manager->priv->delay_inhibit_fd);
96 manager->priv->delay_inhibit_fd = -1;
97 }
98 }
99
100 static void
csm_consolekit_finalize(GObject * object)101 csm_consolekit_finalize (GObject *object)
102 {
103 CsmConsolekit *consolekit = CSM_CONSOLEKIT (object);
104
105 g_clear_object (&consolekit->priv->ck_proxy);
106 g_clear_object (&consolekit->priv->ck_session_proxy);
107 free (consolekit->priv->session_id);
108 g_free (consolekit->priv->session_path);
109
110 if (consolekit->priv->inhibitors != NULL) {
111 g_slist_free_full (consolekit->priv->inhibitors, g_free);
112 }
113 drop_system_inhibitor (consolekit);
114 drop_delay_inhibitor (consolekit);
115
116 #ifdef HAVE_OLD_UPOWER
117 g_clear_object (&manager->priv->up_client);
118 #endif
119
120 G_OBJECT_CLASS (csm_consolekit_parent_class)->finalize (object);
121 }
122
123 static void
csm_consolekit_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)124 csm_consolekit_set_property (GObject *object,
125 guint prop_id,
126 const GValue *value,
127 GParamSpec *pspec)
128 {
129 CsmConsolekit *self = CSM_CONSOLEKIT (object);
130
131 switch (prop_id) {
132 case PROP_ACTIVE:
133 self->priv->is_active = g_value_get_boolean (value);
134 break;
135 default:
136 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
137 }
138 }
139
140 static void
csm_consolekit_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)141 csm_consolekit_get_property (GObject *object,
142 guint prop_id,
143 GValue *value,
144 GParamSpec *pspec)
145 {
146 CsmConsolekit *self = CSM_CONSOLEKIT (object);
147
148 switch (prop_id) {
149 case PROP_ACTIVE:
150 g_value_set_boolean (value, self->priv->is_active);
151 break;
152 default:
153 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
154 break;
155 }
156 }
157
158 static void
csm_consolekit_class_init(CsmConsolekitClass * manager_class)159 csm_consolekit_class_init (CsmConsolekitClass *manager_class)
160 {
161 GObjectClass *object_class;
162
163 object_class = G_OBJECT_CLASS (manager_class);
164
165 object_class->get_property = csm_consolekit_get_property;
166 object_class->set_property = csm_consolekit_set_property;
167 object_class->finalize = csm_consolekit_finalize;
168
169 g_object_class_override_property (object_class, PROP_ACTIVE, "active");
170
171 g_type_class_add_private (manager_class, sizeof (CsmConsolekitPrivate));
172 }
173
174 static void ck_session_proxy_signal_cb (GDBusProxy *proxy,
175 const gchar *sender_name,
176 const gchar *signal_name,
177 GVariant *parameters,
178 gpointer user_data);
179
180 static void ck_proxy_signal_cb (GDBusProxy *proxy,
181 const gchar *sender_name,
182 const gchar *signal_name,
183 GVariant *parameters,
184 gpointer user_data);
185
186 static void
ck_pid_get_session(CsmConsolekit * manager,pid_t pid,gchar ** session_id)187 ck_pid_get_session (CsmConsolekit *manager,
188 pid_t pid,
189 gchar **session_id)
190 {
191 GVariant *res;
192
193 *session_id = NULL;
194
195 if (pid < 0) {
196 g_warning ("Calling GetSessionForUnixProcess failed."
197 "Invalid pid.");
198 return;
199 }
200
201 res = g_dbus_proxy_call_sync (manager->priv->ck_proxy,
202 "GetSessionForUnixProcess",
203 g_variant_new ("(u)", pid),
204 0,
205 -1,
206 NULL,
207 NULL);
208 if (!res) {
209 g_warning ("Calling GetSessionForUnixProcess failed."
210 "Check that ConsoleKit is properly installed.");
211 return;
212 }
213
214 g_variant_get (res, "(o)", session_id);
215 g_variant_unref (res);
216 }
217
218 static void
csm_consolekit_init(CsmConsolekit * manager)219 csm_consolekit_init (CsmConsolekit *manager)
220 {
221 GError *error = NULL;
222 GDBusConnection *bus;
223 GVariant *res;
224
225 manager->priv = G_TYPE_INSTANCE_GET_PRIVATE (manager,
226 CSM_TYPE_CONSOLEKIT,
227 CsmConsolekitPrivate);
228
229 manager->priv->inhibit_fd = -1;
230 manager->priv->delay_inhibit_fd = -1;
231
232 bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
233 if (bus == NULL)
234 g_error ("Failed to connect to system bus: %s",
235 error->message);
236 manager->priv->ck_proxy =
237 g_dbus_proxy_new_sync (bus,
238 0,
239 NULL,
240 CK_NAME,
241 CK_MANAGER_PATH,
242 CK_MANAGER_INTERFACE,
243 NULL,
244 &error);
245 if (manager->priv->ck_proxy == NULL) {
246 g_warning ("Failed to connect to consolekit: %s",
247 error->message);
248 g_clear_error (&error);
249 }
250
251 g_signal_connect (manager->priv->ck_proxy, "g-signal",
252 G_CALLBACK (ck_proxy_signal_cb), manager);
253
254 ck_pid_get_session (manager, getpid (), &manager->priv->session_id);
255
256 if (manager->priv->session_id == NULL) {
257 g_warning ("Could not get session id for session. Check that ConsoleKit is "
258 "properly installed.");
259 return;
260 }
261
262 /* in ConsoleKit, the session id is the session path */
263 manager->priv->session_path = g_strdup (manager->priv->session_id);
264
265 manager->priv->ck_session_proxy =
266 g_dbus_proxy_new_sync (bus,
267 0,
268 NULL,
269 CK_NAME,
270 manager->priv->session_path,
271 CK_SESSION_INTERFACE,
272 NULL,
273 &error);
274 if (manager->priv->ck_proxy == NULL) {
275 g_warning ("Failed to connect to consolekit session: %s",
276 error->message);
277 g_clear_error (&error);
278 }
279
280 g_signal_connect (manager->priv->ck_session_proxy, "g-signal",
281 G_CALLBACK (ck_session_proxy_signal_cb), manager);
282
283 #ifdef HAVE_OLD_UPOWER
284 g_clear_object (&manager->priv->up_client);
285 manager->priv->up_client = up_client_new ();
286 #endif
287
288 g_object_unref (bus);
289 }
290
291 static void
emit_restart_complete(CsmConsolekit * manager,GError * error)292 emit_restart_complete (CsmConsolekit *manager,
293 GError *error)
294 {
295 GError *call_error;
296
297 call_error = NULL;
298
299 if (error != NULL) {
300 call_error = g_error_new_literal (CSM_SYSTEM_ERROR,
301 CSM_SYSTEM_ERROR_RESTARTING,
302 error->message);
303 }
304
305 g_signal_emit_by_name (G_OBJECT (manager),
306 "request_completed", call_error);
307
308 if (call_error != NULL) {
309 g_error_free (call_error);
310 }
311 }
312
313 static void
emit_stop_complete(CsmConsolekit * manager,GError * error)314 emit_stop_complete (CsmConsolekit *manager,
315 GError *error)
316 {
317 GError *call_error;
318
319 call_error = NULL;
320
321 if (error != NULL) {
322 call_error = g_error_new_literal (CSM_SYSTEM_ERROR,
323 CSM_SYSTEM_ERROR_STOPPING,
324 error->message);
325 }
326
327 g_signal_emit_by_name (G_OBJECT (manager),
328 "request_completed", call_error);
329
330 if (call_error != NULL) {
331 g_error_free (call_error);
332 }
333 }
334
335 static void
restart_done(GObject * source,GAsyncResult * result,gpointer user_data)336 restart_done (GObject *source,
337 GAsyncResult *result,
338 gpointer user_data)
339 {
340 GDBusProxy *proxy = G_DBUS_PROXY (source);
341 CsmConsolekit *manager = user_data;
342 GError *error = NULL;
343 GVariant *res;
344
345 res = g_dbus_proxy_call_finish (proxy, result, &error);
346
347 if (!res) {
348 g_warning ("Unable to restart system: %s", error->message);
349 emit_restart_complete (manager, error);
350 g_error_free (error);
351 } else {
352 emit_restart_complete (manager, NULL);
353 g_variant_unref (res);
354 }
355 }
356
357 static void
csm_consolekit_attempt_restart(CsmSystem * system)358 csm_consolekit_attempt_restart (CsmSystem *system)
359 {
360 CsmConsolekit *manager = CSM_CONSOLEKIT (system);
361
362 /* Use Restart instead of Reboot because it will work on
363 * both CK and CK2 */
364 g_dbus_proxy_call (manager->priv->ck_proxy,
365 "Restart",
366 g_variant_new ("()"),
367 0,
368 G_MAXINT,
369 NULL,
370 restart_done,
371 manager);
372 }
373
374 static void
stop_done(GObject * source,GAsyncResult * result,gpointer user_data)375 stop_done (GObject *source,
376 GAsyncResult *result,
377 gpointer user_data)
378 {
379 GDBusProxy *proxy = G_DBUS_PROXY (source);
380 CsmConsolekit *manager = user_data;
381 GError *error = NULL;
382 GVariant *res;
383
384 res = g_dbus_proxy_call_finish (proxy, result, &error);
385
386 if (!res) {
387 g_warning ("Unable to stop system: %s", error->message);
388 emit_stop_complete (manager, error);
389 g_error_free (error);
390 } else {
391 emit_stop_complete (manager, NULL);
392 g_variant_unref (res);
393 }
394 }
395
396 static void
csm_consolekit_attempt_stop(CsmSystem * system)397 csm_consolekit_attempt_stop (CsmSystem *system)
398 {
399 CsmConsolekit *manager = CSM_CONSOLEKIT (system);
400
401 /* Use Stop insetad of PowerOff because it will work with
402 * Ck and CK2. */
403 g_dbus_proxy_call (manager->priv->ck_proxy,
404 "Stop",
405 g_variant_new ("()"),
406 0,
407 G_MAXINT,
408 NULL,
409 stop_done,
410 manager);
411 }
412
413 static void
csm_consolekit_set_session_idle(CsmSystem * system,gboolean is_idle)414 csm_consolekit_set_session_idle (CsmSystem *system,
415 gboolean is_idle)
416 {
417 CsmConsolekit *manager = CSM_CONSOLEKIT (system);
418
419 g_debug ("Updating consolekit idle status: %d", is_idle);
420 g_dbus_proxy_call_sync (manager->priv->ck_session_proxy,
421 "SetIdleHint",
422 g_variant_new ("(b)", is_idle),
423 0,
424 G_MAXINT,
425 NULL, NULL);
426 }
427
428 static void
ck_session_get_seat(CsmConsolekit * manager,gchar ** seat)429 ck_session_get_seat (CsmConsolekit *manager,
430 gchar **seat)
431 {
432 GVariant *res;
433
434 *seat = NULL;
435
436 res = g_dbus_proxy_call_sync (manager->priv->ck_session_proxy,
437 "GetSeatId",
438 g_variant_new ("()"),
439 0,
440 -1,
441 NULL, NULL);
442 if (!res) {
443 g_warning ("CsmConsoleKit: Calling GetSeatId failed.");
444 return;
445 }
446
447 g_variant_get (res, "(o)", seat);
448 g_variant_unref (res);
449 }
450
451 /* returns -1 on failure
452 * 0 seat is multi-session
453 * 1 seat is not multi-session
454 */
455 static gint
ck_seat_can_multi_session(CsmConsolekit * manager,const gchar * seat)456 ck_seat_can_multi_session (CsmConsolekit *manager,
457 const gchar *seat)
458 {
459 GDBusConnection *bus;
460 GVariant *res;
461 gboolean can_activate;
462
463
464 bus = g_dbus_proxy_get_connection (manager->priv->ck_proxy);
465 res = g_dbus_connection_call_sync (bus,
466 CK_NAME,
467 seat,
468 CK_SEAT_INTERFACE,
469 "CanActivateSessions",
470 g_variant_new ("()"),
471 G_VARIANT_TYPE_BOOLEAN,
472 0,
473 -1,
474 NULL, NULL);
475 if (!res) {
476 g_warning ("CsmConsoleKit: Calling GetSeatId failed.");
477 return -1;
478 }
479
480 g_variant_get (res, "(b)", &can_activate);
481 g_variant_unref (res);
482
483 return can_activate == TRUE ? 1 : 0;
484 }
485
486 static gboolean
csm_consolekit_can_switch_user(CsmSystem * system)487 csm_consolekit_can_switch_user (CsmSystem *system)
488 {
489 CsmConsolekit *manager = CSM_CONSOLEKIT (system);
490 gchar *seat;
491 gint ret;
492
493 ck_session_get_seat (manager, &seat);
494 ret = ck_seat_can_multi_session (manager, seat);
495 free (seat);
496
497 return ret > 0;
498 }
499
500 static gboolean
csm_consolekit_can_restart(CsmSystem * system)501 csm_consolekit_can_restart (CsmSystem *system)
502 {
503 CsmConsolekit *manager = CSM_CONSOLEKIT (system);
504 GVariant *res;
505 gboolean can_restart;
506
507 res = g_dbus_proxy_call_sync (manager->priv->ck_proxy,
508 "CanRestart",
509 g_variant_new ("()"),
510 0,
511 G_MAXINT,
512 NULL,
513 NULL);
514 if (!res) {
515 g_warning ("Calling CanRestart failed. Check that ConsoleKit is "
516 "properly installed.");
517 return FALSE;
518 }
519
520 g_variant_get (res, "(b)", &can_restart);
521 g_variant_unref (res);
522
523 return can_restart;
524 }
525
526 static gboolean
csm_consolekit_can_stop(CsmSystem * system)527 csm_consolekit_can_stop (CsmSystem *system)
528 {
529 CsmConsolekit *manager = CSM_CONSOLEKIT (system);
530 GVariant *res;
531 gboolean can_stop;
532
533 res = g_dbus_proxy_call_sync (manager->priv->ck_proxy,
534 "CanStop",
535 g_variant_new ("()"),
536 0,
537 G_MAXINT,
538 NULL,
539 NULL);
540 if (!res) {
541 g_warning ("Calling CanStop failed. Check that ConsoleKit is "
542 "properly installed.");
543 return FALSE;
544 }
545
546 g_variant_get (res, "(b)", &can_stop);
547 g_variant_unref (res);
548
549 return can_stop;
550 }
551
552 /* returns -1 on failure, 0 on success */
553 static gint
ck_session_get_class(CsmConsolekit * manager,gchar ** session_class)554 ck_session_get_class (CsmConsolekit *manager,
555 gchar **session_class)
556 {
557 GVariant *res;
558
559 *session_class = NULL;
560
561 res = g_dbus_proxy_call_sync (manager->priv->ck_session_proxy,
562 "GetSessionClass",
563 g_variant_new ("()"),
564 0,
565 -1,
566 NULL, NULL);
567 if (!res) {
568 g_warning ("CsmConsoleKit: Calling GetSessionClass failed.");
569 return -1;
570 }
571
572 g_variant_get (res, "(s)", session_class);
573 g_variant_unref (res);
574
575 return 0;
576 }
577
578 static gboolean
csm_consolekit_is_login_session(CsmSystem * system)579 csm_consolekit_is_login_session (CsmSystem *system)
580 {
581 CsmConsolekit *manager = CSM_CONSOLEKIT (system);
582 int res;
583 gboolean ret;
584 gchar *session_class = NULL;
585
586 ret = FALSE;
587
588 if (manager->priv->session_id == NULL) {
589 return ret;
590 }
591
592 res = ck_session_get_class (manager, &session_class);
593 if (res < 0) {
594 g_warning ("Could not get session class: %s", strerror (-res));
595 return FALSE;
596 }
597 ret = (g_strcmp0 (session_class, "greeter") == 0);
598 g_free (session_class);
599
600 return ret;
601 }
602
603 static gboolean
csm_consolekit_can_suspend(CsmSystem * system)604 csm_consolekit_can_suspend (CsmSystem *system)
605 {
606 #ifdef HAVE_OLD_UPOWER
607 CsmConsolekit *consolekit = CSM_CONSOLEKIT (system);
608 return up_client_get_can_suspend (consolekit->priv->up_client);
609 #else
610 CsmConsolekit *manager = CSM_CONSOLEKIT (system);
611 gchar *rv;
612 GVariant *res;
613 gboolean can_suspend;
614
615 res = g_dbus_proxy_call_sync (manager->priv->ck_proxy,
616 "CanSuspend",
617 NULL,
618 0,
619 G_MAXINT,
620 NULL,
621 NULL);
622 if (!res) {
623 g_warning ("Calling CanSuspend failed. Check that ConsoleKit is "
624 "properly installed.");
625 return FALSE;
626 }
627
628 g_variant_get (res, "(s)", &rv);
629 g_variant_unref (res);
630
631 can_suspend = g_strcmp0 (rv, "yes") == 0 ||
632 g_strcmp0 (rv, "challenge") == 0;
633
634 g_free (rv);
635
636 return can_suspend;
637 #endif
638 }
639
640 static gboolean
csm_consolekit_can_hibernate(CsmSystem * system)641 csm_consolekit_can_hibernate (CsmSystem *system)
642 {
643 #ifdef HAVE_OLD_UPOWER
644 CsmConsolekit *consolekit = CSM_CONSOLEKIT (system);
645 return up_client_get_can_hibernate (consolekit->priv->up_client);
646 #else
647 CsmConsolekit *manager = CSM_CONSOLEKIT (system);
648 gchar *rv;
649 GVariant *res;
650 gboolean can_hibernate;
651
652 res = g_dbus_proxy_call_sync (manager->priv->ck_proxy,
653 "CanHibernate",
654 NULL,
655 0,
656 G_MAXINT,
657 NULL,
658 NULL);
659 if (!res) {
660 g_warning ("Calling CanHibernate failed. Check that ConsoleKit is "
661 "properly installed.");
662 return FALSE;
663 }
664
665 g_variant_get (res, "(s)", &rv);
666 g_variant_unref (res);
667
668 can_hibernate = g_strcmp0 (rv, "yes") == 0 ||
669 g_strcmp0 (rv, "challenge") == 0;
670
671 g_free (rv);
672
673 return can_hibernate;
674 #endif
675 }
676
677 static void
suspend_done(GObject * source,GAsyncResult * result,gpointer user_data)678 suspend_done (GObject *source,
679 GAsyncResult *result,
680 gpointer user_data)
681 {
682 GDBusProxy *proxy = G_DBUS_PROXY (source);
683 GError *error = NULL;
684 GVariant *res;
685
686 res = g_dbus_proxy_call_finish (proxy, result, &error);
687
688 if (!res) {
689 g_warning ("Unable to suspend system: %s", error->message);
690 g_error_free (error);
691 } else {
692 g_variant_unref (res);
693 }
694 }
695
696 static void
hibernate_done(GObject * source,GAsyncResult * result,gpointer user_data)697 hibernate_done (GObject *source,
698 GAsyncResult *result,
699 gpointer user_data)
700 {
701 GDBusProxy *proxy = G_DBUS_PROXY (source);
702 GError *error = NULL;
703 GVariant *res;
704
705 res = g_dbus_proxy_call_finish (proxy, result, &error);
706
707 if (!res) {
708 g_warning ("Unable to hibernate system: %s", error->message);
709 g_error_free (error);
710 } else {
711 g_variant_unref (res);
712 }
713 }
714
715 static void
csm_consolekit_suspend(CsmSystem * system,gboolean suspend_then_hibernate)716 csm_consolekit_suspend (CsmSystem *system, gboolean suspend_then_hibernate)
717 {
718 #ifdef HAVE_OLD_UPOWER
719 CsmConsolekit *consolekit = CSM_CONSOLEKIT (system);
720 GError *error = NULL;
721 gboolean ret;
722
723 ret = up_client_suspend_sync (consolekit->priv->up_client, NULL, &error);
724 if (!ret) {
725 g_warning ("Unexpected suspend failure: %s", error->message);
726 g_error_free (error);
727 }
728 #else
729 CsmConsolekit *manager = CSM_CONSOLEKIT (system);
730
731 gchar *method = "Suspend";
732 if (suspend_then_hibernate && csm_consolekit_can_suspend (system) && csm_consolekit_can_hibernate (system)) {
733 method = "SuspendThenHibernate";
734 }
735 g_debug ("Suspend using: %s", method);
736
737 g_dbus_proxy_call (manager->priv->ck_proxy,
738 method,
739 g_variant_new ("(b)", TRUE),
740 0,
741 G_MAXINT,
742 NULL,
743 suspend_done,
744 manager);
745 #endif
746 }
747
748 static void
csm_consolekit_hibernate(CsmSystem * system)749 csm_consolekit_hibernate (CsmSystem *system)
750 {
751 #ifdef HAVE_OLD_UPOWER
752 CsmConsolekit *consolekit = CSM_CONSOLEKIT (system);
753 GError *error = NULL;
754 gboolean ret;
755
756 ret = up_client_hibernate_sync (consolekit->priv->up_client, NULL, &error);
757 if (!ret) {
758 g_warning ("Unexpected hibernate failure: %s", error->message);
759 g_error_free (error);
760 }
761 #else
762 CsmConsolekit *manager = CSM_CONSOLEKIT (system);
763
764 g_dbus_proxy_call (manager->priv->ck_proxy,
765 "Hibernate",
766 g_variant_new ("(b)", TRUE),
767 0,
768 G_MAXINT,
769 NULL,
770 hibernate_done,
771 manager);
772 #endif
773 }
774
775 static void
inhibit_done(GObject * source,GAsyncResult * result,gpointer user_data)776 inhibit_done (GObject *source,
777 GAsyncResult *result,
778 gpointer user_data)
779 {
780 GDBusProxy *proxy = G_DBUS_PROXY (source);
781 CsmConsolekit *manager = CSM_CONSOLEKIT (user_data);
782 GError *error = NULL;
783 GVariant *res;
784 GUnixFDList *fd_list = NULL;
785 gint idx;
786
787 res = g_dbus_proxy_call_with_unix_fd_list_finish (proxy, &fd_list, result, &error);
788
789 if (!res) {
790 g_warning ("Unable to inhibit system: %s", error->message);
791 g_error_free (error);
792 } else {
793 g_variant_get (res, "(h)", &idx);
794 manager->priv->inhibit_fd = g_unix_fd_list_get (fd_list, idx, &error);
795 if (manager->priv->inhibit_fd == -1) {
796 g_warning ("Failed to receive system inhibitor fd: %s", error->message);
797 g_error_free (error);
798 }
799 g_debug ("System inhibitor fd is %d", manager->priv->inhibit_fd);
800 g_object_unref (fd_list);
801 g_variant_unref (res);
802 }
803
804 if (manager->priv->inhibitors == NULL) {
805 drop_system_inhibitor (manager);
806 }
807 }
808
809 static void
csm_consolekit_add_inhibitor(CsmSystem * system,const gchar * id,CsmInhibitorFlag flag)810 csm_consolekit_add_inhibitor (CsmSystem *system,
811 const gchar *id,
812 CsmInhibitorFlag flag)
813 {
814 CsmConsolekit *manager = CSM_CONSOLEKIT (system);
815
816 if ((flag & CSM_INHIBITOR_FLAG_SUSPEND) == 0)
817 return;
818
819 if (manager->priv->inhibitors == NULL) {
820 g_debug ("Adding system inhibitor");
821 g_dbus_proxy_call_with_unix_fd_list (manager->priv->ck_proxy,
822 "Inhibit",
823 g_variant_new ("(ssss)",
824 "sleep:shutdown",
825 g_get_user_name (),
826 "user session inhibited",
827 "block"),
828 0,
829 G_MAXINT,
830 NULL,
831 NULL,
832 inhibit_done,
833 manager);
834 }
835 manager->priv->inhibitors = g_slist_prepend (manager->priv->inhibitors, g_strdup (id));
836 }
837
838 static void
csm_consolekit_remove_inhibitor(CsmSystem * system,const gchar * id)839 csm_consolekit_remove_inhibitor (CsmSystem *system,
840 const gchar *id)
841 {
842 CsmConsolekit *manager = CSM_CONSOLEKIT (system);
843 GSList *l;
844
845 l = g_slist_find_custom (manager->priv->inhibitors, id, (GCompareFunc)g_strcmp0);
846 if (l == NULL)
847 return;
848
849 g_free (l->data);
850 manager->priv->inhibitors = g_slist_delete_link (manager->priv->inhibitors, l);
851 if (manager->priv->inhibitors == NULL) {
852 drop_system_inhibitor (manager);
853 }
854 }
855
856 static gboolean
csm_consolekit_is_last_session_for_user(CsmSystem * system)857 csm_consolekit_is_last_session_for_user (CsmSystem *system)
858 {
859 return FALSE;
860 }
861
862 static void
csm_consolekit_system_init(CsmSystemInterface * iface)863 csm_consolekit_system_init (CsmSystemInterface *iface)
864 {
865 iface->can_switch_user = csm_consolekit_can_switch_user;
866 iface->can_stop = csm_consolekit_can_stop;
867 iface->can_restart = csm_consolekit_can_restart;
868 iface->can_suspend = csm_consolekit_can_suspend;
869 iface->can_hibernate = csm_consolekit_can_hibernate;
870 iface->attempt_stop = csm_consolekit_attempt_stop;
871 iface->attempt_restart = csm_consolekit_attempt_restart;
872 iface->suspend = csm_consolekit_suspend;
873 iface->hibernate = csm_consolekit_hibernate;
874 iface->set_session_idle = csm_consolekit_set_session_idle;
875 iface->is_login_session = csm_consolekit_is_login_session;
876 iface->add_inhibitor = csm_consolekit_add_inhibitor;
877 iface->remove_inhibitor = csm_consolekit_remove_inhibitor;
878 iface->is_last_session_for_user = csm_consolekit_is_last_session_for_user;
879 }
880
881 CsmConsolekit *
csm_consolekit_new(void)882 csm_consolekit_new (void)
883 {
884 CsmConsolekit *manager;
885
886 manager = g_object_new (CSM_TYPE_CONSOLEKIT, NULL);
887
888 return manager;
889 }
890
891 static void
ck_proxy_signal_cb(GDBusProxy * proxy,const gchar * sender_name,const gchar * signal_name,GVariant * parameters,gpointer user_data)892 ck_proxy_signal_cb (GDBusProxy *proxy,
893 const gchar *sender_name,
894 const gchar *signal_name,
895 GVariant *parameters,
896 gpointer user_data)
897 {
898 CsmConsolekit *consolekit = user_data;
899 gboolean is_about_to_shutdown;
900
901 g_debug ("CsmConsolekit: received ConsoleKit signal: %s", signal_name);
902
903 if (g_strcmp0 (signal_name, "PrepareForShutdown") != 0) {
904 g_debug ("CsmConsolekit: ignoring %s signal", signal_name);
905 return;
906 }
907
908 g_variant_get (parameters, "(b)", &is_about_to_shutdown);
909 if (!is_about_to_shutdown) {
910 g_debug ("CsmConsolekit: ignoring %s signal since about-to-shutdown is FALSE", signal_name);
911 return;
912 }
913
914 if (consolekit->priv->prepare_for_shutdown_expected) {
915 g_debug ("CsmConsolekit: shutdown successfully prepared");
916 g_signal_emit_by_name (consolekit, "shutdown-prepared", TRUE);
917 consolekit->priv->prepare_for_shutdown_expected = FALSE;
918 }
919 }
920
921 static void
ck_session_proxy_signal_cb(GDBusProxy * proxy,const gchar * sender_name,const gchar * signal_name,GVariant * parameters,gpointer user_data)922 ck_session_proxy_signal_cb (GDBusProxy *proxy,
923 const gchar *sender_name,
924 const gchar *signal_name,
925 GVariant *parameters,
926 gpointer user_data)
927 {
928 CsmConsolekit *consolekit = user_data;
929 gboolean is_active;
930
931 g_debug ("CsmConsolekit: received ConsoleKit signal: %s", signal_name);
932
933 if (g_strcmp0 (signal_name, "ActiveChanged") != 0) {
934 g_debug ("CsmConsolekit: ignoring %s signal", signal_name);
935 return;
936 }
937
938 g_variant_get (parameters, "(b)", &is_active);
939 if (consolekit->priv->is_active != is_active) {
940 g_debug ("CsmConsolekit: session state changed");
941 consolekit->priv->is_active = is_active;
942 g_object_notify (G_OBJECT (consolekit), "active");
943 }
944 }
945