chiark / gitweb /
sd-login: beef up login api, to add monitoring and enumerating
[elogind.git] / src / logind-user.c
index 8ebd6eca235b1a3e7803006872ed13b50d46294d..3c245c09272ec57563b53b0246d540aad37c9e0f 100644 (file)
@@ -94,6 +94,9 @@ int user_save(User *u) {
         assert(u);
         assert(u->state_file);
 
+        if (!u->started)
+                return 0;
+
         r = safe_mkdir("/run/systemd/users", 0755, 0, 0);
         if (r < 0)
                 goto finish;
@@ -131,6 +134,44 @@ int user_save(User *u) {
                         "DISPLAY=%s\n",
                         u->display->id);
 
+        if (u->sessions) {
+                Session *i;
+
+                fputs("SESSIONS=", f);
+                LIST_FOREACH(sessions_by_user, i, u->sessions) {
+                        fprintf(f,
+                                "%s%c",
+                                i->id,
+                                i->sessions_by_seat_next ? ' ' : '\n');
+                }
+
+                fputs("SEATS=", f);
+                LIST_FOREACH(sessions_by_user, i, u->sessions) {
+                        if (i->seat)
+                                fprintf(f,
+                                        "%s%c",
+                                        i->seat->id,
+                                        i->sessions_by_seat_next ? ' ' : '\n');
+                }
+
+                fputs("ACTIVE_SESSIONS=", f);
+                LIST_FOREACH(sessions_by_user, i, u->sessions)
+                        if (session_is_active(i))
+                                fprintf(f,
+                                        "%lu%c",
+                                        (unsigned long) i->user->uid,
+                                        i->sessions_by_seat_next ? ' ' : '\n');
+
+                fputs("ACTIVE_SEATS=", f);
+                LIST_FOREACH(sessions_by_user, i, u->sessions) {
+                        if (session_is_active(i) && i->seat)
+                                fprintf(f,
+                                        "%s%c",
+                                        i->seat->id,
+                                        i->sessions_by_seat_next ? ' ' : '\n');
+                }
+        }
+
         fflush(f);
 
         if (ferror(f) || rename(temp_path, u->state_file) < 0) {
@@ -177,7 +218,7 @@ int user_load(User *u) {
                 free(display);
         }
 
-        if (s && s->display && x11_display_is_local(s->display))
+        if (s && s->display && display_is_local(s->display))
                 u->display = s;
 
         return r;
@@ -234,15 +275,19 @@ static int user_create_cgroup(User *u) {
 
         r = cg_create(SYSTEMD_CGROUP_CONTROLLER, p);
         if (r < 0) {
+                log_error("Failed to create cgroup "SYSTEMD_CGROUP_CONTROLLER":%s: %s", p, strerror(-r));
                 free(p);
                 u->cgroup_path = NULL;
-                log_error("Failed to create cgroup "SYSTEMD_CGROUP_CONTROLLER":%s: %s", p, strerror(-r));
                 return r;
         }
 
         u->cgroup_path = p;
 
         STRV_FOREACH(k, u->manager->controllers) {
+
+                if (strv_contains(u->manager->reset_controllers, *k))
+                        continue;
+
                 r = cg_create(*k, p);
                 if (r < 0)
                         log_warning("Failed to create cgroup %s:%s: %s", *k, p, strerror(-r));
@@ -265,6 +310,8 @@ int user_start(User *u) {
         if (u->started)
                 return 0;
 
+        log_info("New user %s logged in.", u->name);
+
         /* Make XDG_RUNTIME_DIR */
         r = user_mkdir_runtime_path(u);
         if (r < 0)
@@ -280,13 +327,13 @@ int user_start(User *u) {
         if (r < 0)
                 return r;
 
-        /* Save new user data */
-        user_save(u);
-
         dual_timestamp_get(&u->timestamp);
 
         u->started = true;
 
+        /* Save new user data */
+        user_save(u);
+
         user_send_signal(u, true);
 
         return 0;
@@ -304,10 +351,19 @@ static int user_stop_service(User *u) {
 static int user_shall_kill(User *u) {
         assert(u);
 
-        return u->manager->kill_user_processes;
+        if (!u->manager->kill_user_processes)
+                return false;
+
+        if (strv_contains(u->manager->kill_exclude_users, u->name))
+                return false;
+
+        if (strv_isempty(u->manager->kill_only_users))
+                return true;
+
+        return strv_contains(u->manager->kill_only_users, u->name);
 }
 
-static int user_kill_cgroup(User *u) {
+static int user_terminate_cgroup(User *u) {
         int r;
         char **k;
 
@@ -368,8 +424,8 @@ int user_stop(User *u) {
         int r = 0, k;
         assert(u);
 
-        if (!u->started)
-                return 0;
+        if (u->started)
+                log_info("User %s logged out.", u->name);
 
         LIST_FOREACH(sessions_by_user, s, u->sessions) {
                 k = session_stop(s);
@@ -377,15 +433,13 @@ int user_stop(User *u) {
                         r = k;
         }
 
-        user_send_signal(u, false);
-
         /* Kill systemd */
         k = user_stop_service(u);
         if (k < 0)
                 r = k;
 
         /* Kill cgroup */
-        k = user_kill_cgroup(u);
+        k = user_terminate_cgroup(u);
         if (k < 0)
                 r = k;
 
@@ -397,6 +451,9 @@ int user_stop(User *u) {
         unlink(u->state_file);
         user_add_to_gc_queue(u);
 
+        if (u->started)
+                user_send_signal(u, false);
+
         u->started = false;
 
         return r;
@@ -438,12 +495,15 @@ int user_get_idle_hint(User *u, dual_timestamp *t) {
         return idle_hint;
 }
 
-int user_check_gc(User *u) {
+int user_check_gc(User *u, bool drop_not_started) {
         int r;
         char *p;
 
         assert(u);
 
+        if (drop_not_started && !u->started)
+                return 0;
+
         if (u->sessions)
                 return 1;
 
@@ -493,6 +553,30 @@ UserState user_get_state(User *u) {
         return USER_ONLINE;
 }
 
+int user_kill(User *u, int signo) {
+        int r = 0, q;
+        Set *pid_set = NULL;
+
+        assert(u);
+
+        if (!u->cgroup_path)
+                return -ESRCH;
+
+        pid_set = set_new(trivial_hash_func, trivial_compare_func);
+        if (!pid_set)
+                return -ENOMEM;
+
+        q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, signo, false, true, false, pid_set);
+        if (q < 0)
+                if (q != -EAGAIN && q != -ESRCH && q != -ENOENT)
+                        r = q;
+
+        if (pid_set)
+                set_free(pid_set);
+
+        return r;
+}
+
 static const char* const user_state_table[_USER_STATE_MAX] = {
         [USER_OFFLINE] = "offline",
         [USER_LINGERING] = "lingering",