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