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