chiark / gitweb /
Remove dependency of systemd units, services and slices for new sessions.
authorSven Eden <yamakuzure@gmx.net>
Thu, 26 Jan 2017 08:56:23 +0000 (09:56 +0100)
committerSven Eden <yamakuzure@gmx.net>
Tue, 14 Mar 2017 09:23:10 +0000 (10:23 +0100)
* elogind does not support systemd services and units. But at least
  the units are needed to support the systemd cgroup slice/scope
  system.
* Remove systemd subscription to scope, service and slice jobs.
  These can not be supported in any way, as they depend on systemd
  running the machine.
* The functions session_start_scope(), user_start_service() and
  user_start_slice() no longer try to call systemd via dbus for
  assistance.
  This way they generate their proper scope, service and slice names,
  and store them in the Managers HashMaps for session and user units.
  This should enable us to reverse track pids to users and such
  stuff, as that is what systemd-logind does, not knowing whether any
  unit *really* has been started or not.
  However, this will not work out of the box until we find a way to
  integrate cg_create_everywhere() into elogind without becoming
  dependent of systemd unit, service and job knowledge again.

src/login/logind-dbus.c
src/login/logind-session-dbus.c
src/login/logind-session.c
src/login/logind-session.h
src/login/logind-user.c
src/login/logind-user.h
src/login/logind.h

index fdf95fc..31580af 100644 (file)
@@ -821,6 +821,15 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus
          * created. We send the reply back from
          * session_send_create_reply(). */
 
+        /* Elogind note: replying directly, since we're not actually
+           starting slices and thus we aren't waiting on systemd.  */
+
+        r = session_send_create_reply(session, NULL);
+        if (r < 0)
+                goto fail;
+
+        session_save(session);
+
         return 1;
 
 fail:
