1 /*
2  * Copyright (C) 2010-2011 Robert Ancell.
3  * Author: Robert Ancell <robert.ancell@canonical.com>
4  *
5  * This library is free software; you can redistribute it and/or modify it under
6  * the terms of the GNU Lesser General Public License as published by the Free
7  * Software Foundation; either version 2 or version 3 of the License.
8  * See http://www.gnu.org/copyleft/lgpl.html the full text of the license.
9  */
10 
11 #include <config.h>
12 
13 #include <string.h>
14 #include <gio/gio.h>
15 
16 #include "lightdm/power.h"
17 
18 /**
19  * SECTION:power
20  * @title: Power Management
21  * @short_description: Shutdown, restart, sleep the system
22  * @include: lightdm.h
23  *
24  * Helper functions to perform power management operations.
25  */
26 
27 static GDBusProxy *upower_proxy = NULL;
28 static GDBusProxy *ck_proxy = NULL;
29 static GDBusProxy *login1_proxy = NULL;
30 
31 static GVariant *
upower_call_function(const gchar * function,GError ** error)32 upower_call_function (const gchar *function, GError **error)
33 {
34     if (!upower_proxy)
35     {
36         upower_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
37                                                       G_DBUS_PROXY_FLAGS_NONE,
38                                                       NULL,
39                                                       "org.freedesktop.UPower",
40                                                       "/org/freedesktop/UPower",
41                                                       "org.freedesktop.UPower",
42                                                       NULL,
43                                                       error);
44         if (!upower_proxy)
45             return NULL;
46     }
47 
48     return g_dbus_proxy_call_sync (upower_proxy,
49                                    function,
50                                    NULL,
51                                    G_DBUS_CALL_FLAGS_NONE,
52                                    -1,
53                                    NULL,
54                                    error);
55 }
56 
57 static GVariant *
login1_call_function(const gchar * function,GVariant * parameters,GError ** error)58 login1_call_function (const gchar *function, GVariant *parameters, GError **error)
59 {
60     if (!login1_proxy)
61     {
62         login1_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
63                                                       G_DBUS_PROXY_FLAGS_NONE,
64                                                       NULL,
65                                                       "org.freedesktop.login1",
66                                                       "/org/freedesktop/login1",
67                                                       "org.freedesktop.login1.Manager",
68                                                       NULL,
69                                                       error);
70         if (!login1_proxy)
71             return NULL;
72     }
73 
74     return g_dbus_proxy_call_sync (login1_proxy,
75                                    function,
76                                    parameters,
77                                    G_DBUS_CALL_FLAGS_NONE,
78                                    -1,
79                                    NULL,
80                                    error);
81 }
82 
83 static GVariant *
ck_call_function(const gchar * function,GVariant * parameters,GError ** error)84 ck_call_function (const gchar *function, GVariant *parameters, GError **error)
85 {
86     if (!ck_proxy)
87     {
88         ck_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
89                                                   G_DBUS_PROXY_FLAGS_NONE,
90                                                   NULL,
91                                                   "org.freedesktop.ConsoleKit",
92                                                   "/org/freedesktop/ConsoleKit/Manager",
93                                                   "org.freedesktop.ConsoleKit.Manager",
94                                                   NULL,
95                                                   error);
96         if (!ck_proxy)
97             return FALSE;
98     }
99 
100     return g_dbus_proxy_call_sync (ck_proxy,
101                                    function,
102                                    parameters,
103                                    G_DBUS_CALL_FLAGS_NONE,
104                                    -1,
105                                    NULL,
106                                    error);
107 }
108 
109 /**
110  * lightdm_get_can_suspend:
111  *
112  * Checks if authorized to do a system suspend.
113  *
114  * Return value: #TRUE if can suspend the system
115  **/
116 gboolean
lightdm_get_can_suspend(void)117 lightdm_get_can_suspend (void)
118 {
119     g_autoptr(GVariant) r = login1_call_function ("CanSuspend", NULL, NULL);
120     gboolean can_suspend = FALSE;
121     if (r)
122     {
123         const gchar *result;
124         if (g_variant_is_of_type (r, G_VARIANT_TYPE ("(s)")))
125         {
126             g_variant_get (r, "(&s)", &result);
127             can_suspend = g_strcmp0 (result, "yes") == 0;
128         }
129     }
130     if (!r)
131     {
132         const gchar *result;
133         r = ck_call_function ("CanSuspend", NULL, NULL);
134         if (r && g_variant_is_of_type (r, G_VARIANT_TYPE ("(s)")))
135         {
136             g_variant_get (r, "(&s)", &result);
137             can_suspend = g_strcmp0 (result, "yes") == 0;
138         }
139     }
140     if (!r)
141     {
142         r = upower_call_function ("SuspendAllowed", NULL);
143         if (r && g_variant_is_of_type (r, G_VARIANT_TYPE ("(b)")))
144             g_variant_get (r, "(b)", &can_suspend);
145     }
146 
147     return can_suspend;
148 }
149 
150 /**
151  * lightdm_suspend:
152  * @error: return location for a #GError, or %NULL
153  *
154  * Triggers a system suspend.
155  *
156  * Return value: #TRUE if suspend initiated.
157  **/
158 gboolean
lightdm_suspend(GError ** error)159 lightdm_suspend (GError **error)
160 {
161     g_autoptr(GError) login1_error = NULL;
162     g_autoptr(GVariant) login1_result = login1_call_function ("Suspend", g_variant_new("(b)", FALSE), &login1_error);
163     if (login1_result)
164         return TRUE;
165 
166     g_debug ("Can't suspend using logind; falling back to ConsoleKit: %s", login1_error->message);
167 
168     g_autoptr(GError) ck_error = NULL;
169     g_autoptr(GVariant) ck_result = ck_call_function ("Suspend", g_variant_new ("(b)", FALSE), &ck_error);
170     if (ck_result)
171         return TRUE;
172 
173     g_debug ("Can't suspend using logind or ConsoleKit; falling back to UPower: %s", ck_error->message);
174 
175     g_autoptr(GVariant) upower_result = upower_call_function ("Suspend", error);
176     return upower_result != NULL;
177 }
178 
179 /**
180  * lightdm_get_can_hibernate:
181  *
182  * Checks if is authorized to do a system hibernate.
183  *
184  * Return value: #TRUE if can hibernate the system
185  **/
186 gboolean
lightdm_get_can_hibernate(void)187 lightdm_get_can_hibernate (void)
188 {
189     g_autoptr(GVariant) r = login1_call_function ("CanHibernate", NULL, NULL);
190     gboolean can_hibernate = FALSE;
191     if (r)
192     {
193         const gchar *result;
194         if (g_variant_is_of_type (r, G_VARIANT_TYPE ("(s)")))
195         {
196             g_variant_get (r, "(&s)", &result);
197             can_hibernate = g_strcmp0 (result, "yes") == 0;
198         }
199     }
200     if (!r)
201     {
202         const gchar *result;
203         r = ck_call_function ("CanHibernate", NULL, NULL);
204         if (r && g_variant_is_of_type (r, G_VARIANT_TYPE ("(s)")))
205         {
206             g_variant_get (r, "(&s)", &result);
207             can_hibernate = g_strcmp0 (result, "yes") == 0;
208         }
209     }
210     if (!r)
211     {
212         r = upower_call_function ("HibernateAllowed", NULL);
213         if (r && g_variant_is_of_type (r, G_VARIANT_TYPE ("(b)")))
214             g_variant_get (r, "(b)", &can_hibernate);
215     }
216 
217     return can_hibernate;
218 }
219 
220 /**
221  * lightdm_hibernate:
222  * @error: return location for a #GError, or %NULL
223  *
224  * Triggers a system hibernate.
225  *
226  * Return value: #TRUE if hibernate initiated.
227  **/
228 gboolean
lightdm_hibernate(GError ** error)229 lightdm_hibernate (GError **error)
230 {
231     g_autoptr(GError) login1_error = NULL;
232     g_autoptr(GVariant) login1_result = login1_call_function ("Hibernate", g_variant_new("(b)", FALSE), &login1_error);
233     if (login1_result)
234         return TRUE;
235 
236     g_debug ("Can't hibernate using logind; falling back to ConsoleKit: %s", login1_error->message);
237 
238     g_autoptr(GError) ck_error = NULL;
239     g_autoptr(GVariant) ck_result = ck_call_function ("Hibernate", g_variant_new ("(b)", FALSE), &ck_error);
240     if (ck_result)
241         return TRUE;
242 
243     g_debug ("Can't hibernate using logind or ConsoleKit; falling back to UPower: %s", ck_error->message);
244 
245     g_autoptr(GVariant) upower_result = upower_call_function ("Hibernate", error);
246     return upower_result != NULL;
247 }
248 
249 /**
250  * lightdm_get_can_restart:
251  *
252  * Checks if is authorized to do a system restart.
253  *
254  * Return value: #TRUE if can restart the system
255  **/
256 gboolean
lightdm_get_can_restart(void)257 lightdm_get_can_restart (void)
258 {
259     g_autoptr(GVariant) r = login1_call_function ("CanReboot", NULL, NULL);
260     gboolean can_restart = FALSE;
261     if (r)
262     {
263         const gchar *result;
264         if (g_variant_is_of_type (r, G_VARIANT_TYPE ("(s)")))
265         {
266             g_variant_get (r, "(&s)", &result);
267             can_restart = g_strcmp0 (result, "yes") == 0;
268         }
269     }
270     else
271     {
272         r = ck_call_function ("CanRestart", NULL, NULL);
273         if (r && g_variant_is_of_type (r, G_VARIANT_TYPE ("(b)")))
274             g_variant_get (r, "(b)", &can_restart);
275     }
276 
277     return can_restart;
278 }
279 
280 /**
281  * lightdm_restart:
282  * @error: return location for a #GError, or %NULL
283  *
284  * Triggers a system restart.
285  *
286  * Return value: #TRUE if restart initiated.
287  **/
288 gboolean
lightdm_restart(GError ** error)289 lightdm_restart (GError **error)
290 {
291     g_autoptr(GError) login1_error = NULL;
292     g_autoptr(GVariant) login1_result = login1_call_function ("Reboot", g_variant_new("(b)", FALSE), &login1_error);
293     if (login1_result)
294         return TRUE;
295 
296     g_autoptr(GVariant) ck_result = ck_call_function ("Restart", NULL, error);
297     return ck_result != NULL;
298 }
299 
300 /**
301  * lightdm_get_can_shutdown:
302  *
303  * Checks if is authorized to do a system shutdown.
304  *
305  * Return value: #TRUE if can shutdown the system
306  **/
307 gboolean
lightdm_get_can_shutdown(void)308 lightdm_get_can_shutdown (void)
309 {
310     g_autoptr(GVariant) r = login1_call_function ("CanPowerOff", NULL, NULL);
311     gboolean can_shutdown = FALSE;
312     if (r)
313     {
314         const gchar *result;
315         if (g_variant_is_of_type (r, G_VARIANT_TYPE ("(s)")))
316         {
317             g_variant_get (r, "(&s)", &result);
318             can_shutdown = g_strcmp0 (result, "yes") == 0;
319         }
320     }
321     else
322     {
323         r = ck_call_function ("CanStop", NULL, NULL);
324         if (r && g_variant_is_of_type (r, G_VARIANT_TYPE ("(b)")))
325             g_variant_get (r, "(b)", &can_shutdown);
326     }
327 
328     return can_shutdown;
329 }
330 
331 /**
332  * lightdm_shutdown:
333  * @error: return location for a #GError, or %NULL
334  *
335  * Triggers a system shutdown.
336  *
337  * Return value: #TRUE if shutdown initiated.
338  **/
339 gboolean
lightdm_shutdown(GError ** error)340 lightdm_shutdown (GError **error)
341 {
342     g_autoptr(GError) login1_error = NULL;
343     g_autoptr(GVariant) login1_result = login1_call_function ("PowerOff", g_variant_new("(b)", FALSE), &login1_error);
344     if (login1_result)
345         return TRUE;
346 
347     g_autoptr(GVariant) ck_result = ck_call_function ("Stop", NULL, error);
348     return ck_result != NULL;
349 }
350