From: Didier Roche <didrocks@ubuntu.com>
Date: Thu, 27 Nov 2014 10:51:50 +0100
Subject: Prefer /etc/X11/default-display-manager if present

Add a generator to ensure /etc/X11/default-display-manager is controlling
which display-manager is started.
---
 Makefile.am                                        |  11 +-
 src/default-display-manager-generator/Makefile     |  24 +++++
 .../default-display-manager-generator.c            | 112 +++++++++++++++++++++
 3 files changed, 146 insertions(+), 1 deletion(-)
 create mode 100644 src/default-display-manager-generator/Makefile
 create mode 100644 src/default-display-manager-generator/default-display-manager-generator.c

diff --git a/Makefile.am b/Makefile.am
index 6f4df22..9d83771 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -387,7 +387,8 @@ systemgenerator_PROGRAMS = \
 	systemd-getty-generator \
 	systemd-fstab-generator \
 	systemd-system-update-generator \
-	systemd-debug-generator
+	systemd-debug-generator \
+	systemd-default-display-manager-generator
 
 dist_bashcompletion_DATA = \
 	shell-completion/bash/busctl \
@@ -1965,6 +1966,14 @@ systemd_delta_LDADD = \
 	libsystemd-shared.la
 
 # ------------------------------------------------------------------------------
+systemd_default_display_manager_generator_SOURCES = \
+    src/default-display-manager-generator/default-display-manager-generator.c
+
+systemd_default_display_manager_generator_LDADD = \
+    libsystemd-label.la \
+    libsystemd-shared.la
+
+# ------------------------------------------------------------------------------
 systemd_insserv_generator_SOURCES = \
 	src/insserv-generator/insserv-generator.c
 
diff --git a/src/default-display-manager-generator/Makefile b/src/default-display-manager-generator/Makefile
new file mode 100644
index 0000000..3a4bbbe
--- /dev/null
+++ b/src/default-display-manager-generator/Makefile
@@ -0,0 +1,24 @@
+#  This file is part of systemd.
+#
+#  Copyright 2014 Canonical
+#
+#  systemd 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.
+#
+#  systemd 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
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public License
+#  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+
+all:
+	$(MAKE) -C ..
+
+clean:
+	$(MAKE) -C .. clean
+
+.PHONY: all clean
diff --git a/src/default-display-manager-generator/default-display-manager-generator.c b/src/default-display-manager-generator/default-display-manager-generator.c
new file mode 100644
index 0000000..3e476b5
--- /dev/null
+++ b/src/default-display-manager-generator/default-display-manager-generator.c
@@ -0,0 +1,112 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2014 Canonical
+
+  systemd 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.
+
+  systemd 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
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+#include <stdbool.h>
+#include <unistd.h>
+
+#include "fileio.h"
+#include "log.h"
+#include "mkdir.h"
+#include "util.h"
+
+
+/*
+ * Ensure that the started display-manager is matching
+ * /etc/X11/default-display-manager if present, otherwise
+ * let display-manager.service symlinks pick the preferred one
+ * if any.
+ */
+
+static const char *dm_service_unit = SYSTEM_CONFIG_UNIT_PATH "/display-manager.service";
+static const char *default_dm_file = "/etc/X11/default-display-manager";
+static const char *dest = NULL;
+
+static int generate_display_manager_alias(void) {
+
+        _cleanup_free_ char *default_dm_path = NULL, *enabled_dm_unit = NULL;
+        const char *default_dm = NULL, *in_mem_symlink = NULL, *target_unit_path = NULL;
+        bool dm_service_exists = true;
+        int r;
+
+        r = read_full_file(default_dm_file, &default_dm_path, NULL);
+        if (r < 0) {
+                log_debug("No %s file, nothing to generate", default_dm_file);
+                return 0;
+        }
+        default_dm = strstrip(basename(default_dm_path));
+
+        r = readlink_value(dm_service_unit, &enabled_dm_unit);
+        if (r < 0) {
+                enabled_dm_unit = strdup("");
+                dm_service_exists = false;
+        }
+
+        /* all is fine if the info matches */
+        if (streq(strappenda(default_dm, ".service"), enabled_dm_unit))
+                return 0;
+
+        target_unit_path = strappenda(SYSTEM_DATA_UNIT_PATH, "/", default_dm, ".service");
+
+        /* we only create the alias symlink for non sysvinit services */
+        if (access(target_unit_path, F_OK) < 0 && (errno == ENOENT)) {
+                /* if the dm service was already disabled, nothing to be done */
+                if (!dm_service_exists) {
+                        log_debug("No %s file, nothing to mask", dm_service_unit);
+                        return 0;
+                }
+                log_warning("%s is not a systemd unit, we disable the systemd enabled display manager", target_unit_path);
+                target_unit_path = "/dev/null";
+        } else {
+                log_warning("%s points at %s while the default systemd unit is %s. Reconfiguring %s as default.",
+                            default_dm_file, default_dm, enabled_dm_unit, default_dm);
+        }
+
+        in_mem_symlink = strappenda(dest, "/display-manager.service");
+        mkdir_parents_label(in_mem_symlink, 0755);
+        if (symlink(target_unit_path, in_mem_symlink) < 0) {
+                log_error("Failed to create symlink %s: %m", in_mem_symlink);
+                return -errno;
+        }
+
+        return 0;
+}
+
+int main(int argc, char *argv[]) {
+        int r;
+
+        if (argc != 4) {
+                log_error("This program takes three arguments.");
+                return EXIT_FAILURE;
+        }
+
+        dest = argv[2];
+
+        log_set_target(LOG_TARGET_SAFE);
+        log_parse_environment();
+        log_open();
+
+        umask(0022);
+
+        r = generate_display_manager_alias();
+
+        return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+}
