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