LCOV - code coverage report
Current view: top level - login - logind-session.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 4 719 0.6 %
Date: 2019-08-22 15:41:25 Functions: 8 49 16.3 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : 
       3             : #include <errno.h>
       4             : #include <fcntl.h>
       5             : #include <linux/kd.h>
       6             : #include <linux/vt.h>
       7             : #include <signal.h>
       8             : #include <string.h>
       9             : #include <sys/ioctl.h>
      10             : #include <sys/stat.h>
      11             : #include <unistd.h>
      12             : 
      13             : #include "sd-messages.h"
      14             : 
      15             : #include "alloc-util.h"
      16             : #include "audit-util.h"
      17             : #include "bus-error.h"
      18             : #include "bus-util.h"
      19             : #include "env-file.h"
      20             : #include "escape.h"
      21             : #include "fd-util.h"
      22             : #include "fileio.h"
      23             : #include "format-util.h"
      24             : #include "io-util.h"
      25             : #include "logind-dbus.h"
      26             : #include "logind-seat-dbus.h"
      27             : #include "logind-session-dbus.h"
      28             : #include "logind-session.h"
      29             : #include "logind-user-dbus.h"
      30             : #include "mkdir.h"
      31             : #include "parse-util.h"
      32             : #include "path-util.h"
      33             : #include "process-util.h"
      34             : #include "serialize.h"
      35             : #include "string-table.h"
      36             : #include "strv.h"
      37             : #include "terminal-util.h"
      38             : #include "tmpfile-util.h"
      39             : #include "user-util.h"
      40             : #include "util.h"
      41             : 
      42             : #define RELEASE_USEC (20*USEC_PER_SEC)
      43             : 
      44             : static void session_remove_fifo(Session *s);
      45             : static void session_restore_vt(Session *s);
      46             : 
      47           0 : int session_new(Session **ret, Manager *m, const char *id) {
      48           0 :         _cleanup_(session_freep) Session *s = NULL;
      49             :         int r;
      50             : 
      51           0 :         assert(ret);
      52           0 :         assert(m);
      53           0 :         assert(id);
      54             : 
      55           0 :         if (!session_id_valid(id))
      56           0 :                 return -EINVAL;
      57             : 
      58           0 :         s = new(Session, 1);
      59           0 :         if (!s)
      60           0 :                 return -ENOMEM;
      61             : 
      62           0 :         *s = (Session) {
      63             :                 .manager = m,
      64             :                 .fifo_fd = -1,
      65             :                 .vtfd = -1,
      66             :                 .audit_id = AUDIT_SESSION_INVALID,
      67             :                 .tty_validity = _TTY_VALIDITY_INVALID,
      68             :         };
      69             : 
      70           0 :         s->state_file = path_join("/run/systemd/sessions", id);
      71           0 :         if (!s->state_file)
      72           0 :                 return -ENOMEM;
      73             : 
      74           0 :         s->id = basename(s->state_file);
      75             : 
      76           0 :         s->devices = hashmap_new(&devt_hash_ops);
      77           0 :         if (!s->devices)
      78           0 :                 return -ENOMEM;
      79             : 
      80           0 :         r = hashmap_put(m->sessions, s->id, s);
      81           0 :         if (r < 0)
      82           0 :                 return r;
      83             : 
      84           0 :         *ret = TAKE_PTR(s);
      85           0 :         return 0;
      86             : }
      87             : 
      88           0 : Session* session_free(Session *s) {
      89             :         SessionDevice *sd;
      90             : 
      91           0 :         if (!s)
      92           0 :                 return NULL;
      93             : 
      94           0 :         if (s->in_gc_queue)
      95           0 :                 LIST_REMOVE(gc_queue, s->manager->session_gc_queue, s);
      96             : 
      97           0 :         s->timer_event_source = sd_event_source_unref(s->timer_event_source);
      98             : 
      99           0 :         session_drop_controller(s);
     100             : 
     101           0 :         while ((sd = hashmap_first(s->devices)))
     102           0 :                 session_device_free(sd);
     103             : 
     104           0 :         hashmap_free(s->devices);
     105             : 
     106           0 :         if (s->user) {
     107           0 :                 LIST_REMOVE(sessions_by_user, s->user->sessions, s);
     108             : 
     109           0 :                 if (s->user->display == s)
     110           0 :                         s->user->display = NULL;
     111             : 
     112           0 :                 user_update_last_session_timer(s->user);
     113             :         }
     114             : 
     115           0 :         if (s->seat) {
     116           0 :                 if (s->seat->active == s)
     117           0 :                         s->seat->active = NULL;
     118           0 :                 if (s->seat->pending_switch == s)
     119           0 :                         s->seat->pending_switch = NULL;
     120             : 
     121           0 :                 seat_evict_position(s->seat, s);
     122           0 :                 LIST_REMOVE(sessions_by_seat, s->seat->sessions, s);
     123             :         }
     124             : 
     125           0 :         if (s->scope) {
     126           0 :                 hashmap_remove(s->manager->session_units, s->scope);
     127           0 :                 free(s->scope);
     128             :         }
     129             : 
     130           0 :         if (pid_is_valid(s->leader))
     131           0 :                 (void) hashmap_remove_value(s->manager->sessions_by_leader, PID_TO_PTR(s->leader), s);
     132             : 
     133           0 :         free(s->scope_job);
     134             : 
     135           0 :         sd_bus_message_unref(s->create_message);
     136             : 
     137           0 :         free(s->tty);
     138           0 :         free(s->display);
     139           0 :         free(s->remote_host);
     140           0 :         free(s->remote_user);
     141           0 :         free(s->service);
     142           0 :         free(s->desktop);
     143             : 
     144           0 :         hashmap_remove(s->manager->sessions, s->id);
     145             : 
     146           0 :         sd_event_source_unref(s->fifo_event_source);
     147           0 :         safe_close(s->fifo_fd);
     148             : 
     149             :         /* Note that we remove neither the state file nor the fifo path here, since we want both to survive
     150             :          * daemon restarts */
     151           0 :         free(s->state_file);
     152           0 :         free(s->fifo_path);
     153             : 
     154           0 :         return mfree(s);
     155             : }
     156             : 
     157           0 : void session_set_user(Session *s, User *u) {
     158           0 :         assert(s);
     159           0 :         assert(!s->user);
     160             : 
     161           0 :         s->user = u;
     162           0 :         LIST_PREPEND(sessions_by_user, u->sessions, s);
     163             : 
     164           0 :         user_update_last_session_timer(u);
     165           0 : }
     166             : 
     167           0 : int session_set_leader(Session *s, pid_t pid) {
     168             :         int r;
     169             : 
     170           0 :         assert(s);
     171             : 
     172           0 :         if (!pid_is_valid(pid))
     173           0 :                 return -EINVAL;
     174             : 
     175           0 :         if (s->leader == pid)
     176           0 :                 return 0;
     177             : 
     178           0 :         r = hashmap_put(s->manager->sessions_by_leader, PID_TO_PTR(pid), s);
     179           0 :         if (r < 0)
     180           0 :                 return r;
     181             : 
     182           0 :         if (pid_is_valid(s->leader))
     183           0 :                 (void) hashmap_remove_value(s->manager->sessions_by_leader, PID_TO_PTR(s->leader), s);
     184             : 
     185           0 :         s->leader = pid;
     186           0 :         (void) audit_session_from_pid(pid, &s->audit_id);
     187             : 
     188           0 :         return 1;
     189             : }
     190             : 
     191           0 : static void session_save_devices(Session *s, FILE *f) {
     192             :         SessionDevice *sd;
     193             :         Iterator i;
     194             : 
     195           0 :         if (!hashmap_isempty(s->devices)) {
     196           0 :                 fprintf(f, "DEVICES=");
     197           0 :                 HASHMAP_FOREACH(sd, s->devices, i)
     198           0 :                         fprintf(f, "%u:%u ", major(sd->dev), minor(sd->dev));
     199           0 :                 fprintf(f, "\n");
     200             :         }
     201           0 : }
     202             : 
     203           0 : int session_save(Session *s) {
     204           0 :         _cleanup_free_ char *temp_path = NULL;
     205           0 :         _cleanup_fclose_ FILE *f = NULL;
     206           0 :         int r = 0;
     207             : 
     208           0 :         assert(s);
     209             : 
     210           0 :         if (!s->user)
     211           0 :                 return -ESTALE;
     212             : 
     213           0 :         if (!s->started)
     214           0 :                 return 0;
     215             : 
     216           0 :         r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0, MKDIR_WARN_MODE);
     217           0 :         if (r < 0)
     218           0 :                 goto fail;
     219             : 
     220           0 :         r = fopen_temporary(s->state_file, &f, &temp_path);
     221           0 :         if (r < 0)
     222           0 :                 goto fail;
     223             : 
     224           0 :         (void) fchmod(fileno(f), 0644);
     225             : 
     226           0 :         fprintf(f,
     227             :                 "# This is private data. Do not parse.\n"
     228             :                 "UID="UID_FMT"\n"
     229             :                 "USER=%s\n"
     230             :                 "ACTIVE=%i\n"
     231             :                 "IS_DISPLAY=%i\n"
     232             :                 "STATE=%s\n"
     233             :                 "REMOTE=%i\n",
     234           0 :                 s->user->uid,
     235           0 :                 s->user->name,
     236           0 :                 session_is_active(s),
     237           0 :                 s->user->display == s,
     238             :                 session_state_to_string(session_get_state(s)),
     239           0 :                 s->remote);
     240             : 
     241           0 :         if (s->type >= 0)
     242           0 :                 fprintf(f, "TYPE=%s\n", session_type_to_string(s->type));
     243             : 
     244           0 :         if (s->class >= 0)
     245           0 :                 fprintf(f, "CLASS=%s\n", session_class_to_string(s->class));
     246             : 
     247           0 :         if (s->scope)
     248           0 :                 fprintf(f, "SCOPE=%s\n", s->scope);
     249           0 :         if (s->scope_job)
     250           0 :                 fprintf(f, "SCOPE_JOB=%s\n", s->scope_job);
     251             : 
     252           0 :         if (s->fifo_path)
     253           0 :                 fprintf(f, "FIFO=%s\n", s->fifo_path);
     254             : 
     255           0 :         if (s->seat)
     256           0 :                 fprintf(f, "SEAT=%s\n", s->seat->id);
     257             : 
     258           0 :         if (s->tty)
     259           0 :                 fprintf(f, "TTY=%s\n", s->tty);
     260             : 
     261           0 :         if (s->tty_validity >= 0)
     262           0 :                 fprintf(f, "TTY_VALIDITY=%s\n", tty_validity_to_string(s->tty_validity));
     263             : 
     264           0 :         if (s->display)
     265           0 :                 fprintf(f, "DISPLAY=%s\n", s->display);
     266             : 
     267           0 :         if (s->remote_host) {
     268           0 :                 _cleanup_free_ char *escaped;
     269             : 
     270           0 :                 escaped = cescape(s->remote_host);
     271           0 :                 if (!escaped) {
     272           0 :                         r = -ENOMEM;
     273           0 :                         goto fail;
     274             :                 }
     275             : 
     276           0 :                 fprintf(f, "REMOTE_HOST=%s\n", escaped);
     277             :         }
     278             : 
     279           0 :         if (s->remote_user) {
     280           0 :                 _cleanup_free_ char *escaped;
     281             : 
     282           0 :                 escaped = cescape(s->remote_user);
     283           0 :                 if (!escaped) {
     284           0 :                         r = -ENOMEM;
     285           0 :                         goto fail;
     286             :                 }
     287             : 
     288           0 :                 fprintf(f, "REMOTE_USER=%s\n", escaped);
     289             :         }
     290             : 
     291           0 :         if (s->service) {
     292           0 :                 _cleanup_free_ char *escaped;
     293             : 
     294           0 :                 escaped = cescape(s->service);
     295           0 :                 if (!escaped) {
     296           0 :                         r = -ENOMEM;
     297           0 :                         goto fail;
     298             :                 }
     299             : 
     300           0 :                 fprintf(f, "SERVICE=%s\n", escaped);
     301             :         }
     302             : 
     303           0 :         if (s->desktop) {
     304           0 :                 _cleanup_free_ char *escaped;
     305             : 
     306           0 :                 escaped = cescape(s->desktop);
     307           0 :                 if (!escaped) {
     308           0 :                         r = -ENOMEM;
     309           0 :                         goto fail;
     310             :                 }
     311             : 
     312           0 :                 fprintf(f, "DESKTOP=%s\n", escaped);
     313             :         }
     314             : 
     315           0 :         if (s->seat && seat_has_vts(s->seat))
     316           0 :                 fprintf(f, "VTNR=%u\n", s->vtnr);
     317             : 
     318           0 :         if (!s->vtnr)
     319           0 :                 fprintf(f, "POSITION=%u\n", s->position);
     320             : 
     321           0 :         if (pid_is_valid(s->leader))
     322           0 :                 fprintf(f, "LEADER="PID_FMT"\n", s->leader);
     323             : 
     324           0 :         if (audit_session_is_valid(s->audit_id))
     325           0 :                 fprintf(f, "AUDIT=%"PRIu32"\n", s->audit_id);
     326             : 
     327           0 :         if (dual_timestamp_is_set(&s->timestamp))
     328           0 :                 fprintf(f,
     329             :                         "REALTIME="USEC_FMT"\n"
     330             :                         "MONOTONIC="USEC_FMT"\n",
     331             :                         s->timestamp.realtime,
     332             :                         s->timestamp.monotonic);
     333             : 
     334           0 :         if (s->controller) {
     335           0 :                 fprintf(f, "CONTROLLER=%s\n", s->controller);
     336           0 :                 session_save_devices(s, f);
     337             :         }
     338             : 
     339           0 :         r = fflush_and_check(f);
     340           0 :         if (r < 0)
     341           0 :                 goto fail;
     342             : 
     343           0 :         if (rename(temp_path, s->state_file) < 0) {
     344           0 :                 r = -errno;
     345           0 :                 goto fail;
     346             :         }
     347             : 
     348           0 :         return 0;
     349             : 
     350           0 : fail:
     351           0 :         (void) unlink(s->state_file);
     352             : 
     353           0 :         if (temp_path)
     354           0 :                 (void) unlink(temp_path);
     355             : 
     356           0 :         return log_error_errno(r, "Failed to save session data %s: %m", s->state_file);
     357             : }
     358             : 
     359           0 : static int session_load_devices(Session *s, const char *devices) {
     360             :         const char *p;
     361           0 :         int r = 0;
     362             : 
     363           0 :         assert(s);
     364             : 
     365           0 :         for (p = devices;;) {
     366           0 :                 _cleanup_free_ char *word = NULL;
     367             :                 SessionDevice *sd;
     368             :                 dev_t dev;
     369             :                 int k;
     370             : 
     371           0 :                 k = extract_first_word(&p, &word, NULL, 0);
     372           0 :                 if (k == 0)
     373           0 :                         break;
     374           0 :                 if (k < 0) {
     375           0 :                         r = k;
     376           0 :                         break;
     377             :                 }
     378             : 
     379           0 :                 k = parse_dev(word, &dev);
     380           0 :                 if (k < 0) {
     381           0 :                         r = k;
     382           0 :                         continue;
     383             :                 }
     384             : 
     385             :                 /* The file descriptors for loaded devices will be reattached later. */
     386           0 :                 k = session_device_new(s, dev, false, &sd);
     387           0 :                 if (k < 0)
     388           0 :                         r = k;
     389             :         }
     390             : 
     391           0 :         if (r < 0)
     392           0 :                 log_error_errno(r, "Loading session devices for session %s failed: %m", s->id);
     393             : 
     394           0 :         return r;
     395             : }
     396             : 
     397           0 : int session_load(Session *s) {
     398           0 :         _cleanup_free_ char *remote = NULL,
     399           0 :                 *seat = NULL,
     400           0 :                 *tty_validity = NULL,
     401           0 :                 *vtnr = NULL,
     402           0 :                 *state = NULL,
     403           0 :                 *position = NULL,
     404           0 :                 *leader = NULL,
     405           0 :                 *type = NULL,
     406           0 :                 *class = NULL,
     407           0 :                 *uid = NULL,
     408           0 :                 *realtime = NULL,
     409           0 :                 *monotonic = NULL,
     410           0 :                 *controller = NULL,
     411           0 :                 *active = NULL,
     412           0 :                 *devices = NULL,
     413           0 :                 *is_display = NULL;
     414             : 
     415             :         int k, r;
     416             : 
     417           0 :         assert(s);
     418             : 
     419           0 :         r = parse_env_file(NULL, s->state_file,
     420             :                            "REMOTE",         &remote,
     421             :                            "SCOPE",          &s->scope,
     422             :                            "SCOPE_JOB",      &s->scope_job,
     423             :                            "FIFO",           &s->fifo_path,
     424             :                            "SEAT",           &seat,
     425             :                            "TTY",            &s->tty,
     426             :                            "TTY_VALIDITY",   &tty_validity,
     427             :                            "DISPLAY",        &s->display,
     428             :                            "REMOTE_HOST",    &s->remote_host,
     429             :                            "REMOTE_USER",    &s->remote_user,
     430             :                            "SERVICE",        &s->service,
     431             :                            "DESKTOP",        &s->desktop,
     432             :                            "VTNR",           &vtnr,
     433             :                            "STATE",          &state,
     434             :                            "POSITION",       &position,
     435             :                            "LEADER",         &leader,
     436             :                            "TYPE",           &type,
     437             :                            "CLASS",          &class,
     438             :                            "UID",            &uid,
     439             :                            "REALTIME",       &realtime,
     440             :                            "MONOTONIC",      &monotonic,
     441             :                            "CONTROLLER",     &controller,
     442             :                            "ACTIVE",         &active,
     443             :                            "DEVICES",        &devices,
     444             :                            "IS_DISPLAY",     &is_display);
     445             : 
     446           0 :         if (r < 0)
     447           0 :                 return log_error_errno(r, "Failed to read %s: %m", s->state_file);
     448             : 
     449           0 :         if (!s->user) {
     450             :                 uid_t u;
     451             :                 User *user;
     452             : 
     453           0 :                 if (!uid)
     454           0 :                         return log_error_errno(SYNTHETIC_ERRNO(ENOENT),
     455             :                                                "UID not specified for session %s",
     456             :                                                s->id);
     457             : 
     458           0 :                 r = parse_uid(uid, &u);
     459           0 :                 if (r < 0)  {
     460           0 :                         log_error("Failed to parse UID value %s for session %s.", uid, s->id);
     461           0 :                         return r;
     462             :                 }
     463             : 
     464           0 :                 user = hashmap_get(s->manager->users, UID_TO_PTR(u));
     465           0 :                 if (!user)
     466           0 :                         return log_error_errno(SYNTHETIC_ERRNO(ENOENT),
     467             :                                                "User of session %s not known.",
     468             :                                                s->id);
     469             : 
     470           0 :                 session_set_user(s, user);
     471             :         }
     472             : 
     473           0 :         if (remote) {
     474           0 :                 k = parse_boolean(remote);
     475           0 :                 if (k >= 0)
     476           0 :                         s->remote = k;
     477             :         }
     478             : 
     479           0 :         if (vtnr)
     480           0 :                 safe_atou(vtnr, &s->vtnr);
     481             : 
     482           0 :         if (seat && !s->seat) {
     483             :                 Seat *o;
     484             : 
     485           0 :                 o = hashmap_get(s->manager->seats, seat);
     486           0 :                 if (o)
     487           0 :                         r = seat_attach_session(o, s);
     488           0 :                 if (!o || r < 0)
     489           0 :                         log_error("Cannot attach session %s to seat %s", s->id, seat);
     490             :         }
     491             : 
     492           0 :         if (!s->seat || !seat_has_vts(s->seat))
     493           0 :                 s->vtnr = 0;
     494             : 
     495           0 :         if (position && s->seat) {
     496             :                 unsigned npos;
     497             : 
     498           0 :                 safe_atou(position, &npos);
     499           0 :                 seat_claim_position(s->seat, s, npos);
     500             :         }
     501             : 
     502           0 :         if (tty_validity) {
     503             :                 TTYValidity v;
     504             : 
     505           0 :                 v = tty_validity_from_string(tty_validity);
     506           0 :                 if (v < 0)
     507           0 :                         log_debug("Failed to parse TTY validity: %s", tty_validity);
     508             :                 else
     509           0 :                         s->tty_validity = v;
     510             :         }
     511             : 
     512           0 :         if (leader) {
     513             :                 pid_t pid;
     514             : 
     515           0 :                 r = parse_pid(leader, &pid);
     516           0 :                 if (r < 0)
     517           0 :                         log_debug_errno(r, "Failed to parse leader PID of session: %s", leader);
     518             :                 else {
     519           0 :                         r = session_set_leader(s, pid);
     520           0 :                         if (r < 0)
     521           0 :                                 log_warning_errno(r, "Failed to set session leader PID, ignoring: %m");
     522             :                 }
     523             :         }
     524             : 
     525           0 :         if (type) {
     526             :                 SessionType t;
     527             : 
     528           0 :                 t = session_type_from_string(type);
     529           0 :                 if (t >= 0)
     530           0 :                         s->type = t;
     531             :         }
     532             : 
     533           0 :         if (class) {
     534             :                 SessionClass c;
     535             : 
     536           0 :                 c = session_class_from_string(class);
     537           0 :                 if (c >= 0)
     538           0 :                         s->class = c;
     539             :         }
     540             : 
     541           0 :         if (state && streq(state, "closing"))
     542           0 :                 s->stopping = true;
     543             : 
     544           0 :         if (s->fifo_path) {
     545             :                 int fd;
     546             : 
     547             :                 /* If we open an unopened pipe for reading we will not
     548             :                    get an EOF. to trigger an EOF we hence open it for
     549             :                    writing, but close it right away which then will
     550             :                    trigger the EOF. This will happen immediately if no
     551             :                    other process has the FIFO open for writing, i. e.
     552             :                    when the session died before logind (re)started. */
     553             : 
     554           0 :                 fd = session_create_fifo(s);
     555           0 :                 safe_close(fd);
     556             :         }
     557             : 
     558           0 :         if (realtime)
     559           0 :                 (void) deserialize_usec(realtime, &s->timestamp.realtime);
     560           0 :         if (monotonic)
     561           0 :                 (void) deserialize_usec(monotonic, &s->timestamp.monotonic);
     562             : 
     563           0 :         if (active) {
     564           0 :                 k = parse_boolean(active);
     565           0 :                 if (k >= 0)
     566           0 :                         s->was_active = k;
     567             :         }
     568             : 
     569           0 :         if (is_display) {
     570             :                 /* Note that when enumerating users are loaded before sessions, hence the display session to use is
     571             :                  * something we have to store along with the session and not the user, as in that case we couldn't
     572             :                  * apply it at the time we load the user. */
     573             : 
     574           0 :                 k = parse_boolean(is_display);
     575           0 :                 if (k < 0)
     576           0 :                         log_warning_errno(k, "Failed to parse IS_DISPLAY session property: %m");
     577           0 :                 else if (k > 0)
     578           0 :                         s->user->display = s;
     579             :         }
     580             : 
     581           0 :         if (controller) {
     582           0 :                 if (bus_name_has_owner(s->manager->bus, controller, NULL) > 0) {
     583           0 :                         session_set_controller(s, controller, false, false);
     584           0 :                         session_load_devices(s, devices);
     585             :                 } else
     586           0 :                         session_restore_vt(s);
     587             :         }
     588             : 
     589           0 :         return r;
     590             : }
     591             : 
     592           0 : int session_activate(Session *s) {
     593             :         unsigned num_pending;
     594             : 
     595           0 :         assert(s);
     596           0 :         assert(s->user);
     597             : 
     598           0 :         if (!s->seat)
     599           0 :                 return -EOPNOTSUPP;
     600             : 
     601           0 :         if (s->seat->active == s)
     602           0 :                 return 0;
     603             : 
     604             :         /* on seats with VTs, we let VTs manage session-switching */
     605           0 :         if (seat_has_vts(s->seat)) {
     606           0 :                 if (s->vtnr == 0)
     607           0 :                         return -EOPNOTSUPP;
     608             : 
     609           0 :                 return chvt(s->vtnr);
     610             :         }
     611             : 
     612             :         /* On seats without VTs, we implement session-switching in logind. We
     613             :          * try to pause all session-devices and wait until the session
     614             :          * controller acknowledged them. Once all devices are asleep, we simply
     615             :          * switch the active session and be done.
     616             :          * We save the session we want to switch to in seat->pending_switch and
     617             :          * seat_complete_switch() will perform the final switch. */
     618             : 
     619           0 :         s->seat->pending_switch = s;
     620             : 
     621             :         /* if no devices are running, immediately perform the session switch */
     622           0 :         num_pending = session_device_try_pause_all(s);
     623           0 :         if (!num_pending)
     624           0 :                 seat_complete_switch(s->seat);
     625             : 
     626           0 :         return 0;
     627             : }
     628             : 
     629           0 : static int session_start_scope(Session *s, sd_bus_message *properties, sd_bus_error *error) {
     630             :         int r;
     631             : 
     632           0 :         assert(s);
     633           0 :         assert(s->user);
     634             : 
     635           0 :         if (!s->scope) {
     636           0 :                 _cleanup_free_ char *scope = NULL;
     637             :                 const char *description;
     638             : 
     639           0 :                 s->scope_job = mfree(s->scope_job);
     640             : 
     641           0 :                 scope = strjoin("session-", s->id, ".scope");
     642           0 :                 if (!scope)
     643           0 :                         return log_oom();
     644             : 
     645           0 :                 description = strjoina("Session ", s->id, " of user ", s->user->name);
     646             : 
     647           0 :                 r = manager_start_scope(
     648             :                                 s->manager,
     649             :                                 scope,
     650             :                                 s->leader,
     651           0 :                                 s->user->slice,
     652             :                                 description,
     653             :                                 /* These two have StopWhenUnneeded= set, hence add a dep towards them */
     654           0 :                                 STRV_MAKE(s->user->runtime_dir_service,
     655             :                                           s->user->service),
     656             :                                 /* And order us after some more */
     657           0 :                                 STRV_MAKE("systemd-logind.service",
     658             :                                           "systemd-user-sessions.service",
     659             :                                           s->user->runtime_dir_service,
     660             :                                           s->user->service),
     661           0 :                                 s->user->home,
     662             :                                 properties,
     663             :                                 error,
     664             :                                 &s->scope_job);
     665           0 :                 if (r < 0)
     666           0 :                         return log_error_errno(r, "Failed to start session scope %s: %s",
     667             :                                                scope, bus_error_message(error, r));
     668             : 
     669           0 :                 s->scope = TAKE_PTR(scope);
     670             :         }
     671             : 
     672           0 :         (void) hashmap_put(s->manager->session_units, s->scope, s);
     673             : 
     674           0 :         return 0;
     675             : }
     676             : 
     677           0 : int session_start(Session *s, sd_bus_message *properties, sd_bus_error *error) {
     678             :         int r;
     679             : 
     680           0 :         assert(s);
     681             : 
     682           0 :         if (!s->user)
     683           0 :                 return -ESTALE;
     684             : 
     685           0 :         if (s->stopping)
     686           0 :                 return -EINVAL;
     687             : 
     688           0 :         if (s->started)
     689           0 :                 return 0;
     690             : 
     691           0 :         r = user_start(s->user);
     692           0 :         if (r < 0)
     693           0 :                 return r;
     694             : 
     695           0 :         r = session_start_scope(s, properties, error);
     696           0 :         if (r < 0)
     697           0 :                 return r;
     698             : 
     699           0 :         log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
     700             :                    "MESSAGE_ID=" SD_MESSAGE_SESSION_START_STR,
     701             :                    "SESSION_ID=%s", s->id,
     702             :                    "USER_ID=%s", s->user->name,
     703             :                    "LEADER="PID_FMT, s->leader,
     704             :                    LOG_MESSAGE("New session %s of user %s.", s->id, s->user->name));
     705             : 
     706           0 :         if (!dual_timestamp_is_set(&s->timestamp))
     707           0 :                 dual_timestamp_get(&s->timestamp);
     708             : 
     709           0 :         if (s->seat)
     710           0 :                 seat_read_active_vt(s->seat);
     711             : 
     712           0 :         s->started = true;
     713             : 
     714           0 :         user_elect_display(s->user);
     715             : 
     716             :         /* Save data */
     717           0 :         session_save(s);
     718           0 :         user_save(s->user);
     719           0 :         if (s->seat)
     720           0 :                 seat_save(s->seat);
     721             : 
     722             :         /* Send signals */
     723           0 :         session_send_signal(s, true);
     724           0 :         user_send_changed(s->user, "Display", NULL);
     725           0 :         if (s->seat) {
     726           0 :                 if (s->seat->active == s)
     727           0 :                         seat_send_changed(s->seat, "ActiveSession", NULL);
     728             :         }
     729             : 
     730           0 :         return 0;
     731             : }
     732             : 
     733           0 : static int session_stop_scope(Session *s, bool force) {
     734           0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     735             :         int r;
     736             : 
     737           0 :         assert(s);
     738             : 
     739           0 :         if (!s->scope)
     740           0 :                 return 0;
     741             : 
     742             :         /* Let's always abandon the scope first. This tells systemd that we are not interested anymore, and everything
     743             :          * that is left in the scope is "left-over". Informing systemd about this has the benefit that it will log
     744             :          * when killing any processes left after this point. */
     745           0 :         r = manager_abandon_scope(s->manager, s->scope, &error);
     746           0 :         if (r < 0) {
     747           0 :                 log_warning_errno(r, "Failed to abandon session scope, ignoring: %s", bus_error_message(&error, r));
     748           0 :                 sd_bus_error_free(&error);
     749             :         }
     750             : 
     751           0 :         s->scope_job = mfree(s->scope_job);
     752             : 
     753             :         /* Optionally, let's kill everything that's left now. */
     754           0 :         if (force || manager_shall_kill(s->manager, s->user->name)) {
     755             : 
     756           0 :                 r = manager_stop_unit(s->manager, s->scope, &error, &s->scope_job);
     757           0 :                 if (r < 0) {
     758           0 :                         if (force)
     759           0 :                                 return log_error_errno(r, "Failed to stop session scope: %s", bus_error_message(&error, r));
     760             : 
     761           0 :                         log_warning_errno(r, "Failed to stop session scope, ignoring: %s", bus_error_message(&error, r));
     762             :                 }
     763             :         } else {
     764             : 
     765             :                 /* With no killing, this session is allowed to persist in "closing" state indefinitely.
     766             :                  * Therefore session stop and session removal may be two distinct events.
     767             :                  * Session stop is quite significant on its own, let's log it. */
     768           0 :                 log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
     769             :                            "SESSION_ID=%s", s->id,
     770             :                            "USER_ID=%s", s->user->name,
     771             :                            "LEADER="PID_FMT, s->leader,
     772             :                            LOG_MESSAGE("Session %s logged out. Waiting for processes to exit.", s->id));
     773             :         }
     774             : 
     775           0 :         return 0;
     776             : }
     777             : 
     778           0 : int session_stop(Session *s, bool force) {
     779             :         int r;
     780             : 
     781           0 :         assert(s);
     782             : 
     783             :         /* This is called whenever we begin with tearing down a session record. It's called in four cases: explicit API
     784             :          * request via the bus (either directly for the session object or for the seat or user object this session
     785             :          * belongs to; 'force' is true), or due to automatic GC (i.e. scope vanished; 'force' is false), or because the
     786             :          * session FIFO saw an EOF ('force' is false), or because the release timer hit ('force' is false). */
     787             : 
     788           0 :         if (!s->user)
     789           0 :                 return -ESTALE;
     790           0 :         if (!s->started)
     791           0 :                 return 0;
     792           0 :         if (s->stopping)
     793           0 :                 return 0;
     794             : 
     795           0 :         s->timer_event_source = sd_event_source_unref(s->timer_event_source);
     796             : 
     797           0 :         if (s->seat)
     798           0 :                 seat_evict_position(s->seat, s);
     799             : 
     800             :         /* We are going down, don't care about FIFOs anymore */
     801           0 :         session_remove_fifo(s);
     802             : 
     803             :         /* Kill cgroup */
     804           0 :         r = session_stop_scope(s, force);
     805             : 
     806           0 :         s->stopping = true;
     807             : 
     808           0 :         user_elect_display(s->user);
     809             : 
     810           0 :         session_save(s);
     811           0 :         user_save(s->user);
     812             : 
     813           0 :         return r;
     814             : }
     815             : 
     816           0 : int session_finalize(Session *s) {
     817             :         SessionDevice *sd;
     818             : 
     819           0 :         assert(s);
     820             : 
     821           0 :         if (!s->user)
     822           0 :                 return -ESTALE;
     823             : 
     824           0 :         if (s->started)
     825           0 :                 log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
     826             :                            "MESSAGE_ID=" SD_MESSAGE_SESSION_STOP_STR,
     827             :                            "SESSION_ID=%s", s->id,
     828             :                            "USER_ID=%s", s->user->name,
     829             :                            "LEADER="PID_FMT, s->leader,
     830             :                            LOG_MESSAGE("Removed session %s.", s->id));
     831             : 
     832           0 :         s->timer_event_source = sd_event_source_unref(s->timer_event_source);
     833             : 
     834           0 :         if (s->seat)
     835           0 :                 seat_evict_position(s->seat, s);
     836             : 
     837             :         /* Kill session devices */
     838           0 :         while ((sd = hashmap_first(s->devices)))
     839           0 :                 session_device_free(sd);
     840             : 
     841           0 :         (void) unlink(s->state_file);
     842           0 :         session_add_to_gc_queue(s);
     843           0 :         user_add_to_gc_queue(s->user);
     844             : 
     845           0 :         if (s->started) {
     846           0 :                 session_send_signal(s, false);
     847           0 :                 s->started = false;
     848             :         }
     849             : 
     850           0 :         if (s->seat) {
     851           0 :                 if (s->seat->active == s)
     852           0 :                         seat_set_active(s->seat, NULL);
     853             : 
     854           0 :                 seat_save(s->seat);
     855             :         }
     856             : 
     857           0 :         user_save(s->user);
     858           0 :         user_send_changed(s->user, "Display", NULL);
     859             : 
     860           0 :         return 0;
     861             : }
     862             : 
     863           0 : static int release_timeout_callback(sd_event_source *es, uint64_t usec, void *userdata) {
     864           0 :         Session *s = userdata;
     865             : 
     866           0 :         assert(es);
     867           0 :         assert(s);
     868             : 
     869           0 :         session_stop(s, false);
     870           0 :         return 0;
     871             : }
     872             : 
     873           0 : int session_release(Session *s) {
     874           0 :         assert(s);
     875             : 
     876           0 :         if (!s->started || s->stopping)
     877           0 :                 return 0;
     878             : 
     879           0 :         if (s->timer_event_source)
     880           0 :                 return 0;
     881             : 
     882           0 :         return sd_event_add_time(s->manager->event,
     883             :                                  &s->timer_event_source,
     884             :                                  CLOCK_MONOTONIC,
     885             :                                  usec_add(now(CLOCK_MONOTONIC), RELEASE_USEC), 0,
     886             :                                  release_timeout_callback, s);
     887             : }
     888             : 
     889           0 : bool session_is_active(Session *s) {
     890           0 :         assert(s);
     891             : 
     892           0 :         if (!s->seat)
     893           0 :                 return true;
     894             : 
     895           0 :         return s->seat->active == s;
     896             : }
     897             : 
     898           0 : static int get_tty_atime(const char *tty, usec_t *atime) {
     899           0 :         _cleanup_free_ char *p = NULL;
     900             :         struct stat st;
     901             : 
     902           0 :         assert(tty);
     903           0 :         assert(atime);
     904             : 
     905           0 :         if (!path_is_absolute(tty)) {
     906           0 :                 p = path_join("/dev", tty);
     907           0 :                 if (!p)
     908           0 :                         return -ENOMEM;
     909             : 
     910           0 :                 tty = p;
     911           0 :         } else if (!path_startswith(tty, "/dev/"))
     912           0 :                 return -ENOENT;
     913             : 
     914           0 :         if (lstat(tty, &st) < 0)
     915           0 :                 return -errno;
     916             : 
     917           0 :         *atime = timespec_load(&st.st_atim);
     918           0 :         return 0;
     919             : }
     920             : 
     921           0 : static int get_process_ctty_atime(pid_t pid, usec_t *atime) {
     922           0 :         _cleanup_free_ char *p = NULL;
     923             :         int r;
     924             : 
     925           0 :         assert(pid > 0);
     926           0 :         assert(atime);
     927             : 
     928           0 :         r = get_ctty(pid, NULL, &p);
     929           0 :         if (r < 0)
     930           0 :                 return r;
     931             : 
     932           0 :         return get_tty_atime(p, atime);
     933             : }
     934             : 
     935           0 : int session_get_idle_hint(Session *s, dual_timestamp *t) {
     936           0 :         usec_t atime = 0, n;
     937             :         int r;
     938             : 
     939           0 :         assert(s);
     940             : 
     941             :         /* Explicit idle hint is set */
     942           0 :         if (s->idle_hint) {
     943           0 :                 if (t)
     944           0 :                         *t = s->idle_hint_timestamp;
     945             : 
     946           0 :                 return s->idle_hint;
     947             :         }
     948             : 
     949             :         /* Graphical sessions should really implement a real
     950             :          * idle hint logic */
     951           0 :         if (SESSION_TYPE_IS_GRAPHICAL(s->type))
     952           0 :                 goto dont_know;
     953             : 
     954             :         /* For sessions with an explicitly configured tty, let's check
     955             :          * its atime */
     956           0 :         if (s->tty) {
     957           0 :                 r = get_tty_atime(s->tty, &atime);
     958           0 :                 if (r >= 0)
     959           0 :                         goto found_atime;
     960             :         }
     961             : 
     962             :         /* For sessions with a leader but no explicitly configured
     963             :          * tty, let's check the controlling tty of the leader */
     964           0 :         if (pid_is_valid(s->leader)) {
     965           0 :                 r = get_process_ctty_atime(s->leader, &atime);
     966           0 :                 if (r >= 0)
     967           0 :                         goto found_atime;
     968             :         }
     969             : 
     970           0 : dont_know:
     971           0 :         if (t)
     972           0 :                 *t = s->idle_hint_timestamp;
     973             : 
     974           0 :         return 0;
     975             : 
     976           0 : found_atime:
     977           0 :         if (t)
     978           0 :                 dual_timestamp_from_realtime(t, atime);
     979             : 
     980           0 :         n = now(CLOCK_REALTIME);
     981             : 
     982           0 :         if (s->manager->idle_action_usec <= 0)
     983           0 :                 return 0;
     984             : 
     985           0 :         return atime + s->manager->idle_action_usec <= n;
     986             : }
     987             : 
     988           0 : void session_set_idle_hint(Session *s, bool b) {
     989           0 :         assert(s);
     990             : 
     991           0 :         if (s->idle_hint == b)
     992           0 :                 return;
     993             : 
     994           0 :         s->idle_hint = b;
     995           0 :         dual_timestamp_get(&s->idle_hint_timestamp);
     996             : 
     997           0 :         session_send_changed(s, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
     998             : 
     999           0 :         if (s->seat)
    1000           0 :                 seat_send_changed(s->seat, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
    1001             : 
    1002           0 :         user_send_changed(s->user, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
    1003           0 :         manager_send_changed(s->manager, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
    1004             : }
    1005             : 
    1006           0 : int session_get_locked_hint(Session *s) {
    1007           0 :         assert(s);
    1008             : 
    1009           0 :         return s->locked_hint;
    1010             : }
    1011             : 
    1012           0 : void session_set_locked_hint(Session *s, bool b) {
    1013           0 :         assert(s);
    1014             : 
    1015           0 :         if (s->locked_hint == b)
    1016           0 :                 return;
    1017             : 
    1018           0 :         s->locked_hint = b;
    1019             : 
    1020           0 :         session_send_changed(s, "LockedHint", NULL);
    1021             : }
    1022             : 
    1023           0 : static int session_dispatch_fifo(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
    1024           0 :         Session *s = userdata;
    1025             : 
    1026           0 :         assert(s);
    1027           0 :         assert(s->fifo_fd == fd);
    1028             : 
    1029             :         /* EOF on the FIFO means the session died abnormally. */
    1030             : 
    1031           0 :         session_remove_fifo(s);
    1032           0 :         session_stop(s, false);
    1033             : 
    1034           0 :         return 1;
    1035             : }
    1036             : 
    1037           0 : int session_create_fifo(Session *s) {
    1038             :         int r;
    1039             : 
    1040           0 :         assert(s);
    1041             : 
    1042             :         /* Create FIFO */
    1043           0 :         if (!s->fifo_path) {
    1044           0 :                 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0, MKDIR_WARN_MODE);
    1045           0 :                 if (r < 0)
    1046           0 :                         return r;
    1047             : 
    1048           0 :                 s->fifo_path = strjoin("/run/systemd/sessions/", s->id, ".ref");
    1049           0 :                 if (!s->fifo_path)
    1050           0 :                         return -ENOMEM;
    1051             : 
    1052           0 :                 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
    1053           0 :                         return -errno;
    1054             :         }
    1055             : 
    1056             :         /* Open reading side */
    1057           0 :         if (s->fifo_fd < 0) {
    1058           0 :                 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
    1059           0 :                 if (s->fifo_fd < 0)
    1060           0 :                         return -errno;
    1061             :         }
    1062             : 
    1063           0 :         if (!s->fifo_event_source) {
    1064           0 :                 r = sd_event_add_io(s->manager->event, &s->fifo_event_source, s->fifo_fd, 0, session_dispatch_fifo, s);
    1065           0 :                 if (r < 0)
    1066           0 :                         return r;
    1067             : 
    1068             :                 /* Let's make sure we noticed dead sessions before we process new bus requests (which might create new
    1069             :                  * sessions). */
    1070           0 :                 r = sd_event_source_set_priority(s->fifo_event_source, SD_EVENT_PRIORITY_NORMAL-10);
    1071           0 :                 if (r < 0)
    1072           0 :                         return r;
    1073             :         }
    1074             : 
    1075             :         /* Open writing side */
    1076           0 :         r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NONBLOCK);
    1077           0 :         if (r < 0)
    1078           0 :                 return -errno;
    1079             : 
    1080           0 :         return r;
    1081             : }
    1082             : 
    1083           0 : static void session_remove_fifo(Session *s) {
    1084           0 :         assert(s);
    1085             : 
    1086           0 :         s->fifo_event_source = sd_event_source_unref(s->fifo_event_source);
    1087           0 :         s->fifo_fd = safe_close(s->fifo_fd);
    1088             : 
    1089           0 :         if (s->fifo_path) {
    1090           0 :                 (void) unlink(s->fifo_path);
    1091           0 :                 s->fifo_path = mfree(s->fifo_path);
    1092             :         }
    1093           0 : }
    1094             : 
    1095           0 : bool session_may_gc(Session *s, bool drop_not_started) {
    1096             :         int r;
    1097             : 
    1098           0 :         assert(s);
    1099             : 
    1100           0 :         if (drop_not_started && !s->started)
    1101           0 :                 return true;
    1102             : 
    1103           0 :         if (!s->user)
    1104           0 :                 return true;
    1105             : 
    1106           0 :         if (s->fifo_fd >= 0) {
    1107           0 :                 if (pipe_eof(s->fifo_fd) <= 0)
    1108           0 :                         return false;
    1109             :         }
    1110             : 
    1111           0 :         if (s->scope_job) {
    1112           0 :                 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
    1113             : 
    1114           0 :                 r = manager_job_is_active(s->manager, s->scope_job, &error);
    1115           0 :                 if (r < 0)
    1116           0 :                         log_debug_errno(r, "Failed to determine whether job '%s' is pending, ignoring: %s", s->scope_job, bus_error_message(&error, r));
    1117           0 :                 if (r != 0)
    1118           0 :                         return false;
    1119             :         }
    1120             : 
    1121           0 :         if (s->scope) {
    1122           0 :                 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
    1123             : 
    1124           0 :                 r = manager_unit_is_active(s->manager, s->scope, &error);
    1125           0 :                 if (r < 0)
    1126           0 :                         log_debug_errno(r, "Failed to determine whether unit '%s' is active, ignoring: %s", s->scope, bus_error_message(&error, r));
    1127           0 :                 if (r != 0)
    1128           0 :                         return false;
    1129             :         }
    1130             : 
    1131           0 :         return true;
    1132             : }
    1133             : 
    1134           0 : void session_add_to_gc_queue(Session *s) {
    1135           0 :         assert(s);
    1136             : 
    1137           0 :         if (s->in_gc_queue)
    1138           0 :                 return;
    1139             : 
    1140           0 :         LIST_PREPEND(gc_queue, s->manager->session_gc_queue, s);
    1141           0 :         s->in_gc_queue = true;
    1142             : }
    1143             : 
    1144           0 : SessionState session_get_state(Session *s) {
    1145           0 :         assert(s);
    1146             : 
    1147             :         /* always check closing first */
    1148           0 :         if (s->stopping || s->timer_event_source)
    1149           0 :                 return SESSION_CLOSING;
    1150             : 
    1151           0 :         if (s->scope_job || s->fifo_fd < 0)
    1152           0 :                 return SESSION_OPENING;
    1153             : 
    1154           0 :         if (session_is_active(s))
    1155           0 :                 return SESSION_ACTIVE;
    1156             : 
    1157           0 :         return SESSION_ONLINE;
    1158             : }
    1159             : 
    1160           0 : int session_kill(Session *s, KillWho who, int signo) {
    1161           0 :         assert(s);
    1162             : 
    1163           0 :         if (!s->scope)
    1164           0 :                 return -ESRCH;
    1165             : 
    1166           0 :         return manager_kill_unit(s->manager, s->scope, who, signo, NULL);
    1167             : }
    1168             : 
    1169           0 : static int session_open_vt(Session *s) {
    1170             :         char path[sizeof("/dev/tty") + DECIMAL_STR_MAX(s->vtnr)];
    1171             : 
    1172           0 :         if (s->vtnr < 1)
    1173           0 :                 return -ENODEV;
    1174             : 
    1175           0 :         if (s->vtfd >= 0)
    1176           0 :                 return s->vtfd;
    1177             : 
    1178           0 :         sprintf(path, "/dev/tty%u", s->vtnr);
    1179           0 :         s->vtfd = open_terminal(path, O_RDWR | O_CLOEXEC | O_NONBLOCK | O_NOCTTY);
    1180           0 :         if (s->vtfd < 0)
    1181           0 :                 return log_error_errno(s->vtfd, "cannot open VT %s of session %s: %m", path, s->id);
    1182             : 
    1183           0 :         return s->vtfd;
    1184             : }
    1185             : 
    1186           0 : int session_prepare_vt(Session *s) {
    1187             :         int vt, r;
    1188           0 :         struct vt_mode mode = {};
    1189             : 
    1190           0 :         if (s->vtnr < 1)
    1191           0 :                 return 0;
    1192             : 
    1193           0 :         vt = session_open_vt(s);
    1194           0 :         if (vt < 0)
    1195           0 :                 return vt;
    1196             : 
    1197           0 :         r = fchown(vt, s->user->uid, -1);
    1198           0 :         if (r < 0) {
    1199           0 :                 r = log_error_errno(errno,
    1200             :                                     "Cannot change owner of /dev/tty%u: %m",
    1201             :                                     s->vtnr);
    1202           0 :                 goto error;
    1203             :         }
    1204             : 
    1205           0 :         r = ioctl(vt, KDSKBMODE, K_OFF);
    1206           0 :         if (r < 0) {
    1207           0 :                 r = log_error_errno(errno,
    1208             :                                     "Cannot set K_OFF on /dev/tty%u: %m",
    1209             :                                     s->vtnr);
    1210           0 :                 goto error;
    1211             :         }
    1212             : 
    1213           0 :         r = ioctl(vt, KDSETMODE, KD_GRAPHICS);
    1214           0 :         if (r < 0) {
    1215           0 :                 r = log_error_errno(errno,
    1216             :                                     "Cannot set KD_GRAPHICS on /dev/tty%u: %m",
    1217             :                                     s->vtnr);
    1218           0 :                 goto error;
    1219             :         }
    1220             : 
    1221             :         /* Oh, thanks to the VT layer, VT_AUTO does not work with KD_GRAPHICS.
    1222             :          * So we need a dummy handler here which just acknowledges *all* VT
    1223             :          * switch requests. */
    1224           0 :         mode.mode = VT_PROCESS;
    1225           0 :         mode.relsig = SIGRTMIN;
    1226           0 :         mode.acqsig = SIGRTMIN + 1;
    1227           0 :         r = ioctl(vt, VT_SETMODE, &mode);
    1228           0 :         if (r < 0) {
    1229           0 :                 r = log_error_errno(errno,
    1230             :                                     "Cannot set VT_PROCESS on /dev/tty%u: %m",
    1231             :                                     s->vtnr);
    1232           0 :                 goto error;
    1233             :         }
    1234             : 
    1235           0 :         return 0;
    1236             : 
    1237           0 : error:
    1238           0 :         session_restore_vt(s);
    1239           0 :         return r;
    1240             : }
    1241             : 
    1242           0 : static void session_restore_vt(Session *s) {
    1243             :         int r, vt, old_fd;
    1244             : 
    1245             :         /* We need to get a fresh handle to the virtual terminal,
    1246             :          * since the old file-descriptor is potentially in a hung-up
    1247             :          * state after the controlling process exited; we do a
    1248             :          * little dance to avoid having the terminal be available
    1249             :          * for reuse before we've cleaned it up.
    1250             :          */
    1251           0 :         old_fd = TAKE_FD(s->vtfd);
    1252             : 
    1253           0 :         vt = session_open_vt(s);
    1254           0 :         safe_close(old_fd);
    1255             : 
    1256           0 :         if (vt < 0)
    1257           0 :                 return;
    1258             : 
    1259           0 :         r = vt_restore(vt);
    1260           0 :         if (r < 0)
    1261           0 :                 log_warning_errno(r, "Failed to restore VT, ignoring: %m");
    1262             : 
    1263           0 :         s->vtfd = safe_close(s->vtfd);
    1264             : }
    1265             : 
    1266           0 : void session_leave_vt(Session *s) {
    1267             :         int r;
    1268             : 
    1269           0 :         assert(s);
    1270             : 
    1271             :         /* This is called whenever we get a VT-switch signal from the kernel.
    1272             :          * We acknowledge all of them unconditionally. Note that session are
    1273             :          * free to overwrite those handlers and we only register them for
    1274             :          * sessions with controllers. Legacy sessions are not affected.
    1275             :          * However, if we switch from a non-legacy to a legacy session, we must
    1276             :          * make sure to pause all device before acknowledging the switch. We
    1277             :          * process the real switch only after we are notified via sysfs, so the
    1278             :          * legacy session might have already started using the devices. If we
    1279             :          * don't pause the devices before the switch, we might confuse the
    1280             :          * session we switch to. */
    1281             : 
    1282           0 :         if (s->vtfd < 0)
    1283           0 :                 return;
    1284             : 
    1285           0 :         session_device_pause_all(s);
    1286           0 :         r = vt_release(s->vtfd, false);
    1287           0 :         if (r < 0)
    1288           0 :                 log_debug_errno(r, "Cannot release VT of session %s: %m", s->id);
    1289             : }
    1290             : 
    1291           0 : bool session_is_controller(Session *s, const char *sender) {
    1292           0 :         assert(s);
    1293             : 
    1294           0 :         return streq_ptr(s->controller, sender);
    1295             : }
    1296             : 
    1297           0 : static void session_release_controller(Session *s, bool notify) {
    1298           0 :         _cleanup_free_ char *name = NULL;
    1299             :         SessionDevice *sd;
    1300             : 
    1301           0 :         if (!s->controller)
    1302           0 :                 return;
    1303             : 
    1304           0 :         name = s->controller;
    1305             : 
    1306             :         /* By resetting the controller before releasing the devices, we won't
    1307             :          * send notification signals. This avoids sending useless notifications
    1308             :          * if the controller is released on disconnects. */
    1309           0 :         if (!notify)
    1310           0 :                 s->controller = NULL;
    1311             : 
    1312           0 :         while ((sd = hashmap_first(s->devices)))
    1313           0 :                 session_device_free(sd);
    1314             : 
    1315           0 :         s->controller = NULL;
    1316           0 :         s->track = sd_bus_track_unref(s->track);
    1317             : }
    1318             : 
    1319           0 : static int on_bus_track(sd_bus_track *track, void *userdata) {
    1320           0 :         Session *s = userdata;
    1321             : 
    1322           0 :         assert(track);
    1323           0 :         assert(s);
    1324             : 
    1325           0 :         session_drop_controller(s);
    1326             : 
    1327           0 :         return 0;
    1328             : }
    1329             : 
    1330           0 : int session_set_controller(Session *s, const char *sender, bool force, bool prepare) {
    1331           0 :         _cleanup_free_ char *name = NULL;
    1332             :         int r;
    1333             : 
    1334           0 :         assert(s);
    1335           0 :         assert(sender);
    1336             : 
    1337           0 :         if (session_is_controller(s, sender))
    1338           0 :                 return 0;
    1339           0 :         if (s->controller && !force)
    1340           0 :                 return -EBUSY;
    1341             : 
    1342           0 :         name = strdup(sender);
    1343           0 :         if (!name)
    1344           0 :                 return -ENOMEM;
    1345             : 
    1346           0 :         s->track = sd_bus_track_unref(s->track);
    1347           0 :         r = sd_bus_track_new(s->manager->bus, &s->track, on_bus_track, s);
    1348           0 :         if (r < 0)
    1349           0 :                 return r;
    1350             : 
    1351           0 :         r = sd_bus_track_add_name(s->track, name);
    1352           0 :         if (r < 0)
    1353           0 :                 return r;
    1354             : 
    1355             :         /* When setting a session controller, we forcibly mute the VT and set
    1356             :          * it into graphics-mode. Applications can override that by changing
    1357             :          * VT state after calling TakeControl(). However, this serves as a good
    1358             :          * default and well-behaving controllers can now ignore VTs entirely.
    1359             :          * Note that we reset the VT on ReleaseControl() and if the controller
    1360             :          * exits.
    1361             :          * If logind crashes/restarts, we restore the controller during restart
    1362             :          * (without preparing the VT since the controller has probably overridden
    1363             :          * VT state by now) or reset the VT in case it crashed/exited, too. */
    1364           0 :         if (prepare) {
    1365           0 :                 r = session_prepare_vt(s);
    1366           0 :                 if (r < 0) {
    1367           0 :                         s->track = sd_bus_track_unref(s->track);
    1368           0 :                         return r;
    1369             :                 }
    1370             :         }
    1371             : 
    1372           0 :         session_release_controller(s, true);
    1373           0 :         s->controller = TAKE_PTR(name);
    1374           0 :         session_save(s);
    1375             : 
    1376           0 :         return 0;
    1377             : }
    1378             : 
    1379           0 : void session_drop_controller(Session *s) {
    1380           0 :         assert(s);
    1381             : 
    1382           0 :         if (!s->controller)
    1383           0 :                 return;
    1384             : 
    1385           0 :         s->track = sd_bus_track_unref(s->track);
    1386           0 :         session_release_controller(s, false);
    1387           0 :         session_save(s);
    1388           0 :         session_restore_vt(s);
    1389             : }
    1390             : 
    1391             : static const char* const session_state_table[_SESSION_STATE_MAX] = {
    1392             :         [SESSION_OPENING] = "opening",
    1393             :         [SESSION_ONLINE] = "online",
    1394             :         [SESSION_ACTIVE] = "active",
    1395             :         [SESSION_CLOSING] = "closing"
    1396             : };
    1397             : 
    1398          12 : DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
    1399             : 
    1400             : static const char* const session_type_table[_SESSION_TYPE_MAX] = {
    1401             :         [SESSION_UNSPECIFIED] = "unspecified",
    1402             :         [SESSION_TTY] = "tty",
    1403             :         [SESSION_X11] = "x11",
    1404             :         [SESSION_WAYLAND] = "wayland",
    1405             :         [SESSION_MIR] = "mir",
    1406             :         [SESSION_WEB] = "web",
    1407             : };
    1408             : 
    1409          16 : DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
    1410             : 
    1411             : static const char* const session_class_table[_SESSION_CLASS_MAX] = {
    1412             :         [SESSION_USER] = "user",
    1413             :         [SESSION_GREETER] = "greeter",
    1414             :         [SESSION_LOCK_SCREEN] = "lock-screen",
    1415             :         [SESSION_BACKGROUND] = "background"
    1416             : };
    1417             : 
    1418          12 : DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
    1419             : 
    1420             : static const char* const kill_who_table[_KILL_WHO_MAX] = {
    1421             :         [KILL_LEADER] = "leader",
    1422             :         [KILL_ALL] = "all"
    1423             : };
    1424             : 
    1425           8 : DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);
    1426             : 
    1427             : static const char* const tty_validity_table[_TTY_VALIDITY_MAX] = {
    1428             :         [TTY_FROM_PAM] = "from-pam",
    1429             :         [TTY_FROM_UTMP] = "from-utmp",
    1430             :         [TTY_UTMP_INCONSISTENT] = "utmp-inconsistent",
    1431             : };
    1432             : 
    1433           0 : DEFINE_STRING_TABLE_LOOKUP(tty_validity, TTYValidity);

Generated by: LCOV version 1.14