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