[kde-workspace] Merged and cleaned the systemd shutdown and logout patches.
Martin Briza
mbriza at fedoraproject.org
Thu Dec 6 13:45:17 UTC 2012
commit 27f36752fdf3ccfc0afc5816b3731cb29bb386bf
Author: Martin Briza <mbriza at redhat.com>
Date: Thu Dec 6 14:44:16 2012 +0100
Merged and cleaned the systemd shutdown and logout patches.
It is possible to use systemd and/or CK without defining it at compile time.
kde-workspace-4.8.0-systemd-shutdown.patch | 329 ---------------
kde-workspace-4.9.2-systemd-switch-user.patch | 112 -----
kde-workspace-4.9.2-systemd-switch-user2.patch | 19 -
kde-workspace-4.9.3-systemd-displaymanager.patch | 479 ++++++++++++++++++++++
kde-workspace.spec | 20 +-
5 files changed, 488 insertions(+), 471 deletions(-)
---
diff --git a/kde-workspace-4.9.3-systemd-displaymanager.patch b/kde-workspace-4.9.3-systemd-displaymanager.patch
new file mode 100644
index 0000000..ee3f61e
--- /dev/null
+++ b/kde-workspace-4.9.3-systemd-displaymanager.patch
@@ -0,0 +1,479 @@
+--- libs/kworkspace/kdisplaymanager.cpp.systemd-displaymanager 2012-08-13 10:53:46.000000000 +0200
++++ libs/kworkspace/kdisplaymanager.cpp 2012-12-05 12:58:32.193798795 +0100
+@@ -40,6 +40,166 @@
+ #include <errno.h>
+ #include <stdio.h>
+
++#define _DBUS_PROPERTIES_IFACE "org.freedesktop.DBus.Properties"
++#define _DBUS_PROPERTIES_GET "Get"
++
++#define DBUS_PROPERTIES_IFACE QLatin1String(_DBUS_PROPERTIES_IFACE)
++#define DBUS_PROPERTIES_GET QLatin1String(_DBUS_PROPERTIES_GET)
++
++#define _SYSTEMD_SERVICE "org.freedesktop.login1"
++#define _SYSTEMD_BASE_PATH "/org/freedesktop/login1"
++#define _SYSTEMD_MANAGER_IFACE _SYSTEMD_SERVICE ".Manager"
++#define _SYSTEMD_SESSION_BASE_PATH _SYSTEMD_BASE_PATH "/Session"
++#define _SYSTEMD_SEAT_IFACE _SYSTEMD_SERVICE ".Seat"
++#define _SYSTEMD_SEAT_BASE_PATH _SYSTEMD_BASE_PATH "/Seat"
++#define _SYSTEMD_SESSION_IFACE _SYSTEMD_SERVICE ".Session"
++#define _SYSTEMD_USER_PROPERTY "User"
++#define _SYSTEMD_SEAT_PROPERTY "Seat"
++#define _SYSTEMD_SESSIONS_PROPERTY "Sessions"
++#define _SYSTEMD_SWITCH_CALL "Activate"
++
++#define SYSTEMD_SERVICE QLatin1String(_SYSTEMD_SERVICE)
++#define SYSTEMD_BASE_PATH QLatin1String(_SYSTEMD_BASE_PATH)
++#define SYSTEMD_MANAGER_IFACE QLatin1String(_SYSTEMD_MANAGER_IFACE)
++#define SYSTEMD_SESSION_BASE_PATH QLatin1String(_SYSTEMD_SESSION_BASE_PATH)
++#define SYSTEMD_SEAT_IFACE QLatin1String(_SYSTEMD_SEAT_IFACE)
++#define SYSTEMD_SEAT_BASE_PATH QLatin1String(_SYSTEMD_SEAT_BASE_PATH)
++#define SYSTEMD_SESSION_IFACE QLatin1String(_SYSTEMD_SESSION_IFACE)
++#define SYSTEMD_USER_PROPERTY QLatin1String(_SYSTEMD_USER_PROPERTY)
++#define SYSTEMD_SEAT_PROPERTY QLatin1String(_SYSTEMD_SEAT_PROPERTY)
++#define SYSTEMD_SESSIONS_PROPERTY QLatin1String(_SYSTEMD_SESSIONS_PROPERTY)
++#define SYSTEMD_SWITCH_CALL QLatin1String(_SYSTEMD_SWITCH_CALL)
++
++struct NamedDBusObjectPath
++{
++ QString name;
++ QDBusObjectPath path;
++};
++Q_DECLARE_METATYPE(NamedDBusObjectPath)
++Q_DECLARE_METATYPE(QList<NamedDBusObjectPath>)
++
++// Marshall the NamedDBusObjectPath data into a D-Bus argument
++QDBusArgument &operator<<(QDBusArgument &argument, const NamedDBusObjectPath &namedPath)
++{
++ argument.beginStructure();
++ argument << namedPath.name << namedPath.path;
++ argument.endStructure();
++ return argument;
++}
++
++// Retrieve the NamedDBusObjectPath data from the D-Bus argument
++const QDBusArgument &operator>>(const QDBusArgument &argument, NamedDBusObjectPath &namedPath)
++{
++ argument.beginStructure();
++ argument >> namedPath.name >> namedPath.path;
++ argument.endStructure();
++ return argument;
++}
++
++struct NumberedDBusObjectPath
++{
++ uint num;
++ QDBusObjectPath path;
++};
++Q_DECLARE_METATYPE(NumberedDBusObjectPath)
++
++// Marshall the NumberedDBusObjectPath data into a D-Bus argument
++QDBusArgument &operator<<(QDBusArgument &argument, const NumberedDBusObjectPath &numberedPath)
++{
++ argument.beginStructure();
++ argument << numberedPath.num << numberedPath.path;
++ argument.endStructure();
++ return argument;
++}
++
++// Retrieve the NumberedDBusObjectPath data from the D-Bus argument
++const QDBusArgument &operator>>(const QDBusArgument &argument, NumberedDBusObjectPath &numberedPath)
++{
++ argument.beginStructure();
++ argument >> numberedPath.num >> numberedPath.path;
++ argument.endStructure();
++ return argument;
++}
++
++class SystemdManager : public QDBusInterface
++{
++public:
++ SystemdManager() :
++ QDBusInterface(
++ SYSTEMD_SERVICE,
++ SYSTEMD_BASE_PATH,
++ SYSTEMD_MANAGER_IFACE,
++ QDBusConnection::systemBus()) {}
++};
++
++class SystemdSeat : public QDBusInterface
++{
++public:
++ SystemdSeat(const QDBusObjectPath &path) :
++ QDBusInterface(
++ SYSTEMD_SERVICE,
++ path.path(),
++ SYSTEMD_SEAT_IFACE,
++ QDBusConnection::systemBus()) {}
++ /* HACK to be able to extract a(so) type from QDBus, property doesn't do the trick */
++ QList<NamedDBusObjectPath> getSessions() {
++ QDBusMessage message = QDBusMessage::createMethodCall(service(), path(), DBUS_PROPERTIES_IFACE, DBUS_PROPERTIES_GET);
++ message << interface() << SYSTEMD_SESSIONS_PROPERTY;
++ QDBusMessage reply = QDBusConnection::systemBus().call(message);
++
++ QVariantList args = reply.arguments();
++ if (!args.isEmpty()) {
++ QList<NamedDBusObjectPath> namedPathList = qdbus_cast< QList<NamedDBusObjectPath> >(args.at(0).value<QDBusVariant>().variant().value<QDBusArgument>());
++ return namedPathList;
++ }
++ return QList<NamedDBusObjectPath>();
++ }
++};
++
++class SystemdSession : public QDBusInterface
++{
++public:
++ SystemdSession(const QDBusObjectPath &path) :
++ QDBusInterface(
++ SYSTEMD_SERVICE,
++ path.path(),
++ SYSTEMD_SESSION_IFACE,
++ QDBusConnection::systemBus()) {}
++ /* HACK to be able to extract (so) type from QDBus, property doesn't do the trick */
++ NamedDBusObjectPath getSeat() {
++ QDBusMessage message = QDBusMessage::createMethodCall(service(), path(), DBUS_PROPERTIES_IFACE, DBUS_PROPERTIES_GET);
++ message << interface() << SYSTEMD_SEAT_PROPERTY;
++ QDBusMessage reply = QDBusConnection::systemBus().call(message);
++
++ QVariantList args = reply.arguments();
++ if (!args.isEmpty()) {
++ NamedDBusObjectPath namedPath;
++ args.at(0).value<QDBusVariant>().variant().value<QDBusArgument>() >> namedPath;
++ return namedPath;
++ }
++ return NamedDBusObjectPath();
++ }
++ NumberedDBusObjectPath getUser() {
++ QDBusMessage message = QDBusMessage::createMethodCall(service(), path(), DBUS_PROPERTIES_IFACE, DBUS_PROPERTIES_GET);
++ message << interface() << SYSTEMD_USER_PROPERTY;
++ QDBusMessage reply = QDBusConnection::systemBus().call(message);
++
++ QVariantList args = reply.arguments();
++ if (!args.isEmpty()) {
++ NumberedDBusObjectPath numberedPath;
++ args.at(0).value<QDBusVariant>().variant().value<QDBusArgument>() >> numberedPath;
++ return numberedPath;
++ }
++ return NumberedDBusObjectPath();
++ }
++ void getSessionLocation(SessEnt &se)
++ {
++ se.tty = (property("Type").toString() != QLatin1String("x11"));
++ se.display = property(se.tty ? "TTY" : "Display").toString();
++ se.vt = property("VTNr").toInt();
++ }
++};
++
+ class CKManager : public QDBusInterface
+ {
+ public:
+@@ -68,9 +228,26 @@
+ CKSession(const QDBusObjectPath &path) :
+ QDBusInterface(
+ QLatin1String("org.freedesktop.ConsoleKit"),
+- path.path(),
++ path.path(),
+ QLatin1String("org.freedesktop.ConsoleKit.Session"),
+ QDBusConnection::systemBus()) {}
++ void getSessionLocation(SessEnt &se)
++ {
++ QString tty;
++ QDBusReply<QString> r = call(QLatin1String("GetX11Display"));
++ if (r.isValid() && !r.value().isEmpty()) {
++ QDBusReply<QString> r2 = call(QLatin1String("GetX11DisplayDevice"));
++ tty = r2.value();
++ se.display = r.value();
++ se.tty = false;
++ } else {
++ QDBusReply<QString> r2 = call(QLatin1String("GetDisplayDevice"));
++ tty = r2.value();
++ se.display = tty;
++ se.tty = true;
++ }
++ se.vt = tty.mid(strlen("/dev/tty")).toInt();
++ }
+ };
+
+ class GDMFactory : public QDBusInterface
+@@ -131,6 +308,9 @@
+ }
+ switch (DMType) {
+ default:
++ qDBusRegisterMetaType<NamedDBusObjectPath>();
++ qDBusRegisterMetaType<QList<NamedDBusObjectPath> >();
++ qDBusRegisterMetaType<NumberedDBusObjectPath>();
+ return;
+ case NewKDM:
+ case OldGDM:
+@@ -242,17 +422,31 @@
+
+ static bool getCurrentSeat(QDBusObjectPath *currentSession, QDBusObjectPath *currentSeat)
+ {
+- CKManager man;
+- QDBusReply<QDBusObjectPath> r = man.call(QLatin1String("GetCurrentSession"));
++ SystemdManager man;
++ QDBusReply<QDBusObjectPath> r = man.call(QLatin1String("GetSessionByPID"), (uint) QCoreApplication::applicationPid());
+ if (r.isValid()) {
+- CKSession sess(r.value());
++ SystemdSession sess(r.value());
+ if (sess.isValid()) {
+- QDBusReply<QDBusObjectPath> r2 = sess.call(QLatin1String("GetSeatId"));
+- if (r2.isValid()) {
+- if (currentSession)
+- *currentSession = r.value();
+- *currentSeat = r2.value();
+- return true;
++ NamedDBusObjectPath namedPath = sess.getSeat();
++ if (currentSession)
++ *currentSession = r.value();
++ *currentSeat = namedPath.path;
++ return true;
++ }
++ }
++ else {
++ CKManager man;
++ QDBusReply<QDBusObjectPath> r = man.call(QLatin1String("GetCurrentSession"));
++ if (r.isValid()) {
++ CKSession sess(r.value());
++ if (sess.isValid()) {
++ QDBusReply<QDBusObjectPath> r2 = sess.call(QLatin1String("GetSeatId"));
++ if (r2.isValid()) {
++ if (currentSession)
++ *currentSession = r.value();
++ *currentSeat = r2.value();
++ return true;
++ }
+ }
+ }
+ }
+@@ -261,44 +455,44 @@
+
+ static QList<QDBusObjectPath> getSessionsForSeat(const QDBusObjectPath &path)
+ {
+- CKSeat seat(path);
+- if (seat.isValid()) {
+- QDBusReply<QList<QDBusObjectPath> > r = seat.call(QLatin1String("GetSessions"));
+- if (r.isValid()) {
+- // This will contain only local sessions:
+- // - this is only ever called when isSwitchable() is true => local seat
+- // - remote logins into the machine are assigned to other seats
+- return r.value();
++ if (path.path().startsWith(SYSTEMD_BASE_PATH)) { // systemd path incoming
++ SystemdSeat seat(path);
++ if (seat.isValid()) {
++ QList<NamedDBusObjectPath> r = seat.getSessions();
++ QList<QDBusObjectPath> result;
++ foreach (const NamedDBusObjectPath &namedPath, r)
++ result.append(namedPath.path);
++ // This pretty much can't contain any other than local sessions as seats are assigned only locally in systemd
++ return result;
++ }
++ }
++ else if (path.path().startsWith("/org/freedesktop/ConsoleKit")) {
++ CKSeat seat(path);
++ if (seat.isValid()) {
++ QDBusReply<QList<QDBusObjectPath> > r = seat.call(QLatin1String("GetSessions"));
++ if (r.isValid()) {
++ // This will contain only local sessions:
++ // - this is only ever called when isSwitchable() is true => local seat
++ // - remote logins into the machine are assigned to other seats
++ return r.value();
++ }
+ }
+ }
+ return QList<QDBusObjectPath>();
+ }
+
+-static void getSessionLocation(CKSession &lsess, SessEnt &se)
+-{
+- QString tty;
+- QDBusReply<QString> r = lsess.call(QLatin1String("GetX11Display"));
+- if (r.isValid() && !r.value().isEmpty()) {
+- QDBusReply<QString> r2 = lsess.call(QLatin1String("GetX11DisplayDevice"));
+- tty = r2.value();
+- se.display = r.value();
+- se.tty = false;
+- } else {
+- QDBusReply<QString> r2 = lsess.call(QLatin1String("GetDisplayDevice"));
+- tty = r2.value();
+- se.display = tty;
+- se.tty = true;
+- }
+- se.vt = tty.mid(strlen("/dev/tty")).toInt();
+-}
+-
+ #ifndef KDM_NO_SHUTDOWN
+ bool
+ KDisplayManager::canShutdown()
+ {
+ if (DMType == NewGDM || DMType == NoDM || DMType == LightDM) {
++ QDBusReply<QString> canPowerOff = SystemdManager().call(QLatin1String("CanPowerOff"));
++ if (canPowerOff.isValid())
++ return canPowerOff.value() != QLatin1String("no");
+ QDBusReply<bool> canStop = CKManager().call(QLatin1String("CanStop"));
+- return (canStop.isValid() && canStop.value());
++ if (canStop.isValid())
++ return canStop.value();
++ return false;
+ }
+
+ if (DMType == OldKDM)
+@@ -329,9 +523,21 @@
+ return;
+
+ if (DMType == NewGDM || DMType == NoDM || DMType == LightDM) {
+- // FIXME: entirely ignoring shutdownMode
+- CKManager().call(QLatin1String(
+- shutdownType == KWorkSpace::ShutdownTypeReboot ? "Restart" : "Stop"));
++ // systemd supports only 2 modes:
++ // * interactive = true: brings up a PolicyKit prompt if other sessions are active
++ // * interactive = false: rejects the shutdown if other sessions are active
++ // There are no schedule or force modes.
++ // We try to map our 4 shutdown modes in the sanest way.
++ bool interactive = (shutdownMode == KWorkSpace::ShutdownModeInteractive
++ || shutdownMode == KWorkSpace::ShutdownModeForceNow);
++ QDBusReply<QString> check = SystemdManager().call(QLatin1String(
++ shutdownType == KWorkSpace::ShutdownTypeReboot ? "Reboot" : "PowerOff"), interactive);
++ if (!check.isValid()) {
++ // FIXME: entirely ignoring shutdownMode
++ CKManager().call(QLatin1String(
++ shutdownType == KWorkSpace::ShutdownTypeReboot ? "Restart" : "Stop"));
++ // if even CKManager call fails, there is nothing more to be done
++ }
+ return;
+ }
+
+@@ -406,9 +612,15 @@
+ if (DMType == NewGDM || DMType == LightDM) {
+ QDBusObjectPath currentSeat;
+ if (getCurrentSeat(0, ¤tSeat)) {
+- CKSeat seat(currentSeat);
+- if (seat.isValid()) {
+- QDBusReply<bool> r = seat.call(QLatin1String("CanActivateSessions"));
++ SystemdSeat SDseat(currentSeat);
++ if (SDseat.isValid()) {
++ QVariant prop = SDseat.property("CanMultiSession");
++ if (prop.isValid())
++ return prop.toBool();
++ }
++ CKSeat CKseat(currentSeat);
++ if (CKseat.isValid()) {
++ QDBusReply<bool> r = CKseat.call(QLatin1String("CanActivateSessions"));
+ if (r.isValid())
+ return r.value();
+ }
+@@ -468,23 +680,56 @@
+ if (DMType == NewGDM || DMType == LightDM) {
+ QDBusObjectPath currentSession, currentSeat;
+ if (getCurrentSeat(¤tSession, ¤tSeat)) {
+- foreach (const QDBusObjectPath &sp, getSessionsForSeat(currentSeat)) {
+- CKSession lsess(sp);
+- if (lsess.isValid()) {
+- SessEnt se;
+- getSessionLocation(lsess, se);
+- // "Warning: we haven't yet defined the allowed values for this property.
+- // It is probably best to avoid this until we do."
+- QDBusReply<QString> r = lsess.call(QLatin1String("GetSessionType"));
+- if (r.value() != QLatin1String("LoginWindow")) {
+- QDBusReply<unsigned> r2 = lsess.call(QLatin1String("GetUnixUser"));
+- se.user = KUser(K_UID(r2.value())).loginName();
+- se.session = "<unknown>";
++ // we'll divide the code in two branches to reduce the overhead of calls to non-existent services
++ // systemd part // preferred
++ if (QDBusConnection::systemBus().interface()->isServiceRegistered(SYSTEMD_SERVICE)) {
++ foreach (const QDBusObjectPath &sp, getSessionsForSeat(currentSeat)) {
++ SystemdSession lsess(sp);
++ if (lsess.isValid()) {
++ SessEnt se;
++ lsess.getSessionLocation(se);
++ if ((lsess.property("Class").toString() != QLatin1String("greeter")) &&
++ (lsess.property("State").toString() != QLatin1String("closing"))) {
++ NumberedDBusObjectPath numberedPath = lsess.getUser();
++ se.display = lsess.property("Display").toString();
++ se.vt = lsess.property("VTNr").toInt();
++ se.user = KUser(K_UID(numberedPath.num)).loginName();
++ /* TODO:
++ * regarding the session name in this, it IS possible to find it out - logind tracks the session leader PID
++ * the problem is finding out the name of the process, I could come only with reading /proc/PID/comm which
++ * doesn't seem exactly... right to me --mbriza
++ */
++ se.session = "<unknown>";
++ se.self = lsess.property("Display").toString() == ::getenv("DISPLAY"); /* Bleh once again */
++ se.tty = !lsess.property("TTY").toString().isEmpty();
++ }
++ list.append(se);
++ }
++ }
++ }
++ // ConsoleKit part
++ else if (QDBusConnection::systemBus().interface()->isServiceRegistered("org.freedesktop.ConsoleKit")) {
++ foreach (const QDBusObjectPath &sp, getSessionsForSeat(currentSeat)) {
++ CKSession lsess(sp);
++ if (lsess.isValid()) {
++ SessEnt se;
++ lsess.getSessionLocation(se);
++ // "Warning: we haven't yet defined the allowed values for this property.
++ // It is probably best to avoid this until we do."
++ QDBusReply<QString> r = lsess.call(QLatin1String("GetSessionType"));
++ if (r.value() != QLatin1String("LoginWindow")) {
++ QDBusReply<unsigned> r2 = lsess.call(QLatin1String("GetUnixUser"));
++ se.user = KUser(K_UID(r2.value())).loginName();
++ se.session = "<unknown>";
++ }
++ se.self = (sp == currentSession);
++ list.append(se);
+ }
+- se.self = (sp == currentSession);
+- list.append(se);
+ }
+ }
++ else {
++ return false;
++ }
+ return true;
+ }
+ return false;
+@@ -566,16 +811,33 @@
+ if (DMType == NewGDM || DMType == LightDM) {
+ QDBusObjectPath currentSeat;
+ if (getCurrentSeat(0, ¤tSeat)) {
+- foreach (const QDBusObjectPath &sp, getSessionsForSeat(currentSeat)) {
+- CKSession lsess(sp);
+- if (lsess.isValid()) {
+- SessEnt se;
+- getSessionLocation(lsess, se);
+- if (se.vt == vt) {
+- if (se.tty) // ConsoleKit simply ignores these
+- return false;
+- lsess.call(QLatin1String("Activate"));
+- return true;
++ // systemd part // preferred
++ if (QDBusConnection::systemBus().interface()->isServiceRegistered(SYSTEMD_SERVICE)) {
++ foreach (const QDBusObjectPath &sp, getSessionsForSeat(currentSeat)) {
++ SystemdSession lsess(sp);
++ if (lsess.isValid()) {
++ SessEnt se;
++ lsess.getSessionLocation(se);
++ if (se.vt == vt) {
++ lsess.call(SYSTEMD_SWITCH_CALL);
++ return true;
++ }
++ }
++ }
++ }
++ // ConsoleKit part
++ else if (QDBusConnection::systemBus().interface()->isServiceRegistered("org.freedesktop.ConsoleKit")) {
++ foreach (const QDBusObjectPath &sp, getSessionsForSeat(currentSeat)) {
++ CKSession lsess(sp);
++ if (lsess.isValid()) {
++ SessEnt se;
++ lsess.getSessionLocation(se);
++ if (se.vt == vt) {
++ if (se.tty) // ConsoleKit simply ignores these
++ return false;
++ lsess.call(QLatin1String("Activate"));
++ return true;
++ }
+ }
+ }
+ }
diff --git a/kde-workspace.spec b/kde-workspace.spec
index 737c506..89bd2eb 100644
--- a/kde-workspace.spec
+++ b/kde-workspace.spec
@@ -5,7 +5,7 @@
Summary: KDE Workspace
Name: kde-workspace
Version: 4.9.90
-Release: 1%{?dist}
+Release: 2%{?dist}
License: GPLv2
URL: https://projects.kde.org/projects/kde/kde-workspace
@@ -96,12 +96,9 @@ Patch54: kde-workspace-4.9.90-kscreenlocker_rename.patch
# http://bugzilla.redhat.com/796969
Patch57: kde-workspace-4.8.0-bug796969.patch
-# initial systemd support
-Patch58: kde-workspace-4.8.0-systemd-shutdown.patch
-
-# Support for switching users with systemd - #859347
-Patch60: kde-workspace-4.9.2-systemd-switch-user.patch
-Patch61: kde-workspace-4.9.2-systemd-switch-user2.patch
+# merged patches: systemd-switch-user{,2} systemd-shutdown
+# Support for systemd AND ConsoleKit in kworkspace
+Patch62: kde-workspace-4.9.3-systemd-displaymanager.patch
## upstream patches
@@ -428,9 +425,7 @@ Requires: akonadi
%patch53 -p1 -b .kdm_xauth
%patch54 -p1 -b .kscreenlocker_rename
%patch57 -p1 -b .bug796969
-%patch58 -p1 -b .systemd-shutdown
-%patch60 -p1 -b .systemd-switch-user
-%patch61 -p0 -b .systemd-switch-user2
+%patch62 -p0 -b .systemd-displaymanager
# upstream patches
@@ -456,7 +451,6 @@ pushd %{_target_platform}
-DKDE4_KDM_PAM_SERVICE=kdm \
-DKDE4_KCHECKPASS_PAM_SERVICE=kcheckpass \
-DKDE4_KSCREENSAVER_PAM_SERVICE=kscreensaver \
- -DKWORKSPACE_USE_SYSTEMD:BOOL=ON \
-DPOWERDEVIL_USE_SYSTEMD:BOOL=ON \
..
popd
@@ -979,6 +973,10 @@ fi
%changelog
+* Thu Dec 06 2012 Martin Briza <mbriza at redhat.com> 4.9.90-2
+- Merged and cleaned the systemd shutdown and logout patches.
+- It is possible to use systemd and/or CK without defining it at compile time
+
* Mon Dec 03 2012 Rex Dieter <rdieter at fedoraproject.org> 4.9.90-1
- 4.9.90 (4.10 beta2)
More information about the scm-commits
mailing list