]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/login/logind-session.c
Merge pull request #837 from ssahani/dhcp
[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 int r = 0;
660 SessionDevice *sd;
661
662 assert(s);
663
664 if (!s->user)
665 return -ESTALE;
666
667 if (s->started)
668 log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
669 LOG_MESSAGE_ID(SD_MESSAGE_SESSION_STOP),
670 "SESSION_ID=%s", s->id,
671 "USER_ID=%s", s->user->name,
672 "LEADER="PID_FMT, s->leader,
673 LOG_MESSAGE("Removed session %s.", s->id),
674 NULL);
675
676 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
677
678 if (s->seat)
679 seat_evict_position(s->seat, s);
680
681 /* Kill session devices */
682 while ((sd = hashmap_first(s->devices)))
683 session_device_free(sd);
684
685 unlink(s->state_file);
686 session_add_to_gc_queue(s);
687 user_add_to_gc_queue(s->user);
688
689 if (s->started) {
690 session_send_signal(s, false);
691 s->started = false;
692 }
693
694 if (s->seat) {
695 if (s->seat->active == s)
696 seat_set_active(s->seat, NULL);
697
698 seat_save(s->seat);
699 seat_send_changed(s->seat, "Sessions", NULL);
700 }
701
702 user_save(s->user);
703 user_send_changed(s->user, "Sessions", "Display", NULL);
704
705 return r;
706 }
707
708 static int release_timeout_callback(sd_event_source *es, uint64_t usec, void *userdata) {
709 Session *s = userdata;
710
711 assert(es);
712 assert(s);
713
714 session_stop(s, false);
715 return 0;
716 }
717
718 int session_release(Session *s) {
719 assert(s);
720
721 if (!s->started || s->stopping)
722 return 0;
723
724 if (s->timer_event_source)
725 return 0;
726
727 return sd_event_add_time(s->manager->event,
728 &s->timer_event_source,
729 CLOCK_MONOTONIC,
730 now(CLOCK_MONOTONIC) + RELEASE_USEC, 0,
731 release_timeout_callback, s);
732 }
733
734 bool session_is_active(Session *s) {
735 assert(s);
736
737 if (!s->seat)
738 return true;
739
740 return s->seat->active == s;
741 }
742
743 static int get_tty_atime(const char *tty, usec_t *atime) {
744 _cleanup_free_ char *p = NULL;
745 struct stat st;
746
747 assert(tty);
748 assert(atime);
749
750 if (!path_is_absolute(tty)) {
751 p = strappend("/dev/", tty);
752 if (!p)
753 return -ENOMEM;
754
755 tty = p;
756 } else if (!path_startswith(tty, "/dev/"))
757 return -ENOENT;
758
759 if (lstat(tty, &st) < 0)
760 return -errno;
761
762 *atime = timespec_load(&st.st_atim);
763 return 0;
764 }
765
766 static int get_process_ctty_atime(pid_t pid, usec_t *atime) {
767 _cleanup_free_ char *p = NULL;
768 int r;
769
770 assert(pid > 0);
771 assert(atime);
772
773 r = get_ctty(pid, NULL, &p);
774 if (r < 0)
775 return r;
776
777 return get_tty_atime(p, atime);
778 }
779
780 int session_get_idle_hint(Session *s, dual_timestamp *t) {
781 usec_t atime = 0, n;
782 int r;
783
784 assert(s);
785
786 /* Explicit idle hint is set */
787 if (s->idle_hint) {
788 if (t)
789 *t = s->idle_hint_timestamp;
790
791 return s->idle_hint;
792 }
793
794 /* Graphical sessions should really implement a real
795 * idle hint logic */
796 if (s->display)
797 goto dont_know;
798
799 /* For sessions with an explicitly configured tty, let's check
800 * its atime */
801 if (s->tty) {
802 r = get_tty_atime(s->tty, &atime);
803 if (r >= 0)
804 goto found_atime;
805 }
806
807 /* For sessions with a leader but no explicitly configured
808 * tty, let's check the controlling tty of the leader */
809 if (s->leader > 0) {
810 r = get_process_ctty_atime(s->leader, &atime);
811 if (r >= 0)
812 goto found_atime;
813 }
814
815 dont_know:
816 if (t)
817 *t = s->idle_hint_timestamp;
818
819 return 0;
820
821 found_atime:
822 if (t)
823 dual_timestamp_from_realtime(t, atime);
824
825 n = now(CLOCK_REALTIME);
826
827 if (s->manager->idle_action_usec <= 0)
828 return 0;
829
830 return atime + s->manager->idle_action_usec <= n;
831 }
832
833 void session_set_idle_hint(Session *s, bool b) {
834 assert(s);
835
836 if (s->idle_hint == b)
837 return;
838
839 s->idle_hint = b;
840 dual_timestamp_get(&s->idle_hint_timestamp);
841
842 session_send_changed(s, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
843
844 if (s->seat)
845 seat_send_changed(s->seat, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
846
847 user_send_changed(s->user, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
848 manager_send_changed(s->manager, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
849 }
850
851 static int session_dispatch_fifo(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
852 Session *s = userdata;
853
854 assert(s);
855 assert(s->fifo_fd == fd);
856
857 /* EOF on the FIFO means the session died abnormally. */
858
859 session_remove_fifo(s);
860 session_stop(s, false);
861
862 return 1;
863 }
864
865 int session_create_fifo(Session *s) {
866 int r;
867
868 assert(s);
869
870 /* Create FIFO */
871 if (!s->fifo_path) {
872 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
873 if (r < 0)
874 return r;
875
876 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
877 return -ENOMEM;
878
879 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
880 return -errno;
881 }
882
883 /* Open reading side */
884 if (s->fifo_fd < 0) {
885 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
886 if (s->fifo_fd < 0)
887 return -errno;
888
889 }
890
891 if (!s->fifo_event_source) {
892 r = sd_event_add_io(s->manager->event, &s->fifo_event_source, s->fifo_fd, 0, session_dispatch_fifo, s);
893 if (r < 0)
894 return r;
895
896 r = sd_event_source_set_priority(s->fifo_event_source, SD_EVENT_PRIORITY_IDLE);
897 if (r < 0)
898 return r;
899 }
900
901 /* Open writing side */
902 r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
903 if (r < 0)
904 return -errno;
905
906 return r;
907 }
908
909 static void session_remove_fifo(Session *s) {
910 assert(s);
911
912 s->fifo_event_source = sd_event_source_unref(s->fifo_event_source);
913 s->fifo_fd = safe_close(s->fifo_fd);
914
915 if (s->fifo_path) {
916 unlink(s->fifo_path);
917 free(s->fifo_path);
918 s->fifo_path = NULL;
919 }
920 }
921
922 bool session_check_gc(Session *s, bool drop_not_started) {
923 assert(s);
924
925 if (drop_not_started && !s->started)
926 return false;
927
928 if (!s->user)
929 return false;
930
931 if (s->fifo_fd >= 0) {
932 if (pipe_eof(s->fifo_fd) <= 0)
933 return true;
934 }
935
936 if (s->scope_job && manager_job_is_active(s->manager, s->scope_job))
937 return true;
938
939 if (s->scope && manager_unit_is_active(s->manager, s->scope))
940 return true;
941
942 return false;
943 }
944
945 void session_add_to_gc_queue(Session *s) {
946 assert(s);
947
948 if (s->in_gc_queue)
949 return;
950
951 LIST_PREPEND(gc_queue, s->manager->session_gc_queue, s);
952 s->in_gc_queue = true;
953 }
954
955 SessionState session_get_state(Session *s) {
956 assert(s);
957
958 /* always check closing first */
959 if (s->stopping || s->timer_event_source)
960 return SESSION_CLOSING;
961
962 if (s->scope_job || s->fifo_fd < 0)
963 return SESSION_OPENING;
964
965 if (session_is_active(s))
966 return SESSION_ACTIVE;
967
968 return SESSION_ONLINE;
969 }
970
971 int session_kill(Session *s, KillWho who, int signo) {
972 assert(s);
973
974 if (!s->scope)
975 return -ESRCH;
976
977 return manager_kill_unit(s->manager, s->scope, who, signo, NULL);
978 }
979
980 static int session_open_vt(Session *s) {
981 char path[sizeof("/dev/tty") + DECIMAL_STR_MAX(s->vtnr)];
982
983 if (s->vtnr < 1)
984 return -ENODEV;
985
986 if (s->vtfd >= 0)
987 return s->vtfd;
988
989 sprintf(path, "/dev/tty%u", s->vtnr);
990 s->vtfd = open(path, O_RDWR | O_CLOEXEC | O_NONBLOCK | O_NOCTTY);
991 if (s->vtfd < 0)
992 return log_error_errno(errno, "cannot open VT %s of session %s: %m", path, s->id);
993
994 return s->vtfd;
995 }
996
997 int session_prepare_vt(Session *s) {
998 int vt, r;
999 struct vt_mode mode = { 0 };
1000
1001 if (s->vtnr < 1)
1002 return 0;
1003
1004 vt = session_open_vt(s);
1005 if (vt < 0)
1006 return vt;
1007
1008 r = fchown(vt, s->user->uid, -1);
1009 if (r < 0) {
1010 r = -errno;
1011 log_error_errno(errno, "Cannot change owner of /dev/tty%u: %m", s->vtnr);
1012 goto error;
1013 }
1014
1015 r = ioctl(vt, KDSKBMODE, K_OFF);
1016 if (r < 0) {
1017 r = -errno;
1018 log_error_errno(errno, "Cannot set K_OFF on /dev/tty%u: %m", s->vtnr);
1019 goto error;
1020 }
1021
1022 r = ioctl(vt, KDSETMODE, KD_GRAPHICS);
1023 if (r < 0) {
1024 r = -errno;
1025 log_error_errno(errno, "Cannot set KD_GRAPHICS on /dev/tty%u: %m", s->vtnr);
1026 goto error;
1027 }
1028
1029 /* Oh, thanks to the VT layer, VT_AUTO does not work with KD_GRAPHICS.
1030 * So we need a dummy handler here which just acknowledges *all* VT
1031 * switch requests. */
1032 mode.mode = VT_PROCESS;
1033 mode.relsig = SIGRTMIN;
1034 mode.acqsig = SIGRTMIN + 1;
1035 r = ioctl(vt, VT_SETMODE, &mode);
1036 if (r < 0) {
1037 r = -errno;
1038 log_error_errno(errno, "Cannot set VT_PROCESS on /dev/tty%u: %m", s->vtnr);
1039 goto error;
1040 }
1041
1042 return 0;
1043
1044 error:
1045 session_restore_vt(s);
1046 return r;
1047 }
1048
1049 void session_restore_vt(Session *s) {
1050 _cleanup_free_ char *utf8 = NULL;
1051 int vt, kb = K_XLATE;
1052 struct vt_mode mode = { 0 };
1053
1054 vt = session_open_vt(s);
1055 if (vt < 0)
1056 return;
1057
1058 (void) ioctl(vt, KDSETMODE, KD_TEXT);
1059
1060 if (read_one_line_file("/sys/module/vt/parameters/default_utf8", &utf8) >= 0 && *utf8 == '1')
1061 kb = K_UNICODE;
1062
1063 (void) ioctl(vt, KDSKBMODE, kb);
1064
1065 mode.mode = VT_AUTO;
1066 (void) ioctl(vt, VT_SETMODE, &mode);
1067
1068 fchown(vt, 0, -1);
1069
1070 s->vtfd = safe_close(s->vtfd);
1071 }
1072
1073 void session_leave_vt(Session *s) {
1074 int r;
1075
1076 assert(s);
1077
1078 /* This is called whenever we get a VT-switch signal from the kernel.
1079 * We acknowledge all of them unconditionally. Note that session are
1080 * free to overwrite those handlers and we only register them for
1081 * sessions with controllers. Legacy sessions are not affected.
1082 * However, if we switch from a non-legacy to a legacy session, we must
1083 * make sure to pause all device before acknowledging the switch. We
1084 * process the real switch only after we are notified via sysfs, so the
1085 * legacy session might have already started using the devices. If we
1086 * don't pause the devices before the switch, we might confuse the
1087 * session we switch to. */
1088
1089 if (s->vtfd < 0)
1090 return;
1091
1092 session_device_pause_all(s);
1093 r = ioctl(s->vtfd, VT_RELDISP, 1);
1094 if (r < 0)
1095 log_debug_errno(errno, "Cannot release VT of session %s: %m", s->id);
1096 }
1097
1098 bool session_is_controller(Session *s, const char *sender) {
1099 assert(s);
1100
1101 return streq_ptr(s->controller, sender);
1102 }
1103
1104 static void session_release_controller(Session *s, bool notify) {
1105 _cleanup_free_ char *name = NULL;
1106 SessionDevice *sd;
1107
1108 if (!s->controller)
1109 return;
1110
1111 name = s->controller;
1112
1113 /* By resetting the controller before releasing the devices, we won't
1114 * send notification signals. This avoids sending useless notifications
1115 * if the controller is released on disconnects. */
1116 if (!notify)
1117 s->controller = NULL;
1118
1119 while ((sd = hashmap_first(s->devices)))
1120 session_device_free(sd);
1121
1122 s->controller = NULL;
1123 manager_drop_busname(s->manager, name);
1124 }
1125
1126 int session_set_controller(Session *s, const char *sender, bool force) {
1127 _cleanup_free_ char *name = NULL;
1128 int r;
1129
1130 assert(s);
1131 assert(sender);
1132
1133 if (session_is_controller(s, sender))
1134 return 0;
1135 if (s->controller && !force)
1136 return -EBUSY;
1137
1138 name = strdup(sender);
1139 if (!name)
1140 return -ENOMEM;
1141
1142 r = manager_watch_busname(s->manager, name);
1143 if (r)
1144 return r;
1145
1146 /* When setting a session controller, we forcibly mute the VT and set
1147 * it into graphics-mode. Applications can override that by changing
1148 * VT state after calling TakeControl(). However, this serves as a good
1149 * default and well-behaving controllers can now ignore VTs entirely.
1150 * Note that we reset the VT on ReleaseControl() and if the controller
1151 * exits.
1152 * If logind crashes/restarts, we restore the controller during restart
1153 * or reset the VT in case it crashed/exited, too. */
1154 r = session_prepare_vt(s);
1155 if (r < 0) {
1156 manager_drop_busname(s->manager, name);
1157 return r;
1158 }
1159
1160 session_release_controller(s, true);
1161 s->controller = name;
1162 name = NULL;
1163 session_save(s);
1164
1165 return 0;
1166 }
1167
1168 void session_drop_controller(Session *s) {
1169 assert(s);
1170
1171 if (!s->controller)
1172 return;
1173
1174 session_release_controller(s, false);
1175 session_save(s);
1176 session_restore_vt(s);
1177 }
1178
1179 static const char* const session_state_table[_SESSION_STATE_MAX] = {
1180 [SESSION_OPENING] = "opening",
1181 [SESSION_ONLINE] = "online",
1182 [SESSION_ACTIVE] = "active",
1183 [SESSION_CLOSING] = "closing"
1184 };
1185
1186 DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
1187
1188 static const char* const session_type_table[_SESSION_TYPE_MAX] = {
1189 [SESSION_UNSPECIFIED] = "unspecified",
1190 [SESSION_TTY] = "tty",
1191 [SESSION_X11] = "x11",
1192 [SESSION_WAYLAND] = "wayland",
1193 [SESSION_MIR] = "mir",
1194 [SESSION_WEB] = "web",
1195 };
1196
1197 DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
1198
1199 static const char* const session_class_table[_SESSION_CLASS_MAX] = {
1200 [SESSION_USER] = "user",
1201 [SESSION_GREETER] = "greeter",
1202 [SESSION_LOCK_SCREEN] = "lock-screen",
1203 [SESSION_BACKGROUND] = "background"
1204 };
1205
1206 DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
1207
1208 static const char* const kill_who_table[_KILL_WHO_MAX] = {
1209 [KILL_LEADER] = "leader",
1210 [KILL_ALL] = "all"
1211 };
1212
1213 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);