From 860d1cf3a76701ade38784822abb24285176227c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 17 Mar 2012 01:52:41 +0100 Subject: [PATCH 01/47] systemd: complement module-console-kit with module-systemd-login ConsoleKit has been deprecated and replaced by systemd's logind daemon, hence provide the same functionality of module-console-kit in module-systemd-login. This also makes sure that the CK module becomes a NOP if the system is booted with systemd, resp. that the systemd module becomes a NOP if the system is booted without systemd, thus being nice to OSes such as Debian which want to support multiple init systems. --- configure.ac | 18 +++ src/Makefile.am | 15 ++- src/daemon/default.pa.in | 3 + src/modules/module-console-kit.c | 12 ++ src/modules/module-systemd-login.c | 243 ++++++++++++++++++++++++++++++++++++ 5 files changed, 289 insertions(+), 2 deletions(-) create mode 100644 src/modules/module-systemd-login.c diff --git a/configure.ac b/configure.ac index 8d7f43a..7bdd401 100644 --- a/configure.ac +++ b/configure.ac @@ -1108,6 +1108,22 @@ AM_CONDITIONAL([HAVE_XEN], [test "x$HAVE_XEN" = x1]) ORC_CHECK([0.4.11]) +#### systemd support (optional) #### + +AC_ARG_ENABLE([systemd], + AS_HELP_STRING([--disable-systemd],[Disable optional systemd support])) + +AS_IF([test "x$enable_systemd" != "xno"], + [PKG_CHECK_MODULES(SYSTEMD, [ libsystemd-login libsystemd-daemon ], HAVE_SYSTEMD=1, HAVE_SYSTEMD=0)], + HAVE_SYSTEMD=0) + +AS_IF([test "x$enable_systemd" = "xyes" && test "x$HAVE_SYSTEMD" = "x0"], + [AC_MSG_ERROR([*** Needed systemd support not found])]) + +AC_SUBST(HAVE_SYSTEMD) +AM_CONDITIONAL([HAVE_SYSTEMD], [test "x$HAVE_SYSTEMD" = x1]) +AS_IF([test "x$HAVE_SYSTEMD" = "x1"], AC_DEFINE([HAVE_SYSTEMD], 1, [Have SYSTEMD?])) + #### Build and Install man pages #### AC_ARG_ENABLE([manpages], @@ -1361,6 +1377,7 @@ AS_IF([test "x$HAVE_XEN" = "x1"], ENABLE_XEN=yes, ENABLE_XEN=no) AS_IF([test "x$HAVE_DBUS" = "x1"], ENABLE_DBUS=yes, ENABLE_DBUS=no) AS_IF([test "x$HAVE_HAL" = "x1"], ENABLE_HAL=yes, ENABLE_HAL=no) AS_IF([test "x$HAVE_UDEV" = "x1"], ENABLE_UDEV=yes, ENABLE_UDEV=no) +AS_IF([test "x$HAVE_SYSTEMD" = "x1"], ENABLE_SYSTEMD=yes, ENABLE_SYSTEMD=no) AS_IF([test "x$HAVE_BLUEZ" = "x1"], ENABLE_BLUEZ=yes, ENABLE_BLUEZ=no) AS_IF([test "x$HAVE_HAL_COMPAT" = "x1"], ENABLE_HAL_COMPAT=yes, ENABLE_HAL_COMPAT=no) AS_IF([test "x$HAVE_TCPWRAP" = "x1"], ENABLE_TCPWRAP=yes, ENABLE_TCPWRAP=no) @@ -1415,6 +1432,7 @@ echo " Enable BlueZ: ${ENABLE_BLUEZ} Enable udev: ${ENABLE_UDEV} Enable HAL->udev compat: ${ENABLE_HAL_COMPAT} + Enable systemd login: ${ENABLE_SYSTEMD} Enable TCP Wrappers: ${ENABLE_TCPWRAP} Enable libsamplerate: ${ENABLE_LIBSAMPLERATE} Enable IPv6: ${ENABLE_IPV6} diff --git a/src/Makefile.am b/src/Makefile.am index 034981c..0451da0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1218,6 +1218,11 @@ modlibexec_LTLIBRARIES += \ module-udev-detect.la endif +if HAVE_SYSTEMD +modlibexec_LTLIBRARIES += \ + module-systemd-login.la +endif + if HAVE_DBUS modlibexec_LTLIBRARIES += \ module-rygel-media-server.la \ @@ -1319,6 +1324,7 @@ SYMDEF_FILES = \ module-echo-cancel-symdef.h \ module-hal-detect-symdef.h \ module-udev-detect-symdef.h \ + module-systemd-login-symdef.h \ module-bluetooth-proximity-symdef.h \ module-bluetooth-discover-symdef.h \ module-bluetooth-device-symdef.h \ @@ -1876,8 +1882,13 @@ module_udev_detect_la_CFLAGS = $(AM_CFLAGS) $(UDEV_CFLAGS) module_console_kit_la_SOURCES = modules/module-console-kit.c module_console_kit_la_LDFLAGS = $(MODULE_LDFLAGS) -module_console_kit_la_LIBADD = $(MODULE_LIBADD) $(DBUS_LIBS) -module_console_kit_la_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS) +module_console_kit_la_LIBADD = $(MODULE_LIBADD) $(DBUS_LIBS) $(SYSTEMD_LIBS) +module_console_kit_la_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS) $(SYSTEMD_CFLAGS) + +module_systemd_login_la_SOURCES = modules/module-systemd-login.c +module_systemd_login_la_LDFLAGS = $(MODULE_LDFLAGS) +module_systemd_login_la_LIBADD = $(MODULE_LIBADD) $(SYSTEMD_LIBS) +module_systemd_login_la_CFLAGS = $(AM_CFLAGS) $(SYSTEMD_CFLAGS) # GConf support module_gconf_la_SOURCES = modules/gconf/module-gconf.c diff --git a/src/daemon/default.pa.in b/src/daemon/default.pa.in index 633bb77..88b5944 100755 --- a/src/daemon/default.pa.in +++ b/src/daemon/default.pa.in @@ -150,6 +150,9 @@ load-module module-suspend-on-idle .ifexists module-console-kit@PA_SOEXT@ load-module module-console-kit .endif +.ifexists module-systemd-login@PA_SOEXT@ +load-module module-systemd-login +.endif ### Enable positioned event sounds load-module module-position-event-sounds diff --git a/src/modules/module-console-kit.c b/src/modules/module-console-kit.c index 4c5857c..29f7e66 100644 --- a/src/modules/module-console-kit.c +++ b/src/modules/module-console-kit.c @@ -30,6 +30,11 @@ #include #include +#ifdef HAVE_SYSTEMD +#include +#include +#endif + #include #include @@ -280,6 +285,13 @@ int pa__init(pa_module*m) { dbus_error_init(&error); +#ifdef HAVE_SYSTEMD + /* If systemd support is enabled and we boot on systemd we + shouldn't watch ConsoleKit but systemd's logind service. */ + if (sd_booted() > 0) + return 0; +#endif + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log("Failed to parse module arguments"); goto fail; diff --git a/src/modules/module-systemd-login.c b/src/modules/module-systemd-login.c new file mode 100644 index 0000000..024c1eb --- /dev/null +++ b/src/modules/module-systemd-login.c @@ -0,0 +1,243 @@ +/*** + This file is part of PulseAudio. + + Copyright 2012 Lennart Poettering + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include "module-systemd-login-symdef.h" + +PA_MODULE_AUTHOR("Lennart Poettering"); +PA_MODULE_DESCRIPTION("Create a client for each login session of this user"); +PA_MODULE_VERSION(PACKAGE_VERSION); +PA_MODULE_LOAD_ONCE(TRUE); + +static const char* const valid_modargs[] = { + NULL +}; + +struct session { + char *id; + pa_client *client; +}; + +struct userdata { + pa_module *module; + pa_core *core; + pa_hashmap *sessions, *previous_sessions; + sd_login_monitor *monitor; + pa_io_event *io; +}; + +static int add_session(struct userdata *u, const char *id) { + struct session *session; + pa_client_new_data data; + + session = pa_xnew(struct session, 1); + session->id = pa_xstrdup(id); + + pa_client_new_data_init(&data); + data.module = u->module; + data.driver = __FILE__; + pa_proplist_setf(data.proplist, PA_PROP_APPLICATION_NAME, "Login Session %s", id); + pa_proplist_sets(data.proplist, "systemd-login.session", id); + session->client = pa_client_new(u->core, &data); + pa_client_new_data_done(&data); + + if (!session->client) { + pa_xfree(session->id); + pa_xfree(session); + return -1; + } + + pa_hashmap_put(u->sessions, session->id, session); + + pa_log_debug("Added new session %s", id); + return 0; +} + +static void free_session(struct session *session) { + pa_assert(session); + + pa_log_debug("Removing session %s", session->id); + + pa_client_free(session->client); + pa_xfree(session->id); + pa_xfree(session); +} + +static int get_session_list(struct userdata *u) { + int r; + char **sessions; + pa_hashmap *h; + struct session *o; + + pa_assert(u); + + r = sd_uid_get_sessions(getuid(), 0, &sessions); + if (r < 0) + return -1; + + /* We copy all sessions that still exist from one hashmap to the + * other and then flush the remaining ones */ + + h = u->previous_sessions; + u->previous_sessions = u->sessions; + u->sessions = h; + + if (sessions) { + char **s; + + /* Note that the sessions array is allocated with libc's + * malloc()/free() calls, hence do not use pa_xfree() to free + * this here. */ + + for (s = sessions; *s; s++) { + o = pa_hashmap_remove(u->previous_sessions, *s); + if (o) + pa_hashmap_put(u->sessions, o->id, o); + else + add_session(u, *s); + + free(*s); + } + + free(sessions); + } + + while ((o = pa_hashmap_steal_first(u->previous_sessions))) + free_session(o); + + return 0; +} + +static void monitor_cb( + pa_mainloop_api*a, + pa_io_event* e, + int fd, + pa_io_event_flags_t events, + void *userdata) { + + struct userdata *u = userdata; + + pa_assert(u); + + sd_login_monitor_flush(u->monitor); + get_session_list(u); +} + +int pa__init(pa_module *m) { + struct userdata *u = NULL; + pa_modargs *ma; + sd_login_monitor *monitor = NULL; + int r; + + pa_assert(m); + + /* If we are not actually booting with systemd become a NOP */ + if (sd_booted() <= 0) + return 0; + + ma = pa_modargs_new(m->argument, valid_modargs); + if (!ma) { + pa_log("Failed to parse module arguments"); + goto fail; + } + + r = sd_login_monitor_new("session", &monitor); + if (r < 0) { + pa_log("Failed to create session monitor: %s", strerror(-r)); + goto fail; + } + + m->userdata = u = pa_xnew0(struct userdata, 1); + u->core = m->core; + u->module = m; + u->sessions = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); + u->previous_sessions = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); + u->monitor = monitor; + + u->io = u->core->mainloop->io_new(u->core->mainloop, sd_login_monitor_get_fd(monitor), PA_IO_EVENT_INPUT, monitor_cb, u); + + if (get_session_list(u) < 0) + goto fail; + + pa_modargs_free(ma); + + return 0; + +fail: + if (ma) + pa_modargs_free(ma); + + pa__done(m); + + return -1; +} + +void pa__done(pa_module *m) { + struct userdata *u; + struct session *session; + + pa_assert(m); + + u = m->userdata; + if (!u) + return; + + if (u->sessions) { + while ((session = pa_hashmap_steal_first(u->sessions))) + free_session(session); + + pa_hashmap_free(u->sessions, NULL, NULL); + + while ((session = pa_hashmap_steal_first(u->previous_sessions))) + free_session(session); + + pa_hashmap_free(u->previous_sessions, NULL, NULL); + } + + if (u->io) + m->core->mainloop->io_free(u->io); + + if (u->monitor) + sd_login_monitor_unref(u->monitor); + + pa_xfree(u); +} -- 1.7.5.4