device: renew dhcp leases on awake for software devices
[NetworkManager.git] / src / nm-sleep-monitor-systemd.c
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2 /* This program is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 2 of the License, or
5  * (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License along
13  * with this program; if not, write to the Free Software Foundation, Inc.,
14  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
15  *
16  * (C) Copyright 2012 Red Hat, Inc.
17  * Author: Matthias Clasen <mclasen@redhat.com>
18  */
19
20 #include "nm-default.h"
21
22 #include <errno.h>
23 #include <string.h>
24 #include <sys/stat.h>
25 #include <gio/gunixfdlist.h>
26
27 #include "nm-core-internal.h"
28 #include "NetworkManagerUtils.h"
29
30 #include "nm-sleep-monitor.h"
31
32 #if defined (SUSPEND_RESUME_SYSTEMD) == defined (SUSPEND_RESUME_CONSOLEKIT)
33 #error either define SUSPEND_RESUME_SYSTEMD or SUSPEND_RESUME_CONSOLEKIT
34 #endif
35
36 #ifdef SUSPEND_RESUME_SYSTEMD
37
38 #define SUSPEND_DBUS_NAME               "org.freedesktop.login1"
39 #define SUSPEND_DBUS_PATH               "/org/freedesktop/login1"
40 #define SUSPEND_DBUS_INTERFACE          "org.freedesktop.login1.Manager"
41
42 #else
43
44 /* ConsoleKit2 has added the same suspend/resume DBUS API that Systemd
45  * uses. http://consolekit2.github.io/ConsoleKit2/#Manager.Inhibit
46  */
47
48 #define SUSPEND_DBUS_NAME               "org.freedesktop.ConsoleKit"
49 #define SUSPEND_DBUS_PATH               "/org/freedesktop/ConsoleKit/Manager"
50 #define SUSPEND_DBUS_INTERFACE          "org.freedesktop.ConsoleKit.Manager"
51
52 #endif
53
54 struct _NMSleepMonitor {
55         GObject parent_instance;
56
57         GDBusProxy *sd_proxy;
58         gint inhibit_fd;
59 };
60
61 struct _NMSleepMonitorClass {
62         GObjectClass parent_class;
63
64         void (*sleeping) (NMSleepMonitor *monitor);
65         void (*resuming) (NMSleepMonitor *monitor);
66 };
67
68
69 enum {
70         SLEEPING,
71         RESUMING,
72         LAST_SIGNAL,
73 };
74 static guint signals[LAST_SIGNAL] = {0};
75
76 G_DEFINE_TYPE (NMSleepMonitor, nm_sleep_monitor, G_TYPE_OBJECT);
77
78 /********************************************************************/
79
80 static gboolean
81 drop_inhibitor (NMSleepMonitor *self)
82 {
83         if (self->inhibit_fd >= 0) {
84                 nm_log_dbg (LOGD_SUSPEND, "Dropping systemd sleep inhibitor");
85                 close (self->inhibit_fd);
86                 self->inhibit_fd = -1;
87                 return TRUE;
88         }
89         return FALSE;
90 }
91
92 static void
93 inhibit_done (GObject      *source,
94               GAsyncResult *result,
95               gpointer      user_data)
96 {
97         GDBusProxy *sd_proxy = G_DBUS_PROXY (source);
98         NMSleepMonitor *self = user_data;
99         GError *error = NULL;
100         GVariant *res;
101         GUnixFDList *fd_list;
102
103         res = g_dbus_proxy_call_with_unix_fd_list_finish (sd_proxy, &fd_list, result, &error);
104         if (!res) {
105                 g_dbus_error_strip_remote_error (error);
106                 nm_log_warn (LOGD_SUSPEND, "Inhibit failed: %s", error->message);
107                 g_error_free (error);
108         } else {
109                 if (!fd_list || g_unix_fd_list_get_length (fd_list) != 1)
110                         nm_log_warn (LOGD_SUSPEND, "Didn't get a single fd back");
111
112                 self->inhibit_fd = g_unix_fd_list_get (fd_list, 0, NULL);
113
114                 nm_log_dbg (LOGD_SUSPEND, "Inhibitor fd is %d", self->inhibit_fd);
115                 g_object_unref (fd_list);
116                 g_variant_unref (res);
117         }
118 }
119
120 static void
121 take_inhibitor (NMSleepMonitor *self)
122 {
123         g_assert (self->inhibit_fd == -1);
124
125         nm_log_dbg (LOGD_SUSPEND, "Taking systemd sleep inhibitor");
126         g_dbus_proxy_call_with_unix_fd_list (self->sd_proxy,
127                                              "Inhibit",
128                                              g_variant_new ("(ssss)",
129                                                             "sleep",
130                                                             "NetworkManager",
131                                                             _("NetworkManager needs to turn off networks"),
132                                                             "delay"),
133                                              0,
134                                              G_MAXINT,
135                                              NULL,
136                                              NULL,
137                                              inhibit_done,
138                                              self);
139 }
140
141 static void
142 prepare_for_sleep_cb (GDBusProxy  *proxy,
143                       gboolean     is_about_to_suspend,
144                       gpointer     data)
145 {
146         NMSleepMonitor *self = data;
147
148         nm_log_dbg (LOGD_SUSPEND, "Received PrepareForSleep signal: %d", is_about_to_suspend);
149
150         if (is_about_to_suspend) {
151                 g_signal_emit (self, signals[SLEEPING], 0);
152                 drop_inhibitor (self);
153         } else {
154                 take_inhibitor (self);
155                 g_signal_emit (self, signals[RESUMING], 0);
156         }
157 }
158
159 static void
160 name_owner_cb (GObject    *object,
161                GParamSpec *pspec,
162                gpointer    user_data)
163 {
164         GDBusProxy *proxy = G_DBUS_PROXY (object);
165         NMSleepMonitor *self = NM_SLEEP_MONITOR (user_data);
166         char *owner;
167
168         g_assert (proxy == self->sd_proxy);
169
170         owner = g_dbus_proxy_get_name_owner (proxy);
171         if (owner)
172                 take_inhibitor (self);
173         else
174                 drop_inhibitor (self);
175         g_free (owner);
176 }
177
178 static void
179 on_proxy_acquired (GObject *object,
180                    GAsyncResult *res,
181                    NMSleepMonitor *self)
182 {
183         GError *error = NULL;
184         char *owner;
185
186         self->sd_proxy = g_dbus_proxy_new_for_bus_finish (res, &error);
187         if (!self->sd_proxy) {
188                 nm_log_warn (LOGD_SUSPEND, "Failed to acquire logind proxy: %s", error->message);
189                 g_clear_error (&error);
190                 return;
191         }
192
193         g_signal_connect (self->sd_proxy, "notify::g-name-owner", G_CALLBACK (name_owner_cb), self);
194         _nm_dbus_signal_connect (self->sd_proxy, "PrepareForSleep", G_VARIANT_TYPE ("(b)"),
195                                  G_CALLBACK (prepare_for_sleep_cb), self);
196
197         owner = g_dbus_proxy_get_name_owner (self->sd_proxy);
198         if (owner)
199                 take_inhibitor (self);
200         g_free (owner);
201 }
202
203 static void
204 nm_sleep_monitor_init (NMSleepMonitor *self)
205 {
206         self->inhibit_fd = -1;
207         g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
208                                   G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START |
209                                   G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
210                                   NULL,
211                                   SUSPEND_DBUS_NAME, SUSPEND_DBUS_PATH, SUSPEND_DBUS_INTERFACE,
212                                   NULL,
213                                   (GAsyncReadyCallback) on_proxy_acquired, self);
214 }
215
216 static void
217 finalize (GObject *object)
218 {
219         NMSleepMonitor *self = NM_SLEEP_MONITOR (object);
220
221         drop_inhibitor (self);
222         if (self->sd_proxy)
223                 g_object_unref (self->sd_proxy);
224
225         if (G_OBJECT_CLASS (nm_sleep_monitor_parent_class)->finalize != NULL)
226                 G_OBJECT_CLASS (nm_sleep_monitor_parent_class)->finalize (object);
227 }
228
229 static void
230 nm_sleep_monitor_class_init (NMSleepMonitorClass *klass)
231 {
232         GObjectClass *gobject_class;
233
234         gobject_class = G_OBJECT_CLASS (klass);
235
236         gobject_class->finalize = finalize;
237
238         signals[SLEEPING] = g_signal_new (NM_SLEEP_MONITOR_SLEEPING,
239                                           NM_TYPE_SLEEP_MONITOR,
240                                           G_SIGNAL_RUN_LAST,
241                                           G_STRUCT_OFFSET (NMSleepMonitorClass, sleeping),
242                                           NULL,                   /* accumulator      */
243                                           NULL,                   /* accumulator data */
244                                           g_cclosure_marshal_VOID__VOID,
245                                           G_TYPE_NONE, 0);
246         signals[RESUMING] = g_signal_new (NM_SLEEP_MONITOR_RESUMING,
247                                           NM_TYPE_SLEEP_MONITOR,
248                                           G_SIGNAL_RUN_LAST,
249                                           G_STRUCT_OFFSET (NMSleepMonitorClass, resuming),
250                                           NULL,                   /* accumulator      */
251                                           NULL,                   /* accumulator data */
252                                           g_cclosure_marshal_VOID__VOID,
253                                           G_TYPE_NONE, 0);
254 }
255
256 NM_DEFINE_SINGLETON_GETTER (NMSleepMonitor, nm_sleep_monitor_get, NM_TYPE_SLEEP_MONITOR);
257
258 /* ---------------------------------------------------------------------------------------------------- */