]>
Commit | Line | Data |
---|---|---|
b761b8be ŁK |
1 | diff -u -Nr NetworkManager-0.9.3.995/configure.ac NetworkManager-0.9.3.995-systemd-fallback/configure.ac |
2 | --- NetworkManager-0.9.3.995/configure.ac 2012-03-02 01:05:21.000000000 +0100 | |
3 | +++ NetworkManager-0.9.3.995-systemd-fallback/configure.ac 2012-03-06 16:55:58.294793902 +0100 | |
4 | @@ -344,7 +344,7 @@ | |
5 | case $with_session_tracking in | |
6 | ck|none) ;; | |
7 | systemd) | |
8 | - PKG_CHECK_MODULES(SYSTEMD, [libsystemd-login]) | |
9 | + PKG_CHECK_MODULES(SYSTEMD, [libsystemd-daemon libsystemd-login]) | |
10 | ;; | |
11 | *) | |
12 | AC_MSG_ERROR(--with-session-tracking must be one of [none, ck, systemd]) | |
13 | diff -u -Nr NetworkManager-0.9.3.995/src/nm-session-monitor-systemd.c NetworkManager-0.9.3.995-systemd-fallback/src/nm-session-monitor-systemd.c | |
14 | --- NetworkManager-0.9.3.995/src/nm-session-monitor-systemd.c 2012-02-27 16:57:16.000000000 +0100 | |
15 | +++ NetworkManager-0.9.3.995-systemd-fallback/src/nm-session-monitor-systemd.c 2012-03-06 16:55:01.285264295 +0100 | |
16 | @@ -28,6 +28,10 @@ | |
17 | #include <glib/gstdio.h> | |
18 | #include <systemd/sd-login.h> | |
19 | #include <stdlib.h> | |
20 | +#include <systemd/sd-daemon.h> | |
21 | +#include <sys/stat.h> | |
22 | +#include <gio/gio.h> | |
23 | +#include "nm-logging.h" | |
24 | ||
25 | #include "nm-session-utils.h" | |
26 | #include "nm-session-monitor.h" | |
27 | @@ -107,10 +111,20 @@ | |
28 | return source; | |
29 | } | |
30 | ||
31 | +/********************************************************************/ | |
32 | + | |
33 | +#define CKDB_PATH "/var/run/ConsoleKit/database" | |
34 | + | |
35 | struct _NMSessionMonitor { | |
36 | GObject parent_instance; | |
37 | ||
38 | GSource *sd_source; | |
39 | + | |
40 | + GKeyFile *database; | |
41 | + GFileMonitor *database_monitor; | |
42 | + time_t database_mtime; | |
43 | + GHashTable *sessions_by_uid; | |
44 | + GHashTable *sessions_by_user; | |
45 | }; | |
46 | ||
47 | struct _NMSessionMonitorClass { | |
48 | @@ -130,6 +144,215 @@ | |
49 | ||
50 | /* ---------------------------------------------------------------------------------------------------- */ | |
51 | ||
52 | +typedef struct { | |
53 | + char *user; | |
54 | + uid_t uid; | |
55 | + gboolean local; | |
56 | + gboolean active; | |
57 | +} Session; | |
58 | + | |
59 | +static void | |
60 | +session_free (Session *s) | |
61 | +{ | |
62 | + g_free (s->user); | |
63 | + memset (s, 0, sizeof (Session)); | |
64 | + g_free (s); | |
65 | +} | |
66 | + | |
67 | +static gboolean | |
68 | +check_key (GKeyFile *keyfile, const char *group, const char *key, GError **error) | |
69 | +{ | |
70 | + if (g_key_file_has_key (keyfile, group, key, error)) | |
71 | + return TRUE; | |
72 | + | |
73 | + if (!error) { | |
74 | + g_set_error (error, | |
75 | + NM_SESSION_MONITOR_ERROR, | |
76 | + NM_SESSION_MONITOR_ERROR_MALFORMED_DATABASE, | |
77 | + "ConsoleKit database " CKDB_PATH " group '%s' had no '%s' key", | |
78 | + group, key); | |
79 | + } | |
80 | + return FALSE; | |
81 | +} | |
82 | + | |
83 | +static Session * | |
84 | +session_new (GKeyFile *keyfile, const char *group, GError **error) | |
85 | +{ | |
86 | + GError *local = NULL; | |
87 | + Session *s; | |
88 | + const char *uname = NULL; | |
89 | + | |
90 | + s = g_new0 (Session, 1); | |
91 | + g_assert (s); | |
92 | + | |
93 | + s->uid = G_MAXUINT; /* paranoia */ | |
94 | + if (!check_key (keyfile, group, "uid", &local)) | |
95 | + goto error; | |
96 | + s->uid = (uid_t) g_key_file_get_integer (keyfile, group, "uid", &local); | |
97 | + if (local) | |
98 | + goto error; | |
99 | + | |
100 | + if (!check_key (keyfile, group, "is_active", &local)) | |
101 | + goto error; | |
102 | + s->active = g_key_file_get_boolean (keyfile, group, "is_active", &local); | |
103 | + if (local) | |
104 | + goto error; | |
105 | + | |
106 | + if (!check_key (keyfile, group, "is_local", &local)) | |
107 | + goto error; | |
108 | + s->local = g_key_file_get_boolean (keyfile, group, "is_local", &local); | |
109 | + if (local) | |
110 | + goto error; | |
111 | + | |
112 | + if (!nm_session_uid_to_user (s->uid, &uname, error)) | |
113 | + return FALSE; | |
114 | + s->user = g_strdup (uname); | |
115 | + | |
116 | + return s; | |
117 | + | |
118 | +error: | |
119 | + session_free (s); | |
120 | + g_propagate_error (error, local); | |
121 | + return NULL; | |
122 | +} | |
123 | + | |
124 | +static void | |
125 | +session_merge (Session *src, Session *dest) | |
126 | +{ | |
127 | + g_return_if_fail (src != NULL); | |
128 | + g_return_if_fail (dest != NULL); | |
129 | + | |
130 | + g_warn_if_fail (g_strcmp0 (src->user, dest->user) == 0); | |
131 | + g_warn_if_fail (src->uid == dest->uid); | |
132 | + | |
133 | + dest->local = (dest->local || src->local); | |
134 | + dest->active = (dest->active || src->active); | |
135 | +} | |
136 | + | |
137 | +/********************************************************************/ | |
138 | + | |
139 | +static void | |
140 | +free_database (NMSessionMonitor *self) | |
141 | +{ | |
142 | + if (self->database != NULL) { | |
143 | + g_key_file_free (self->database); | |
144 | + self->database = NULL; | |
145 | + } | |
146 | + | |
147 | + g_hash_table_remove_all (self->sessions_by_uid); | |
148 | + g_hash_table_remove_all (self->sessions_by_user); | |
149 | +} | |
150 | + | |
151 | +static gboolean | |
152 | +reload_database (NMSessionMonitor *self, GError **error) | |
153 | +{ | |
154 | + struct stat statbuf; | |
155 | + char **groups = NULL; | |
156 | + gsize len = 0, i; | |
157 | + Session *s; | |
158 | + | |
159 | + free_database (self); | |
160 | + | |
161 | + errno = 0; | |
162 | + if (stat (CKDB_PATH, &statbuf) != 0) { | |
163 | + g_set_error (error, | |
164 | + NM_SESSION_MONITOR_ERROR, | |
165 | + errno == ENOENT ? NM_SESSION_MONITOR_ERROR_NO_DATABASE : NM_SESSION_MONITOR_ERROR_IO_ERROR, | |
166 | + "Error statting file " CKDB_PATH ": %s", | |
167 | + strerror (errno)); | |
168 | + goto error; | |
169 | + } | |
170 | + self->database_mtime = statbuf.st_mtime; | |
171 | + | |
172 | + self->database = g_key_file_new (); | |
173 | + if (!g_key_file_load_from_file (self->database, CKDB_PATH, G_KEY_FILE_NONE, error)) | |
174 | + goto error; | |
175 | + | |
176 | + groups = g_key_file_get_groups (self->database, &len); | |
177 | + if (!groups) { | |
178 | + g_set_error_literal (error, | |
179 | + NM_SESSION_MONITOR_ERROR, | |
180 | + NM_SESSION_MONITOR_ERROR_IO_ERROR, | |
181 | + "Could not load groups from " CKDB_PATH ""); | |
182 | + goto error; | |
183 | + } | |
184 | + | |
185 | + for (i = 0; i < len; i++) { | |
186 | + Session *found; | |
187 | + | |
188 | + if (!g_str_has_prefix (groups[i], "Session ")) | |
189 | + continue; | |
190 | + | |
191 | + s = session_new (self->database, groups[i], error); | |
192 | + if (!s) | |
193 | + goto error; | |
194 | + | |
195 | + found = g_hash_table_lookup (self->sessions_by_user, (gpointer) s->user); | |
196 | + if (found) { | |
197 | + session_merge (s, found); | |
198 | + session_free (s); | |
199 | + } else { | |
200 | + /* Entirely new user */ | |
201 | + g_hash_table_insert (self->sessions_by_user, (gpointer) s->user, s); | |
202 | + g_hash_table_insert (self->sessions_by_uid, GUINT_TO_POINTER (s->uid), s); | |
203 | + } | |
204 | + } | |
205 | + | |
206 | + g_strfreev (groups); | |
207 | + return TRUE; | |
208 | + | |
209 | +error: | |
210 | + if (groups) | |
211 | + g_strfreev (groups); | |
212 | + free_database (self); | |
213 | + return FALSE; | |
214 | +} | |
215 | + | |
216 | +static gboolean | |
217 | +ensure_database (NMSessionMonitor *self, GError **error) | |
218 | +{ | |
219 | + gboolean ret = FALSE; | |
220 | + | |
221 | + if (self->database != NULL) { | |
222 | + struct stat statbuf; | |
223 | + | |
224 | + errno = 0; | |
225 | + if (stat (CKDB_PATH, &statbuf) != 0) { | |
226 | + g_set_error (error, | |
227 | + NM_SESSION_MONITOR_ERROR, | |
228 | + errno == ENOENT ? NM_SESSION_MONITOR_ERROR_NO_DATABASE : NM_SESSION_MONITOR_ERROR_IO_ERROR, | |
229 | + "Error statting file " CKDB_PATH " to check timestamp: %s", | |
230 | + strerror (errno)); | |
231 | + goto out; | |
232 | + } | |
233 | + | |
234 | + if (statbuf.st_mtime == self->database_mtime) { | |
235 | + ret = TRUE; | |
236 | + goto out; | |
237 | + } | |
238 | + } | |
239 | + | |
240 | + ret = reload_database (self, error); | |
241 | + | |
242 | +out: | |
243 | + return ret; | |
244 | +} | |
245 | + | |
246 | +static void | |
247 | +on_file_monitor_changed (GFileMonitor * file_monitor, | |
248 | + GFile * file, | |
249 | + GFile * other_file, | |
250 | + GFileMonitorEvent event_type, | |
251 | + gpointer user_data) | |
252 | +{ | |
253 | + NMSessionMonitor *self = NM_SESSION_MONITOR (user_data); | |
254 | + | |
255 | + /* throw away cache */ | |
256 | + free_database (self); | |
257 | + | |
258 | + g_signal_emit (self, signals[CHANGED_SIGNAL], 0); | |
259 | +} | |
260 | + | |
261 | static gboolean | |
262 | sessions_changed (gpointer user_data) | |
263 | { | |
264 | @@ -143,9 +366,50 @@ | |
265 | static void | |
266 | nm_session_monitor_init (NMSessionMonitor *monitor) | |
267 | { | |
268 | - monitor->sd_source = sd_source_new (); | |
269 | - g_source_set_callback (monitor->sd_source, sessions_changed, monitor, NULL); | |
270 | - g_source_attach (monitor->sd_source, NULL); | |
271 | + if (sd_booted () > 0) { | |
272 | + monitor->sd_source = sd_source_new (); | |
273 | + g_source_set_callback (monitor->sd_source, sessions_changed, monitor, NULL); | |
274 | + g_source_attach (monitor->sd_source, NULL); | |
275 | + | |
276 | + monitor->database_monitor = NULL; | |
277 | + monitor->database = NULL; | |
278 | + } else { | |
279 | + monitor->sd_source = NULL; | |
280 | + | |
281 | + GError *error = NULL; | |
282 | + GFile *file; | |
283 | + | |
284 | + /* Sessions-by-user is responsible for destroying the Session objects */ | |
285 | + monitor->sessions_by_user = g_hash_table_new_full (g_str_hash, g_str_equal, | |
286 | + NULL, (GDestroyNotify) session_free); | |
287 | + monitor->sessions_by_uid = g_hash_table_new (g_direct_hash, g_direct_equal); | |
288 | + | |
289 | + | |
290 | + error = NULL; | |
291 | + if (!ensure_database (monitor, &error)) { | |
292 | + /* Ignore the first error if the CK database isn't found yet */ | |
293 | + if (g_error_matches (error, | |
294 | + NM_SESSION_MONITOR_ERROR, | |
295 | + NM_SESSION_MONITOR_ERROR_NO_DATABASE) == FALSE) { | |
296 | + nm_log_err (LOGD_CORE, "Error loading " CKDB_PATH ": %s", error->message); | |
297 | + } | |
298 | + g_error_free (error); | |
299 | + } | |
300 | + | |
301 | + error = NULL; | |
302 | + file = g_file_new_for_path (CKDB_PATH); | |
303 | + monitor->database_monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, &error); | |
304 | + g_object_unref (file); | |
305 | + if (monitor->database_monitor == NULL) { | |
306 | + nm_log_err (LOGD_CORE, "Error monitoring " CKDB_PATH ": %s", error->message); | |
307 | + g_error_free (error); | |
308 | + } else { | |
309 | + g_signal_connect (monitor->database_monitor, | |
310 | + "changed", | |
311 | + G_CALLBACK (on_file_monitor_changed), | |
312 | + monitor); | |
313 | + } | |
314 | + } | |
315 | } | |
316 | ||
317 | static void | |
318 | @@ -158,6 +422,12 @@ | |
319 | g_source_unref (monitor->sd_source); | |
320 | } | |
321 | ||
322 | + if (monitor->database_monitor != NULL) | |
323 | + g_object_unref (monitor->database_monitor); | |
324 | + | |
325 | + if (monitor->database != NULL) | |
326 | + free_database (monitor); | |
327 | + | |
328 | if (G_OBJECT_CLASS (nm_session_monitor_parent_class)->finalize != NULL) | |
329 | G_OBJECT_CLASS (nm_session_monitor_parent_class)->finalize (object); | |
330 | } | |
331 | @@ -206,15 +476,36 @@ | |
332 | uid_t *out_uid, | |
333 | GError **error) | |
334 | { | |
335 | - uid_t uid; | |
336 | + if (monitor->sd_source != NULL) { | |
337 | + uid_t uid; | |
338 | ||
339 | - if (!nm_session_user_to_uid (username, &uid, error)) | |
340 | - return FALSE; | |
341 | + if (!nm_session_user_to_uid (username, &uid, error)) | |
342 | + return FALSE; | |
343 | ||
344 | - if (out_uid) | |
345 | - *out_uid = uid; | |
346 | + if (out_uid) | |
347 | + *out_uid = uid; | |
348 | ||
349 | - return nm_session_monitor_uid_has_session (monitor, uid, NULL, error); | |
350 | + return nm_session_monitor_uid_has_session (monitor, uid, NULL, error); | |
351 | + } else { | |
352 | + Session *s; | |
353 | + | |
354 | + if (!ensure_database (monitor, error)) | |
355 | + return FALSE; | |
356 | + | |
357 | + s = g_hash_table_lookup (monitor->sessions_by_user, (gpointer) username); | |
358 | + if (!s) { | |
359 | + g_set_error (error, | |
360 | + NM_SESSION_MONITOR_ERROR, | |
361 | + NM_SESSION_MONITOR_ERROR_UNKNOWN_USER, | |
362 | + "No session found for user '%s'", | |
363 | + username); | |
364 | + return FALSE; | |
365 | + } | |
366 | + | |
367 | + if (out_uid) | |
368 | + *out_uid = s->uid; | |
369 | + return TRUE; | |
370 | + } | |
371 | } | |
372 | ||
373 | gboolean | |
374 | @@ -222,12 +513,31 @@ | |
375 | const char *username, | |
376 | GError **error) | |
377 | { | |
378 | - uid_t uid; | |
379 | + if (monitor->sd_source != NULL) { | |
380 | + uid_t uid; | |
381 | ||
382 | - if (!nm_session_user_to_uid (username, &uid, error)) | |
383 | - return FALSE; | |
384 | + if (!nm_session_user_to_uid (username, &uid, error)) | |
385 | + return FALSE; | |
386 | + | |
387 | + return nm_session_monitor_uid_active (monitor, uid, error); | |
388 | + } else { | |
389 | + Session *s; | |
390 | + | |
391 | + if (!ensure_database (monitor, error)) | |
392 | + return FALSE; | |
393 | + | |
394 | + s = g_hash_table_lookup (monitor->sessions_by_user, (gpointer) username); | |
395 | + if (!s) { | |
396 | + g_set_error (error, | |
397 | + NM_SESSION_MONITOR_ERROR, | |
398 | + NM_SESSION_MONITOR_ERROR_UNKNOWN_USER, | |
399 | + "No session found for user '%s'", | |
400 | + username); | |
401 | + return FALSE; | |
402 | + } | |
403 | ||
404 | - return nm_session_monitor_uid_active (monitor, uid, error); | |
405 | + return s->active; | |
406 | + } | |
407 | } | |
408 | ||
409 | gboolean | |
410 | @@ -236,10 +546,31 @@ | |
411 | const char **out_user, | |
412 | GError **error) | |
413 | { | |
414 | - if (!nm_session_uid_to_user (uid, out_user, error)) | |
415 | - return FALSE; | |
416 | + if (monitor->sd_source != NULL) { | |
417 | + if (!nm_session_uid_to_user (uid, out_user, error)) | |
418 | + return FALSE; | |
419 | ||
420 | - return sd_uid_get_sessions (uid, FALSE, NULL) > 0; | |
421 | + return sd_uid_get_sessions (uid, FALSE, NULL) > 0; | |
422 | + } else { | |
423 | + Session *s; | |
424 | + | |
425 | + if (!ensure_database (monitor, error)) | |
426 | + return FALSE; | |
427 | + | |
428 | + s = g_hash_table_lookup (monitor->sessions_by_uid, GUINT_TO_POINTER (uid)); | |
429 | + if (!s) { | |
430 | + g_set_error (error, | |
431 | + NM_SESSION_MONITOR_ERROR, | |
432 | + NM_SESSION_MONITOR_ERROR_UNKNOWN_USER, | |
433 | + "No session found for uid %d", | |
434 | + uid); | |
435 | + return FALSE; | |
436 | + } | |
437 | + | |
438 | + if (out_user) | |
439 | + *out_user = s->user; | |
440 | + return TRUE; | |
441 | + } | |
442 | } | |
443 | ||
444 | gboolean | |
445 | @@ -247,5 +578,24 @@ | |
446 | uid_t uid, | |
447 | GError **error) | |
448 | { | |
449 | - return sd_uid_get_sessions (uid, TRUE, NULL) > 0; | |
450 | + if (monitor->sd_source != NULL) | |
451 | + return sd_uid_get_sessions (uid, TRUE, NULL) > 0; | |
452 | + else { | |
453 | + Session *s; | |
454 | + | |
455 | + if (!ensure_database (monitor, error)) | |
456 | + return FALSE; | |
457 | + | |
458 | + s = g_hash_table_lookup (monitor->sessions_by_uid, GUINT_TO_POINTER (uid)); | |
459 | + if (!s) { | |
460 | + g_set_error (error, | |
461 | + NM_SESSION_MONITOR_ERROR, | |
462 | + NM_SESSION_MONITOR_ERROR_UNKNOWN_USER, | |
463 | + "No session found for uid '%d'", | |
464 | + uid); | |
465 | + return FALSE; | |
466 | + } | |
467 | + | |
468 | + return s->active; | |
469 | + } | |
470 | } |