LCOV - code coverage report
Current view: top level - login - logind-user.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 1 424 0.2 %
Date: 2019-08-22 15:41:25 Functions: 2 26 7.7 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : 
       3             : #include <errno.h>
       4             : #include <string.h>
       5             : #include <unistd.h>
       6             : 
       7             : #include "alloc-util.h"
       8             : #include "bus-common-errors.h"
       9             : #include "bus-error.h"
      10             : #include "bus-util.h"
      11             : #include "cgroup-util.h"
      12             : #include "clean-ipc.h"
      13             : #include "env-file.h"
      14             : #include "escape.h"
      15             : #include "fd-util.h"
      16             : #include "fileio.h"
      17             : #include "format-util.h"
      18             : #include "fs-util.h"
      19             : #include "hashmap.h"
      20             : #include "label.h"
      21             : #include "limits-util.h"
      22             : #include "logind-dbus.h"
      23             : #include "logind-user.h"
      24             : #include "logind-user-dbus.h"
      25             : #include "mkdir.h"
      26             : #include "parse-util.h"
      27             : #include "path-util.h"
      28             : #include "rm-rf.h"
      29             : #include "serialize.h"
      30             : #include "special.h"
      31             : #include "stdio-util.h"
      32             : #include "string-table.h"
      33             : #include "strv.h"
      34             : #include "tmpfile-util.h"
      35             : #include "unit-name.h"
      36             : #include "user-util.h"
      37             : #include "util.h"
      38             : 
      39           0 : int user_new(User **ret,
      40             :              Manager *m,
      41             :              uid_t uid,
      42             :              gid_t gid,
      43             :              const char *name,
      44             :              const char *home) {
      45             : 
      46           0 :         _cleanup_(user_freep) User *u = NULL;
      47             :         char lu[DECIMAL_STR_MAX(uid_t) + 1];
      48             :         int r;
      49             : 
      50           0 :         assert(ret);
      51           0 :         assert(m);
      52           0 :         assert(name);
      53             : 
      54           0 :         u = new(User, 1);
      55           0 :         if (!u)
      56           0 :                 return -ENOMEM;
      57             : 
      58           0 :         *u = (User) {
      59             :                 .manager = m,
      60             :                 .uid = uid,
      61             :                 .gid = gid,
      62             :                 .last_session_timestamp = USEC_INFINITY,
      63             :         };
      64             : 
      65           0 :         u->name = strdup(name);
      66           0 :         if (!u->name)
      67           0 :                 return -ENOMEM;
      68             : 
      69           0 :         u->home = strdup(home);
      70           0 :         if (!u->home)
      71           0 :                 return -ENOMEM;
      72             : 
      73           0 :         path_simplify(u->home, true);
      74             : 
      75           0 :         if (asprintf(&u->state_file, "/run/systemd/users/"UID_FMT, uid) < 0)
      76           0 :                 return -ENOMEM;
      77             : 
      78           0 :         if (asprintf(&u->runtime_path, "/run/user/"UID_FMT, uid) < 0)
      79           0 :                 return -ENOMEM;
      80             : 
      81           0 :         xsprintf(lu, UID_FMT, uid);
      82           0 :         r = slice_build_subslice(SPECIAL_USER_SLICE, lu, &u->slice);
      83           0 :         if (r < 0)
      84           0 :                 return r;
      85             : 
      86           0 :         r = unit_name_build("user", lu, ".service", &u->service);
      87           0 :         if (r < 0)
      88           0 :                 return r;
      89             : 
      90           0 :         r = unit_name_build("user-runtime-dir", lu, ".service", &u->runtime_dir_service);
      91           0 :         if (r < 0)
      92           0 :                 return r;
      93             : 
      94           0 :         r = hashmap_put(m->users, UID_TO_PTR(uid), u);
      95           0 :         if (r < 0)
      96           0 :                 return r;
      97             : 
      98           0 :         r = hashmap_put(m->user_units, u->slice, u);
      99           0 :         if (r < 0)
     100           0 :                 return r;
     101             : 
     102           0 :         r = hashmap_put(m->user_units, u->service, u);
     103           0 :         if (r < 0)
     104           0 :                 return r;
     105             : 
     106           0 :         r = hashmap_put(m->user_units, u->runtime_dir_service, u);
     107           0 :         if (r < 0)
     108           0 :                 return r;
     109             : 
     110           0 :         *ret = TAKE_PTR(u);
     111           0 :         return 0;
     112             : }
     113             : 
     114           0 : User *user_free(User *u) {
     115           0 :         if (!u)
     116           0 :                 return NULL;
     117             : 
     118           0 :         if (u->in_gc_queue)
     119           0 :                 LIST_REMOVE(gc_queue, u->manager->user_gc_queue, u);
     120             : 
     121           0 :         while (u->sessions)
     122           0 :                 session_free(u->sessions);
     123             : 
     124           0 :         if (u->service)
     125           0 :                 hashmap_remove_value(u->manager->user_units, u->service, u);
     126             : 
     127           0 :         if (u->runtime_dir_service)
     128           0 :                 hashmap_remove_value(u->manager->user_units, u->runtime_dir_service, u);
     129             : 
     130           0 :         if (u->slice)
     131           0 :                 hashmap_remove_value(u->manager->user_units, u->slice, u);
     132             : 
     133           0 :         hashmap_remove_value(u->manager->users, UID_TO_PTR(u->uid), u);
     134             : 
     135           0 :         (void) sd_event_source_unref(u->timer_event_source);
     136             : 
     137           0 :         u->service_job = mfree(u->service_job);
     138             : 
     139           0 :         u->service = mfree(u->service);
     140           0 :         u->runtime_dir_service = mfree(u->runtime_dir_service);
     141           0 :         u->slice = mfree(u->slice);
     142           0 :         u->runtime_path = mfree(u->runtime_path);
     143           0 :         u->state_file = mfree(u->state_file);
     144           0 :         u->name = mfree(u->name);
     145           0 :         u->home = mfree(u->home);
     146             : 
     147           0 :         return mfree(u);
     148             : }
     149             : 
     150           0 : static int user_save_internal(User *u) {
     151           0 :         _cleanup_free_ char *temp_path = NULL;
     152           0 :         _cleanup_fclose_ FILE *f = NULL;
     153             :         int r;
     154             : 
     155           0 :         assert(u);
     156           0 :         assert(u->state_file);
     157             : 
     158           0 :         r = mkdir_safe_label("/run/systemd/users", 0755, 0, 0, MKDIR_WARN_MODE);
     159           0 :         if (r < 0)
     160           0 :                 goto fail;
     161             : 
     162           0 :         r = fopen_temporary(u->state_file, &f, &temp_path);
     163           0 :         if (r < 0)
     164           0 :                 goto fail;
     165             : 
     166           0 :         (void) fchmod(fileno(f), 0644);
     167             : 
     168           0 :         fprintf(f,
     169             :                 "# This is private data. Do not parse.\n"
     170             :                 "NAME=%s\n"
     171             :                 "STATE=%s\n"         /* friendly user-facing state */
     172             :                 "STOPPING=%s\n",     /* low-level state */
     173             :                 u->name,
     174             :                 user_state_to_string(user_get_state(u)),
     175           0 :                 yes_no(u->stopping));
     176             : 
     177             :         /* LEGACY: no-one reads RUNTIME= anymore, drop it at some point */
     178           0 :         if (u->runtime_path)
     179           0 :                 fprintf(f, "RUNTIME=%s\n", u->runtime_path);
     180             : 
     181           0 :         if (u->service_job)
     182           0 :                 fprintf(f, "SERVICE_JOB=%s\n", u->service_job);
     183             : 
     184           0 :         if (u->display)
     185           0 :                 fprintf(f, "DISPLAY=%s\n", u->display->id);
     186             : 
     187           0 :         if (dual_timestamp_is_set(&u->timestamp))
     188           0 :                 fprintf(f,
     189             :                         "REALTIME="USEC_FMT"\n"
     190             :                         "MONOTONIC="USEC_FMT"\n",
     191             :                         u->timestamp.realtime,
     192             :                         u->timestamp.monotonic);
     193             : 
     194           0 :         if (u->last_session_timestamp != USEC_INFINITY)
     195           0 :                 fprintf(f, "LAST_SESSION_TIMESTAMP=" USEC_FMT "\n",
     196             :                         u->last_session_timestamp);
     197             : 
     198           0 :         if (u->sessions) {
     199             :                 Session *i;
     200             :                 bool first;
     201             : 
     202           0 :                 fputs("SESSIONS=", f);
     203           0 :                 first = true;
     204           0 :                 LIST_FOREACH(sessions_by_user, i, u->sessions) {
     205           0 :                         if (first)
     206           0 :                                 first = false;
     207             :                         else
     208           0 :                                 fputc(' ', f);
     209             : 
     210           0 :                         fputs(i->id, f);
     211             :                 }
     212             : 
     213           0 :                 fputs("\nSEATS=", f);
     214           0 :                 first = true;
     215           0 :                 LIST_FOREACH(sessions_by_user, i, u->sessions) {
     216           0 :                         if (!i->seat)
     217           0 :                                 continue;
     218             : 
     219           0 :                         if (first)
     220           0 :                                 first = false;
     221             :                         else
     222           0 :                                 fputc(' ', f);
     223             : 
     224           0 :                         fputs(i->seat->id, f);
     225             :                 }
     226             : 
     227           0 :                 fputs("\nACTIVE_SESSIONS=", f);
     228           0 :                 first = true;
     229           0 :                 LIST_FOREACH(sessions_by_user, i, u->sessions) {
     230           0 :                         if (!session_is_active(i))
     231           0 :                                 continue;
     232             : 
     233           0 :                         if (first)
     234           0 :                                 first = false;
     235             :                         else
     236           0 :                                 fputc(' ', f);
     237             : 
     238           0 :                         fputs(i->id, f);
     239             :                 }
     240             : 
     241           0 :                 fputs("\nONLINE_SESSIONS=", f);
     242           0 :                 first = true;
     243           0 :                 LIST_FOREACH(sessions_by_user, i, u->sessions) {
     244           0 :                         if (session_get_state(i) == SESSION_CLOSING)
     245           0 :                                 continue;
     246             : 
     247           0 :                         if (first)
     248           0 :                                 first = false;
     249             :                         else
     250           0 :                                 fputc(' ', f);
     251             : 
     252           0 :                         fputs(i->id, f);
     253             :                 }
     254             : 
     255           0 :                 fputs("\nACTIVE_SEATS=", f);
     256           0 :                 first = true;
     257           0 :                 LIST_FOREACH(sessions_by_user, i, u->sessions) {
     258           0 :                         if (!session_is_active(i) || !i->seat)
     259           0 :                                 continue;
     260             : 
     261           0 :                         if (first)
     262           0 :                                 first = false;
     263             :                         else
     264           0 :                                 fputc(' ', f);
     265             : 
     266           0 :                         fputs(i->seat->id, f);
     267             :                 }
     268             : 
     269           0 :                 fputs("\nONLINE_SEATS=", f);
     270           0 :                 first = true;
     271           0 :                 LIST_FOREACH(sessions_by_user, i, u->sessions) {
     272           0 :                         if (session_get_state(i) == SESSION_CLOSING || !i->seat)
     273           0 :                                 continue;
     274             : 
     275           0 :                         if (first)
     276           0 :                                 first = false;
     277             :                         else
     278           0 :                                 fputc(' ', f);
     279             : 
     280           0 :                         fputs(i->seat->id, f);
     281             :                 }
     282           0 :                 fputc('\n', f);
     283             :         }
     284             : 
     285           0 :         r = fflush_and_check(f);
     286           0 :         if (r < 0)
     287           0 :                 goto fail;
     288             : 
     289           0 :         if (rename(temp_path, u->state_file) < 0) {
     290           0 :                 r = -errno;
     291           0 :                 goto fail;
     292             :         }
     293             : 
     294           0 :         return 0;
     295             : 
     296           0 : fail:
     297           0 :         (void) unlink(u->state_file);
     298             : 
     299           0 :         if (temp_path)
     300           0 :                 (void) unlink(temp_path);
     301             : 
     302           0 :         return log_error_errno(r, "Failed to save user data %s: %m", u->state_file);
     303             : }
     304             : 
     305           0 : int user_save(User *u) {
     306           0 :         assert(u);
     307             : 
     308           0 :         if (!u->started)
     309           0 :                 return 0;
     310             : 
     311           0 :         return user_save_internal(u);
     312             : }
     313             : 
     314           0 : int user_load(User *u) {
     315           0 :         _cleanup_free_ char *realtime = NULL, *monotonic = NULL, *stopping = NULL, *last_session_timestamp = NULL;
     316             :         int r;
     317             : 
     318           0 :         assert(u);
     319             : 
     320           0 :         r = parse_env_file(NULL, u->state_file,
     321             :                            "SERVICE_JOB",            &u->service_job,
     322             :                            "STOPPING",               &stopping,
     323             :                            "REALTIME",               &realtime,
     324             :                            "MONOTONIC",              &monotonic,
     325             :                            "LAST_SESSION_TIMESTAMP", &last_session_timestamp);
     326           0 :         if (r == -ENOENT)
     327           0 :                 return 0;
     328           0 :         if (r < 0)
     329           0 :                 return log_error_errno(r, "Failed to read %s: %m", u->state_file);
     330             : 
     331           0 :         if (stopping) {
     332           0 :                 r = parse_boolean(stopping);
     333           0 :                 if (r < 0)
     334           0 :                         log_debug_errno(r, "Failed to parse 'STOPPING' boolean: %s", stopping);
     335             :                 else
     336           0 :                         u->stopping = r;
     337             :         }
     338             : 
     339           0 :         if (realtime)
     340           0 :                 (void) deserialize_usec(realtime, &u->timestamp.realtime);
     341           0 :         if (monotonic)
     342           0 :                 (void) deserialize_usec(monotonic, &u->timestamp.monotonic);
     343           0 :         if (last_session_timestamp)
     344           0 :                 (void) deserialize_usec(last_session_timestamp, &u->last_session_timestamp);
     345             : 
     346           0 :         return 0;
     347             : }
     348             : 
     349           0 : static void user_start_service(User *u) {
     350           0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     351             :         int r;
     352             : 
     353           0 :         assert(u);
     354             : 
     355             :         /* Start the service containing the "systemd --user" instance (user@.service). Note that we don't explicitly
     356             :          * start the per-user slice or the systemd-runtime-dir@.service instance, as those are pulled in both by
     357             :          * user@.service and the session scopes as dependencies. */
     358             : 
     359           0 :         u->service_job = mfree(u->service_job);
     360             : 
     361           0 :         r = manager_start_unit(u->manager, u->service, &error, &u->service_job);
     362           0 :         if (r < 0)
     363           0 :                 log_full_errno(sd_bus_error_has_name(&error, BUS_ERROR_UNIT_MASKED) ? LOG_DEBUG : LOG_WARNING, r,
     364             :                                "Failed to start user service '%s', ignoring: %s", u->service, bus_error_message(&error, r));
     365           0 : }
     366             : 
     367           0 : int user_start(User *u) {
     368           0 :         assert(u);
     369             : 
     370           0 :         if (u->started && !u->stopping)
     371           0 :                 return 0;
     372             : 
     373             :         /* If u->stopping is set, the user is marked for removal and service stop-jobs are queued. We have to clear
     374             :          * that flag before queueing the start-jobs again. If they succeed, the user object can be re-used just fine
     375             :          * (pid1 takes care of job-ordering and proper restart), but if they fail, we want to force another user_stop()
     376             :          * so possibly pending units are stopped. */
     377           0 :         u->stopping = false;
     378             : 
     379           0 :         if (!u->started)
     380           0 :                 log_debug("Starting services for new user %s.", u->name);
     381             : 
     382             :         /* Save the user data so far, because pam_systemd will read the XDG_RUNTIME_DIR out of it while starting up
     383             :          * systemd --user.  We need to do user_save_internal() because we have not "officially" started yet. */
     384           0 :         user_save_internal(u);
     385             : 
     386             :         /* Start user@UID.service */
     387           0 :         user_start_service(u);
     388             : 
     389           0 :         if (!u->started) {
     390           0 :                 if (!dual_timestamp_is_set(&u->timestamp))
     391           0 :                         dual_timestamp_get(&u->timestamp);
     392           0 :                 user_send_signal(u, true);
     393           0 :                 u->started = true;
     394             :         }
     395             : 
     396             :         /* Save new user data */
     397           0 :         user_save(u);
     398             : 
     399           0 :         return 0;
     400             : }
     401             : 
     402           0 : static void user_stop_service(User *u) {
     403           0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     404             :         int r;
     405             : 
     406           0 :         assert(u);
     407           0 :         assert(u->service);
     408             : 
     409             :         /* The reverse of user_start_service(). Note that we only stop user@UID.service here, and let StopWhenUnneeded=
     410             :          * deal with the slice and the user-runtime-dir@.service instance. */
     411             : 
     412           0 :         u->service_job = mfree(u->service_job);
     413             : 
     414           0 :         r = manager_stop_unit(u->manager, u->service, &error, &u->service_job);
     415           0 :         if (r < 0)
     416           0 :                 log_warning_errno(r, "Failed to stop user service '%s', ignoring: %s", u->service, bus_error_message(&error, r));
     417           0 : }
     418             : 
     419           0 : int user_stop(User *u, bool force) {
     420             :         Session *s;
     421           0 :         int r = 0;
     422           0 :         assert(u);
     423             : 
     424             :         /* This is called whenever we begin with tearing down a user record. It's called in two cases: explicit API
     425             :          * request to do so via the bus (in which case 'force' is true) and automatically due to GC, if there's no
     426             :          * session left pinning it (in which case 'force' is false). Note that this just initiates tearing down of the
     427             :          * user, the User object will remain in memory until user_finalize() is called, see below. */
     428             : 
     429           0 :         if (!u->started)
     430           0 :                 return 0;
     431             : 
     432           0 :         if (u->stopping) { /* Stop jobs have already been queued */
     433           0 :                 user_save(u);
     434           0 :                 return 0;
     435             :         }
     436             : 
     437           0 :         LIST_FOREACH(sessions_by_user, s, u->sessions) {
     438             :                 int k;
     439             : 
     440           0 :                 k = session_stop(s, force);
     441           0 :                 if (k < 0)
     442           0 :                         r = k;
     443             :         }
     444             : 
     445           0 :         user_stop_service(u);
     446             : 
     447           0 :         u->stopping = true;
     448             : 
     449           0 :         user_save(u);
     450             : 
     451           0 :         return r;
     452             : }
     453             : 
     454           0 : int user_finalize(User *u) {
     455             :         Session *s;
     456           0 :         int r = 0, k;
     457             : 
     458           0 :         assert(u);
     459             : 
     460             :         /* Called when the user is really ready to be freed, i.e. when all unit stop jobs and suchlike for it are
     461             :          * done. This is called as a result of an earlier user_done() when all jobs are completed. */
     462             : 
     463           0 :         if (u->started)
     464           0 :                 log_debug("User %s logged out.", u->name);
     465             : 
     466           0 :         LIST_FOREACH(sessions_by_user, s, u->sessions) {
     467           0 :                 k = session_finalize(s);
     468           0 :                 if (k < 0)
     469           0 :                         r = k;
     470             :         }
     471             : 
     472             :         /* Clean SysV + POSIX IPC objects, but only if this is not a system user. Background: in many setups cronjobs
     473             :          * are run in full PAM and thus logind sessions, even if the code run doesn't belong to actual users but to
     474             :          * system components. Since enable RemoveIPC= globally for all users, we need to be a bit careful with such
     475             :          * cases, as we shouldn't accidentally remove a system service's IPC objects while it is running, just because
     476             :          * a cronjob running as the same user just finished. Hence: exclude system users generally from IPC clean-up,
     477             :          * and do it only for normal users. */
     478           0 :         if (u->manager->remove_ipc && !uid_is_system(u->uid)) {
     479           0 :                 k = clean_ipc_by_uid(u->uid);
     480           0 :                 if (k < 0)
     481           0 :                         r = k;
     482             :         }
     483             : 
     484           0 :         (void) unlink(u->state_file);
     485           0 :         user_add_to_gc_queue(u);
     486             : 
     487           0 :         if (u->started) {
     488           0 :                 user_send_signal(u, false);
     489           0 :                 u->started = false;
     490             :         }
     491             : 
     492           0 :         return r;
     493             : }
     494             : 
     495           0 : int user_get_idle_hint(User *u, dual_timestamp *t) {
     496             :         Session *s;
     497           0 :         bool idle_hint = true;
     498           0 :         dual_timestamp ts = DUAL_TIMESTAMP_NULL;
     499             : 
     500           0 :         assert(u);
     501             : 
     502           0 :         LIST_FOREACH(sessions_by_user, s, u->sessions) {
     503             :                 dual_timestamp k;
     504             :                 int ih;
     505             : 
     506           0 :                 ih = session_get_idle_hint(s, &k);
     507           0 :                 if (ih < 0)
     508           0 :                         return ih;
     509             : 
     510           0 :                 if (!ih) {
     511           0 :                         if (!idle_hint) {
     512           0 :                                 if (k.monotonic < ts.monotonic)
     513           0 :                                         ts = k;
     514             :                         } else {
     515           0 :                                 idle_hint = false;
     516           0 :                                 ts = k;
     517             :                         }
     518           0 :                 } else if (idle_hint) {
     519             : 
     520           0 :                         if (k.monotonic > ts.monotonic)
     521           0 :                                 ts = k;
     522             :                 }
     523             :         }
     524             : 
     525           0 :         if (t)
     526           0 :                 *t = ts;
     527             : 
     528           0 :         return idle_hint;
     529             : }
     530             : 
     531           0 : int user_check_linger_file(User *u) {
     532           0 :         _cleanup_free_ char *cc = NULL;
     533           0 :         char *p = NULL;
     534             : 
     535           0 :         cc = cescape(u->name);
     536           0 :         if (!cc)
     537           0 :                 return -ENOMEM;
     538             : 
     539           0 :         p = strjoina("/var/lib/systemd/linger/", cc);
     540           0 :         if (access(p, F_OK) < 0) {
     541           0 :                 if (errno != ENOENT)
     542           0 :                         return -errno;
     543             : 
     544           0 :                 return false;
     545             :         }
     546             : 
     547           0 :         return true;
     548             : }
     549             : 
     550           0 : static bool user_unit_active(User *u) {
     551             :         const char *i;
     552             :         int r;
     553             : 
     554           0 :         assert(u->service);
     555           0 :         assert(u->runtime_dir_service);
     556           0 :         assert(u->slice);
     557             : 
     558           0 :         FOREACH_STRING(i, u->service, u->runtime_dir_service, u->slice) {
     559           0 :                 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     560             : 
     561           0 :                 r = manager_unit_is_active(u->manager, i, &error);
     562           0 :                 if (r < 0)
     563           0 :                         log_debug_errno(r, "Failed to determine whether unit '%s' is active, ignoring: %s", u->service, bus_error_message(&error, r));
     564           0 :                 if (r != 0)
     565           0 :                         return true;
     566             :         }
     567             : 
     568           0 :         return false;
     569             : }
     570             : 
     571           0 : bool user_may_gc(User *u, bool drop_not_started) {
     572             :         int r;
     573             : 
     574           0 :         assert(u);
     575             : 
     576           0 :         if (drop_not_started && !u->started)
     577           0 :                 return true;
     578             : 
     579           0 :         if (u->sessions)
     580           0 :                 return false;
     581             : 
     582           0 :         if (u->last_session_timestamp != USEC_INFINITY) {
     583             :                 /* All sessions have been closed. Let's see if we shall leave the user record around for a bit */
     584             : 
     585           0 :                 if (u->manager->user_stop_delay == USEC_INFINITY)
     586           0 :                         return false; /* Leave it around forever! */
     587           0 :                 if (u->manager->user_stop_delay > 0 &&
     588           0 :                     now(CLOCK_MONOTONIC) < usec_add(u->last_session_timestamp, u->manager->user_stop_delay))
     589           0 :                         return false; /* Leave it around for a bit longer. */
     590             :         }
     591             : 
     592             :         /* Is this a user that shall stay around forever ("linger")? Before we say "no" to GC'ing for lingering users, let's check
     593             :          * if any of the three units that we maintain for this user is still around. If none of them is,
     594             :          * there's no need to keep this user around even if lingering is enabled. */
     595           0 :         if (user_check_linger_file(u) > 0 && user_unit_active(u))
     596           0 :                 return false;
     597             : 
     598             :         /* Check if our job is still pending */
     599           0 :         if (u->service_job) {
     600           0 :                 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     601             : 
     602           0 :                 r = manager_job_is_active(u->manager, u->service_job, &error);
     603           0 :                 if (r < 0)
     604           0 :                         log_debug_errno(r, "Failed to determine whether job '%s' is pending, ignoring: %s", u->service_job, bus_error_message(&error, r));
     605           0 :                 if (r != 0)
     606           0 :                         return false;
     607             :         }
     608             : 
     609             :         /* Note that we don't care if the three units we manage for each user object are up or not, as we are managing
     610             :          * their state rather than tracking it. */
     611             : 
     612           0 :         return true;
     613             : }
     614             : 
     615           0 : void user_add_to_gc_queue(User *u) {
     616           0 :         assert(u);
     617             : 
     618           0 :         if (u->in_gc_queue)
     619           0 :                 return;
     620             : 
     621           0 :         LIST_PREPEND(gc_queue, u->manager->user_gc_queue, u);
     622           0 :         u->in_gc_queue = true;
     623             : }
     624             : 
     625           0 : UserState user_get_state(User *u) {
     626             :         Session *i;
     627             : 
     628           0 :         assert(u);
     629             : 
     630           0 :         if (u->stopping)
     631           0 :                 return USER_CLOSING;
     632             : 
     633           0 :         if (!u->started || u->service_job)
     634           0 :                 return USER_OPENING;
     635             : 
     636           0 :         if (u->sessions) {
     637           0 :                 bool all_closing = true;
     638             : 
     639           0 :                 LIST_FOREACH(sessions_by_user, i, u->sessions) {
     640             :                         SessionState state;
     641             : 
     642           0 :                         state = session_get_state(i);
     643           0 :                         if (state == SESSION_ACTIVE)
     644           0 :                                 return USER_ACTIVE;
     645           0 :                         if (state != SESSION_CLOSING)
     646           0 :                                 all_closing = false;
     647             :                 }
     648             : 
     649           0 :                 return all_closing ? USER_CLOSING : USER_ONLINE;
     650             :         }
     651             : 
     652           0 :         if (user_check_linger_file(u) > 0 && user_unit_active(u))
     653           0 :                 return USER_LINGERING;
     654             : 
     655           0 :         return USER_CLOSING;
     656             : }
     657             : 
     658           0 : int user_kill(User *u, int signo) {
     659           0 :         assert(u);
     660             : 
     661           0 :         return manager_kill_unit(u->manager, u->slice, KILL_ALL, signo, NULL);
     662             : }
     663             : 
     664           0 : static bool elect_display_filter(Session *s) {
     665             :         /* Return true if the session is a candidate for the user’s ‘primary session’ or ‘display’. */
     666           0 :         assert(s);
     667             : 
     668           0 :         return IN_SET(s->class, SESSION_USER, SESSION_GREETER) && s->started && !s->stopping;
     669             : }
     670             : 
     671           0 : static int elect_display_compare(Session *s1, Session *s2) {
     672             :         /* Indexed by SessionType. Lower numbers mean more preferred. */
     673             :         static const int type_ranks[_SESSION_TYPE_MAX] = {
     674             :                 [SESSION_UNSPECIFIED] = 0,
     675             :                 [SESSION_TTY] = -2,
     676             :                 [SESSION_X11] = -3,
     677             :                 [SESSION_WAYLAND] = -3,
     678             :                 [SESSION_MIR] = -3,
     679             :                 [SESSION_WEB] = -1,
     680             :         };
     681             : 
     682             :         /* Calculate the partial order relationship between s1 and s2,
     683             :          * returning < 0 if s1 is preferred as the user’s ‘primary session’,
     684             :          * 0 if s1 and s2 are equally preferred or incomparable, or > 0 if s2
     685             :          * is preferred.
     686             :          *
     687             :          * s1 or s2 may be NULL. */
     688           0 :         if (!s1 && !s2)
     689           0 :                 return 0;
     690             : 
     691           0 :         if ((s1 == NULL) != (s2 == NULL))
     692           0 :                 return (s1 == NULL) - (s2 == NULL);
     693             : 
     694           0 :         if (s1->stopping != s2->stopping)
     695           0 :                 return s1->stopping - s2->stopping;
     696             : 
     697           0 :         if ((s1->class != SESSION_USER) != (s2->class != SESSION_USER))
     698           0 :                 return (s1->class != SESSION_USER) - (s2->class != SESSION_USER);
     699             : 
     700           0 :         if ((s1->type == _SESSION_TYPE_INVALID) != (s2->type == _SESSION_TYPE_INVALID))
     701           0 :                 return (s1->type == _SESSION_TYPE_INVALID) - (s2->type == _SESSION_TYPE_INVALID);
     702             : 
     703           0 :         if (s1->type != s2->type)
     704           0 :                 return type_ranks[s1->type] - type_ranks[s2->type];
     705             : 
     706           0 :         return 0;
     707             : }
     708             : 
     709           0 : void user_elect_display(User *u) {
     710             :         Session *s;
     711             : 
     712           0 :         assert(u);
     713             : 
     714             :         /* This elects a primary session for each user, which we call the "display". We try to keep the assignment
     715             :          * stable, but we "upgrade" to better choices. */
     716           0 :         log_debug("Electing new display for user %s", u->name);
     717             : 
     718           0 :         LIST_FOREACH(sessions_by_user, s, u->sessions) {
     719           0 :                 if (!elect_display_filter(s)) {
     720           0 :                         log_debug("Ignoring session %s", s->id);
     721           0 :                         continue;
     722             :                 }
     723             : 
     724           0 :                 if (elect_display_compare(s, u->display) < 0) {
     725           0 :                         log_debug("Choosing session %s in preference to %s", s->id, u->display ? u->display->id : "-");
     726           0 :                         u->display = s;
     727             :                 }
     728             :         }
     729           0 : }
     730             : 
     731           0 : static int user_stop_timeout_callback(sd_event_source *es, uint64_t usec, void *userdata) {
     732           0 :         User *u = userdata;
     733             : 
     734           0 :         assert(u);
     735           0 :         user_add_to_gc_queue(u);
     736             : 
     737           0 :         return 0;
     738             : }
     739             : 
     740           0 : void user_update_last_session_timer(User *u) {
     741             :         int r;
     742             : 
     743           0 :         assert(u);
     744             : 
     745           0 :         if (u->sessions) {
     746             :                 /* There are sessions, turn off the timer */
     747           0 :                 u->last_session_timestamp = USEC_INFINITY;
     748           0 :                 u->timer_event_source = sd_event_source_unref(u->timer_event_source);
     749           0 :                 return;
     750             :         }
     751             : 
     752           0 :         if (u->last_session_timestamp != USEC_INFINITY)
     753           0 :                 return; /* Timer already started */
     754             : 
     755           0 :         u->last_session_timestamp = now(CLOCK_MONOTONIC);
     756             : 
     757           0 :         assert(!u->timer_event_source);
     758             : 
     759           0 :         if (IN_SET(u->manager->user_stop_delay, 0, USEC_INFINITY))
     760           0 :                 return;
     761             : 
     762           0 :         if (sd_event_get_state(u->manager->event) == SD_EVENT_FINISHED) {
     763           0 :                 log_debug("Not allocating user stop timeout, since we are already exiting.");
     764           0 :                 return;
     765             :         }
     766             : 
     767           0 :         r = sd_event_add_time(u->manager->event,
     768             :                               &u->timer_event_source,
     769             :                               CLOCK_MONOTONIC,
     770           0 :                               usec_add(u->last_session_timestamp, u->manager->user_stop_delay), 0,
     771             :                               user_stop_timeout_callback, u);
     772           0 :         if (r < 0)
     773           0 :                 log_warning_errno(r, "Failed to enqueue user stop event source, ignoring: %m");
     774             : 
     775           0 :         if (DEBUG_LOGGING) {
     776             :                 char s[FORMAT_TIMESPAN_MAX];
     777             : 
     778           0 :                 log_debug("Last session of user '%s' logged out, terminating user context in %s.",
     779             :                           u->name,
     780             :                           format_timespan(s, sizeof(s), u->manager->user_stop_delay, USEC_PER_MSEC));
     781             :         }
     782             : }
     783             : 
     784             : static const char* const user_state_table[_USER_STATE_MAX] = {
     785             :         [USER_OFFLINE] = "offline",
     786             :         [USER_OPENING] = "opening",
     787             :         [USER_LINGERING] = "lingering",
     788             :         [USER_ONLINE] = "online",
     789             :         [USER_ACTIVE] = "active",
     790             :         [USER_CLOSING] = "closing"
     791             : };
     792             : 
     793          16 : DEFINE_STRING_TABLE_LOOKUP(user_state, UserState);
     794             : 
     795           0 : int config_parse_tmpfs_size(
     796             :                 const char* unit,
     797             :                 const char *filename,
     798             :                 unsigned line,
     799             :                 const char *section,
     800             :                 unsigned section_line,
     801             :                 const char *lvalue,
     802             :                 int ltype,
     803             :                 const char *rvalue,
     804             :                 void *data,
     805             :                 void *userdata) {
     806             : 
     807           0 :         uint64_t *sz = data;
     808             :         int r;
     809             : 
     810           0 :         assert(filename);
     811           0 :         assert(lvalue);
     812           0 :         assert(rvalue);
     813           0 :         assert(data);
     814             : 
     815             :         /* First, try to parse as percentage */
     816           0 :         r = parse_permille(rvalue);
     817           0 :         if (r > 0 && r < 1000)
     818           0 :                 *sz = physical_memory_scale(r, 1000U);
     819             :         else {
     820             :                 uint64_t k;
     821             : 
     822             :                 /* If the passed argument was not a percentage, or out of range, parse as byte size */
     823             : 
     824           0 :                 r = parse_size(rvalue, 1024, &k);
     825           0 :                 if (r >= 0 && (k <= 0 || (uint64_t) (size_t) k != k))
     826           0 :                         r = -ERANGE;
     827           0 :                 if (r < 0) {
     828           0 :                         log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value '%s', ignoring: %m", rvalue);
     829           0 :                         return 0;
     830             :                 }
     831             : 
     832           0 :                 *sz = PAGE_ALIGN((size_t) k);
     833             :         }
     834             : 
     835           0 :         return 0;
     836             : }
     837             : 
     838           0 : int config_parse_compat_user_tasks_max(
     839             :                 const char *unit,
     840             :                 const char *filename,
     841             :                 unsigned line,
     842             :                 const char *section,
     843             :                 unsigned section_line,
     844             :                 const char *lvalue,
     845             :                 int ltype,
     846             :                 const char *rvalue,
     847             :                 void *data,
     848             :                 void *userdata) {
     849             : 
     850           0 :         assert(filename);
     851           0 :         assert(lvalue);
     852           0 :         assert(rvalue);
     853           0 :         assert(data);
     854             : 
     855           0 :         log_syntax(unit, LOG_NOTICE, filename, line, 0,
     856             :                    "Support for option %s= has been removed.",
     857             :                    lvalue);
     858           0 :         log_info("Hint: try creating /etc/systemd/system/user-.slice.d/50-limits.conf with:\n"
     859             :                  "        [Slice]\n"
     860             :                  "        TasksMax=%s",
     861             :                  rvalue);
     862           0 :         return 0;
     863             : }

Generated by: LCOV version 1.14