@@ -2568,8 +2577,11 @@ int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *err
         session = hashmap_get(m->session_units, unit);
         if (session) {
 
+/// elogind does not support scope jobs
+#if 0
                 if (streq_ptr(path, session->scope_job))
                         session->scope_job = mfree(session->scope_job);
+#endif // 0
 
                 session_jobs_reply(session, unit, result);
 
@@ -2580,11 +2592,14 @@ int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *err
         user = hashmap_get(m->user_units, unit);
         if (user) {
 
+/// elogind does not support slice and service jobs
+#if 0
                 if (streq_ptr(path, user->service_job))
                         user->service_job = mfree(user->service_job);
 
                 if (streq_ptr(path, user->slice_job))
                         user->slice_job = mfree(user->slice_job);
+#endif // 0
 
                 LIST_FOREACH(sessions_by_user, session, user->sessions)
                         session_jobs_reply(session, unit, result);
@@ -2698,6 +2713,8 @@ int manager_send_changed(Manager *manager, const char *property, ...) {
                         l);
 }
 
+/// UNNEEDED by elogind
+#if 0
 int manager_start_scope(
                 Manager *manager,
                 const char *scope,
@@ -3015,3 +3032,4 @@ int manager_job_is_active(Manager *manager, const char *path) {
 
         return true;
 }
+#endif //
index e6b4ccd..b0db8e2 100644 (file)
@@ -704,8 +704,11 @@ int session_send_create_reply(Session *s, sd_bus_error *error) {
         if (!s->create_message)
                 return 0;
 
+/// elogind does not support scope and service jobs
+#if 0
         if (!sd_bus_error_is_set(error) && (s->scope_job || s->user->service_job))
                 return 0;
+#endif // 0
 
         c = s->create_message;
         s->create_message = NULL;
index a277cda..1a35671 100644 (file)
@@ -125,7 +125,10 @@ void session_free(Session *s) {
                 free(s->scope);
         }
 
+/// elogind does not support systemd scope_jobs
+#if 0
         free(s->scope_job);
+#endif // 0
 
         sd_bus_message_unref(s->create_message);
 
@@ -196,8 +199,11 @@ int session_save(Session *s) {
 
         if (s->scope)
                 fprintf(f, "SCOPE=%s\n", s->scope);
+/// elogind does not support systemd scope_jobs
+#if 0
         if (s->scope_job)
                 fprintf(f, "SCOPE_JOB=%s\n", s->scope_job);
+#endif // 0
 
         if (s->fifo_path)
                 fprintf(f, "FIFO=%s\n", s->fifo_path);
@@ -324,7 +330,10 @@ int session_load(Session *s) {
         r = parse_env_file(s->state_file, NEWLINE,
                            "REMOTE",         &remote,
                            "SCOPE",          &s->scope,
+/// elogind does not support systemd scope_jobs
+#if 0
                            "SCOPE_JOB",      &s->scope_job,
+#endif // 0
                            "FIFO",           &s->fifo_path,
                            "SEAT",           &seat,
                            "TTY",            &s->tty,
@@ -500,7 +509,7 @@ int session_activate(Session *s) {
 }
 
 static int session_start_scope(Session *s) {
-        int r;
+        int r = 0;
 
         assert(s);
         assert(s->user);
@@ -509,7 +518,7 @@ static int session_start_scope(Session *s) {
         if (!s->scope) {
                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
                 _cleanup_free_ char *description = NULL;
-                char *scope, *job = NULL;
+                char *scope = NULL; //, *job = NULL;
 
                 description = strjoin("Session ", s->id, " of user ", s->user->name, NULL);
                 if (!description)
@@ -519,7 +528,10 @@ static int session_start_scope(Session *s) {
                 if (!scope)
                         return log_oom();
 
+/// elogind : Do not try to use dbus to call systemd
+#if 0
                 r = manager_start_scope(s->manager, scope, s->leader, s->user->slice, description, "logind.service", "systemd-user-sessions.service", &error, &job);
+#endif // 0
                 if (r < 0) {
                         log_error("Failed to start session scope %s: %s %s",
                                   scope, bus_error_message(&error, r), error.name);
@@ -527,9 +539,11 @@ static int session_start_scope(Session *s) {
                         return r;
                 } else {
                         s->scope = scope;
-
+/// elogind does not support scope jobs
+#if 0
                         free(s->scope_job);
                         s->scope_job = job;
+#endif // 0
                 }
         }
 
@@ -596,6 +610,8 @@ int session_start(Session *s) {
         return 0;
 }
 
+/// UNNEEDED by elogind
+#if 0
 static int session_stop_scope(Session *s, bool force) {
         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
         char *job = NULL;
@@ -625,9 +641,10 @@ static int session_stop_scope(Session *s, bool force) {
 
         return 0;
 }
+#endif // 0
 
 int session_stop(Session *s, bool force) {
-        int r;
+        int r = 0;
 
         assert(s);
 
@@ -643,7 +660,12 @@ int session_stop(Session *s, bool force) {
         session_remove_fifo(s);
 
         /* Kill cgroup */
+/// @todo : Currently elogind does not start scopes. It remains to be seen
+///         whether this is really not needed, but then, elogind is not a
+///         systemd cgroups manager.
+#if 0
         r = session_stop_scope(s, force);
+#endif // 0
 
         s->stopping = true;
 
@@ -932,11 +954,14 @@ bool session_check_gc(Session *s, bool drop_not_started) {
                         return true;
         }
 
+/// elogind supports neither scopes nor jobs
+#if 0
         if (s->scope_job && manager_job_is_active(s->manager, s->scope_job))
                 return true;
 
         if (s->scope && manager_unit_is_active(s->manager, s->scope))
                 return true;
+#endif // 0
 
         return false;
 }
@@ -958,7 +983,12 @@ SessionState session_get_state(Session *s) {
         if (s->stopping || s->timer_event_source)
                 return SESSION_CLOSING;
 
+/// elogind does not support systemd scope_jobs
+#if 0
         if (s->scope_job || s->fifo_fd < 0)
+#else
+        if (s->fifo_fd < 0)
+#endif // 0
                 return SESSION_OPENING;
 
         if (session_is_active(s))
@@ -970,10 +1000,15 @@ SessionState session_get_state(Session *s) {
 int session_kill(Session *s, KillWho who, int signo) {
         assert(s);
 
+/// FIXME: Without direct cgroup support, elogind can not kill sessions
+#if 0
         if (!s->scope)
                 return -ESRCH;
 
         return manager_kill_unit(s->manager, s->scope, who, signo, NULL);
+#else
+        return -ESRCH;
+#endif // 0
 }
 
 static int session_open_vt(Session *s) {
index d054c33..2024468 100644 (file)
@@ -89,8 +89,12 @@ struct Session {
         char *service;
         char *desktop;
 
+        /* always NULL */
         char *scope;
+/// UNNEEDED (and unsupported) by elogind
+#if 0
         char *scope_job;
+#endif // 0
 
         Seat *seat;
         unsigned int vtnr;
index 987244e..2733117 100644 (file)
 #include "bus-error.h"
 #include "conf-parser.h"
 #include "clean-ipc.h"
-#include "logind-user.h"
 #include "smack-util.h"
 #include "formats-util.h"
+#include "label.h"
+#include "logind-user.h"
 
 User* user_new(Manager *m, uid_t uid, gid_t gid, const char *name) {
         User *u;
@@ -93,8 +94,11 @@ void user_free(User *u) {
                 free(u->service);
         }
 
+/// elogind does not support slice and service jobs
+#if 0
         free(u->slice_job);
         free(u->service_job);
+#endif // 0
 
         free(u->runtime_path);
 
@@ -105,7 +109,7 @@ void user_free(User *u) {
         free(u);
 }
 
-int user_save(User *u) {
+static int user_save_internal(User *u) {
         _cleanup_free_ char *temp_path = NULL;
         _cleanup_fclose_ FILE *f = NULL;
         int r;
@@ -113,9 +117,6 @@ int user_save(User *u) {
         assert(u);
         assert(u->state_file);
 
-        if (!u->started)
-                return 0;
-
         r = mkdir_safe_label("/run/systemd/users", 0755, 0, 0);
         if (r < 0)
                 goto fail;
@@ -138,13 +139,19 @@ int user_save(User *u) {
 
         if (u->service)
                 fprintf(f, "SERVICE=%s\n", u->service);
+/// elogind does not support service jobs
+#if 0
         if (u->service_job)
                 fprintf(f, "SERVICE_JOB=%s\n", u->service_job);
+#endif // 0
 
         if (u->slice)
                 fprintf(f, "SLICE=%s\n", u->slice);
+/// elogind does not support slice jobs
+#if 0
         if (u->slice_job)
                 fprintf(f, "SLICE_JOB=%s\n", u->slice_job);
+#endif // 0
 
         if (u->display)
                 fprintf(f, "DISPLAY=%s\n", u->display->id);
@@ -263,6 +270,15 @@ fail:
         return log_error_errno(r, "Failed to save user data %s: %m", u->state_file);
 }
 
+int user_save(User *u) {
+        assert(u);
+
+        if (!u->started)
+                return 0;
+
+        return user_save_internal (u);
+}
+
 int user_load(User *u) {
         _cleanup_free_ char *display = NULL, *realtime = NULL, *monotonic = NULL;
         Session *s = NULL;
@@ -273,9 +289,15 @@ int user_load(User *u) {
         r = parse_env_file(u->state_file, NEWLINE,
                            "RUNTIME",     &u->runtime_path,
                            "SERVICE",     &u->service,
+/// elogind does not support service jobs
+#if 0
                            "SERVICE_JOB", &u->service_job,
+#endif // 0
                            "SLICE",       &u->slice,
+/// elogind does not support slice jobs
+#if 0
                            "SLICE_JOB",   &u->slice_job,
+#endif // 0
                            "DISPLAY",     &display,
                            "REALTIME",    &realtime,
                            "MONOTONIC",   &monotonic,
@@ -325,10 +347,10 @@ static int user_mkdir_runtime_path(User *u) {
         } else
                 p = u->runtime_path;
 
-        if (path_is_mount_point(p, false) <= 0) {
+        if (path_is_mount_point(p, 0) <= 0) {
                 _cleanup_free_ char *t = NULL;
 
-                (void) mkdir(p, 0700);
+                (void) mkdir_label(p, 0700);
 
                 if (mac_smack_use())
                         r = asprintf(&t, "mode=0700,smackfsroot=*,uid=" UID_FMT ",gid=" GID_FMT ",size=%zu", u->uid, u->gid, u->manager->runtime_dir_size);
@@ -356,6 +378,10 @@ static int user_mkdir_runtime_path(User *u) {
                                 goto fail;
                         }
                 }
+
+                r = label_fix(p, false, false);
+                if (r < 0)
+                        log_warning_errno(r, "Failed to fix label of '%s', ignoring: %m", p);
         }
 
         u->runtime_path = p;
@@ -373,7 +399,7 @@ fail:
 }
 
 static int user_start_slice(User *u) {
-        char *job;
+        // char *job;
         int r;
 
         assert(u);
@@ -387,15 +413,21 @@ static int user_start_slice(User *u) {
                 if (r < 0)
                         return r;
 
+/// elogind : Do not try to use dbus to ask systemd
+#if 0
                 r = manager_start_unit(u->manager, slice, &error, &job);
+#endif // 0
                 if (r < 0) {
                         log_error("Failed to start user slice: %s", bus_error_message(&error, r));
                         free(slice);
                 } else {
                         u->slice = slice;
 
+/// elogind does not support slice jobs
+#if 0
                         free(u->slice_job);
                         u->slice_job = job;
+#endif // 0
                 }
         }
 
@@ -407,7 +439,7 @@ static int user_start_slice(User *u) {
 
 static int user_start_service(User *u) {
         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
-        char *job;
+        // char *job;
         int r;
 
         assert(u);
@@ -420,15 +452,21 @@ static int user_start_service(User *u) {
                 if (r < 0)
                         return log_error_errno(r, "Failed to build service name: %m");
 
+/// elogind : Do not try to use dbus to ask systemd
+#if 0
                 r = manager_start_unit(u->manager, service, &error, &job);
+#endif // 0
                 if (r < 0) {
                         log_error("Failed to start user service: %s", bus_error_message(&error, r));
                         free(service);
                 } else {
                         u->service = service;
 
+/// elogind does not support service jobs
+#if 0
                         free(u->service_job);
                         u->service_job = job;
+#endif // 0
                 }
         }
 
@@ -458,6 +496,12 @@ int user_start(User *u) {
         if (r < 0)
                 return r;
 
+        /* Save the user data so far, because pam_systemd will read the
+         * XDG_RUNTIME_DIR out of it while starting up systemd --user.
+         * We need to do user_save_internal() because we have not
+         * "officially" started yet. */
+        user_save_internal(u);
+
         /* Spawn user systemd */
         r = user_start_service(u);
         if (r < 0)
@@ -476,10 +520,12 @@ int user_start(User *u) {
         return 0;
 }
 
+/// UNNEEDED by elogind
+#if 0
 static int user_stop_slice(User *u) {
         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
-        char *job;
-        int r;
+        // char *job;
+        int r = 0;
 
         assert(u);
 
@@ -500,8 +546,8 @@ static int user_stop_slice(User *u) {
 
 static int user_stop_service(User *u) {
         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
-        char *job;
-        int r;
+        // char *job;
+        int r = 0;
 
         assert(u);
 
@@ -519,6 +565,7 @@ static int user_stop_service(User *u) {
 
         return r;
 }
+#endif // 0
 
 static int user_remove_runtime_path(User *u) {
         int r;
@@ -567,6 +614,8 @@ int user_stop(User *u, bool force) {
         }
 
         /* Kill systemd */
+/// elogind does not support service or slice jobs
+#if 0
         k = user_stop_service(u);
         if (k < 0)
                 r = k;
@@ -575,6 +624,7 @@ int user_stop(User *u, bool force) {
         k = user_stop_slice(u);
         if (k < 0)
                 r = k;
+#endif // 0
 
         u->stopping = true;
 
@@ -624,7 +674,7 @@ int user_finalize(User *u) {
 int user_get_idle_hint(User *u, dual_timestamp *t) {
         Session *s;
         bool idle_hint = true;
-        dual_timestamp ts = { 0, 0 };
+        dual_timestamp ts = DUAL_TIMESTAMP_NULL;
 
         assert(u);
 
@@ -682,11 +732,14 @@ bool user_check_gc(User *u, bool drop_not_started) {
         if (user_check_linger_file(u) > 0)
                 return true;
 
+/// elogind does not support systemd services and slices
+#if 0
         if (u->slice_job && manager_job_is_active(u->manager, u->slice_job))
                 return true;
 
         if (u->service_job && manager_job_is_active(u->manager, u->service_job))
                 return true;
+#endif // 0
 
         return false;
 }
@@ -709,7 +762,12 @@ UserState user_get_state(User *u) {
         if (u->stopping)
                 return USER_CLOSING;
 
-        if (u->slice_job || u->service_job)
+/// elogind does not support slice and service jobs
+#if 0
+        if (!u->started || u->slice_job || u->service_job)
+#else
+        if (!u->started)
+#endif // 0
                 return USER_OPENING;
 
         if (u->sessions) {
@@ -737,60 +795,84 @@ UserState user_get_state(User *u) {
 int user_kill(User *u, int signo) {
         assert(u);
 
+/// FIXME: Without direct cgroup support, elogind can not kill users
+#if 0
         if (!u->slice)
                 return -ESRCH;
 
         return manager_kill_unit(u->manager, u->slice, KILL_ALL, signo, NULL);
+#else
+        return -ESRCH;
+#endif // 0
+}
+
+static bool elect_display_filter(Session *s) {
+        /* Return true if the session is a candidate for the user’s ‘primary
+         * session’ or ‘display’. */
+        assert(s);
+
+        return (s->class == SESSION_USER && !s->stopping);
+}
+
+static int elect_display_compare(Session *s1, Session *s2) {
+        /* Indexed by SessionType. Lower numbers mean more preferred. */
+        const int type_ranks[_SESSION_TYPE_MAX] = {
+                [SESSION_UNSPECIFIED] = 0,
+                [SESSION_TTY] = -2,
+                [SESSION_X11] = -3,
+                [SESSION_WAYLAND] = -3,
+                [SESSION_MIR] = -3,
+                [SESSION_WEB] = -1,
+        };
+
+        /* Calculate the partial order relationship between s1 and s2,
+         * returning < 0 if s1 is preferred as the user’s ‘primary session’,
+         * 0 if s1 and s2 are equally preferred or incomparable, or > 0 if s2
+         * is preferred.
+         *
+         * s1 or s2 may be NULL. */
+        if (!s1 && !s2)
+                return 0;
+
+        if ((s1 == NULL) != (s2 == NULL))
+                return (s1 == NULL) - (s2 == NULL);
+
+        if (s1->stopping != s2->stopping)
+                return s1->stopping - s2->stopping;
+
+        if ((s1->class != SESSION_USER) != (s2->class != SESSION_USER))
+                return (s1->class != SESSION_USER) - (s2->class != SESSION_USER);
+
+        if ((s1->type == _SESSION_TYPE_INVALID) != (s2->type == _SESSION_TYPE_INVALID))
+                return (s1->type == _SESSION_TYPE_INVALID) - (s2->type == _SESSION_TYPE_INVALID);
+
+        if (s1->type != s2->type)
+                return type_ranks[s1->type] - type_ranks[s2->type];
+
+        return 0;
 }
 
 void user_elect_display(User *u) {
-        Session *graphical = NULL, *text = NULL, *other = NULL, *s;
+        Session *s;
 
         assert(u);
 
         /* This elects a primary session for each user, which we call
          * the "display". We try to keep the assignment stable, but we
          * "upgrade" to better choices. */
+        log_debug("Electing new display for user %s", u->name);
 
         LIST_FOREACH(sessions_by_user, s, u->sessions) {
-
-                if (s->class != SESSION_USER)
+                if (!elect_display_filter(s)) {
+                        log_debug("Ignoring session %s", s->id);
                         continue;
+                }
 
-                if (s->stopping)
-                        continue;
-
-                if (SESSION_TYPE_IS_GRAPHICAL(s->type))
-                        graphical = s;
-                else if (s->type == SESSION_TTY)
-                        text = s;
-                else
-                        other = s;
-        }
-
-        if (graphical &&
-            (!u->display ||
-             u->display->class != SESSION_USER ||
-             u->display->stopping ||
-             !SESSION_TYPE_IS_GRAPHICAL(u->display->type))) {
-                u->display = graphical;
-                return;
-        }
-
-        if (text &&
-            (!u->display ||
-             u->display->class != SESSION_USER ||
-             u->display->stopping ||
-             u->display->type != SESSION_TTY)) {
-                u->display = text;
-                return;
+                if (elect_display_compare(s, u->display) < 0) {
+                        log_debug("Choosing session %s in preference to %s", s->id, u->display ? u->display->id : "-");
+                        u->display = s;
+                }
         }
-
-        if (other &&
-            (!u->display ||
-             u->display->class != SESSION_USER ||
-             u->display->stopping))
-                u->display = other;
 }
 
 static const char* const user_state_table[_USER_STATE_MAX] = {
index 7222478..b30e7d6 100644 (file)
@@ -47,11 +47,17 @@ struct User {
         char *state_file;
         char *runtime_path;
 
+        /* These are always NULL, and here just for logind-user-dbus.c
+           to easily provide a NULL value for the user's service and
+           slice properties. */
         char *service;
         char *slice;
 
+/// UNNEEDED (and unsupported) by elogind
+#if 0
         char *service_job;
         char *slice_job;
+#endif // 0
 
         Session *display;
 
index c0ae523..a74a3e4 100644 (file)
@@ -185,13 +185,13 @@ int bus_manager_shutdown_or_sleep_now_or_later(Manager *m, const char *unit_name
 
 int manager_send_changed(Manager *manager, const char *property, ...) _sentinel_;
 
-int manager_start_scope(Manager *manager, const char *scope, pid_t pid, const char *slice, const char *description, const char *after, const char *after2, sd_bus_error *error, char **job);
-int manager_start_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job);
-int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job);
-int manager_abandon_scope(Manager *manager, const char *scope, sd_bus_error *error);
-int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, sd_bus_error *error);
-int manager_unit_is_active(Manager *manager, const char *unit);
-int manager_job_is_active(Manager *manager, const char *path);
+// UNNEEDED int manager_start_scope(Manager *manager, const char *scope, pid_t pid, const char *slice, const char *description, const char *after, const char *after2, sd_bus_error *error, char **job);
+// UNNEEDED int manager_start_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job);
+// UNNEEDED int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job);
+// UNNEEDED int manager_abandon_scope(Manager *manager, const char *scope, sd_bus_error *error);
+// UNNEEDED int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, sd_bus_error *error);
+// UNNEEDED int manager_unit_is_active(Manager *manager, const char *unit);
+// UNNEEDED int manager_job_is_active(Manager *manager, const char *path);
 
 /* gperf lookup function */
 const struct ConfigPerfItem* logind_gperf_lookup(const char *key, GPERF_LEN_TYPE length);