]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/login/logind-session.c
treewide: use log_*_errno whenever %m is in the format string
[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-id128.h"
32 #include "sd-messages.h"
33 #include "strv.h"
34 #include "util.h"
35 #include "mkdir.h"
36 #include "path-util.h"
37 #include "fileio.h"
38 #include "audit.h"
39 #include "bus-util.h"
40 #include "bus-error.h"
41 #include "logind-session.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 finish;
169
170 r = fopen_temporary(s->state_file, &f, &temp_path);
171 if (r < 0)
172 goto finish;
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 finish;
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 finish;
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 finish;
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 finish;
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, "POS=%u\n", s->pos);
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 fflush(f);
286
287 if (ferror(f) || rename(temp_path, s->state_file) < 0) {
288 r = -errno;
289 unlink(s->state_file);
290 unlink(temp_path);
291 }
292
293 finish:
294 if (r < 0)
295 log_error_errno(r, "Failed to save session data %s: %m", s->state_file);
296
297 return r;
298 }
299
300 int session_load(Session *s) {
301 _cleanup_free_ char *remote = NULL,
302 *seat = NULL,
303 *vtnr = NULL,
304 *pos = NULL,
305 *leader = NULL,
306 *type = NULL,
307 *class = NULL,
308 *uid = NULL,
309 *realtime = NULL,
310 *monotonic = NULL,
311 *controller = NULL;
312
313 int k, r;
314
315 assert(s);
316
317 r = parse_env_file(s->state_file, NEWLINE,
318 "REMOTE", &remote,
319 "SCOPE", &s->scope,
320 "SCOPE_JOB", &s->scope_job,
321 "FIFO", &s->fifo_path,
322 "SEAT", &seat,
323 "TTY", &s->tty,
324 "DISPLAY", &s->display,
325 "REMOTE_HOST", &s->remote_host,
326 "REMOTE_USER", &s->remote_user,
327 "SERVICE", &s->service,
328 "DESKTOP", &s->desktop,
329 "VTNR", &vtnr,
330 "POS", &pos,
331 "LEADER", &leader,
332 "TYPE", &type,
333 "CLASS", &class,
334 "UID", &uid,
335 "REALTIME", &realtime,
336 "MONOTONIC", &monotonic,
337 "CONTROLLER", &controller,
338 NULL);
339
340 if (r < 0)
341 return log_error_errno(r, "Failed to read %s: %m", s->state_file);
342
343 if (!s->user) {
344 uid_t u;
345 User *user;
346
347 if (!uid) {
348 log_error("UID not specified for session %s", s->id);
349 return -ENOENT;
350 }
351
352 r = parse_uid(uid, &u);
353 if (r < 0) {
354 log_error("Failed to parse UID value %s for session %s.", uid, s->id);
355 return r;
356 }
357
358 user = hashmap_get(s->manager->users, ULONG_TO_PTR((unsigned long) u));
359 if (!user) {
360 log_error("User of session %s not known.", s->id);
361 return -ENOENT;
362 }
363
364 session_set_user(s, user);
365 }
366
367 if (remote) {
368 k = parse_boolean(remote);
369 if (k >= 0)
370 s->remote = k;
371 }
372
373 if (vtnr)
374 safe_atou(vtnr, &s->vtnr);
375
376 if (seat && !s->seat) {
377 Seat *o;
378
379 o = hashmap_get(s->manager->seats, seat);
380 if (o)
381 r = seat_attach_session(o, s);
382 if (!o || r < 0)
383 log_error("Cannot attach session %s to seat %s", s->id, seat);
384 }
385
386 if (!s->seat || !seat_has_vts(s->seat))
387 s->vtnr = 0;
388
389 if (pos && s->seat) {
390 unsigned int npos;
391
392 safe_atou(pos, &npos);
393 seat_claim_position(s->seat, s, npos);
394 }
395
396 if (leader) {
397 k = parse_pid(leader, &s->leader);
398 if (k >= 0)
399 audit_session_from_pid(s->leader, &s->audit_id);
400 }
401
402 if (type) {
403 SessionType t;
404
405 t = session_type_from_string(type);
406 if (t >= 0)
407 s->type = t;
408 }
409
410 if (class) {
411 SessionClass c;
412
413 c = session_class_from_string(class);
414 if (c >= 0)
415 s->class = c;
416 }
417
418 if (s->fifo_path) {
419 int fd;
420
421 /* If we open an unopened pipe for reading we will not
422 get an EOF. to trigger an EOF we hence open it for
423 reading, but close it right-away which then will
424 trigger the EOF. */
425
426 fd = session_create_fifo(s);
427 safe_close(fd);
428 }
429
430 if (realtime) {
431 unsigned long long l;
432 if (sscanf(realtime, "%llu", &l) > 0)
433 s->timestamp.realtime = l;
434 }
435
436 if (monotonic) {
437 unsigned long long l;
438 if (sscanf(monotonic, "%llu", &l) > 0)
439 s->timestamp.monotonic = l;
440 }
441
442 if (controller) {
443 if (bus_name_has_owner(s->manager->bus, controller, NULL) > 0)
444 session_set_controller(s, controller, false);
445 else
446 session_restore_vt(s);
447 }
448
449 return r;
450 }
451
452 int session_activate(Session *s) {
453 unsigned int num_pending;
454
455 assert(s);
456 assert(s->user);
457
458 if (!s->seat)
459 return -ENOTSUP;
460
461 if (s->seat->active == s)
462 return 0;
463
464 /* on seats with VTs, we let VTs manage session-switching */
465 if (seat_has_vts(s->seat)) {
466 if (!s->vtnr)
467 return -ENOTSUP;
468
469 return chvt(s->vtnr);
470 }
471
472 /* On seats without VTs, we implement session-switching in logind. We
473 * try to pause all session-devices and wait until the session
474 * controller acknowledged them. Once all devices are asleep, we simply
475 * switch the active session and be done.
476 * We save the session we want to switch to in seat->pending_switch and
477 * seat_complete_switch() will perform the final switch. */
478
479 s->seat->pending_switch = s;
480
481 /* if no devices are running, immediately perform the session switch */
482 num_pending = session_device_try_pause_all(s);
483 if (!num_pending)
484 seat_complete_switch(s->seat);
485
486 return 0;
487 }
488
489 static int session_start_scope(Session *s) {
490 int r;
491
492 assert(s);
493 assert(s->user);
494 assert(s->user->slice);
495
496 if (!s->scope) {
497 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
498 _cleanup_free_ char *description = NULL;
499 char *scope, *job = NULL;
500
501 description = strjoin("Session ", s->id, " of user ", s->user->name, NULL);
502 if (!description)
503 return log_oom();
504
505 scope = strjoin("session-", s->id, ".scope", NULL);
506 if (!scope)
507 return log_oom();
508
509 r = manager_start_scope(s->manager, scope, s->leader, s->user->slice, description, "systemd-logind.service", "systemd-user-sessions.service", &error, &job);
510 if (r < 0) {
511 log_error("Failed to start session scope %s: %s %s",
512 scope, bus_error_message(&error, r), error.name);
513 free(scope);
514 return r;
515 } else {
516 s->scope = scope;
517
518 free(s->scope_job);
519 s->scope_job = job;
520 }
521 }
522
523 if (s->scope)
524 hashmap_put(s->manager->session_units, s->scope, s);
525
526 return 0;
527 }
528
529 int session_start(Session *s) {
530 int r;
531
532 assert(s);
533
534 if (!s->user)
535 return -ESTALE;
536
537 if (s->started)
538 return 0;
539
540 r = user_start(s->user);
541 if (r < 0)
542 return r;
543
544 /* Create cgroup */
545 r = session_start_scope(s);
546 if (r < 0)
547 return r;
548
549 log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
550 LOG_MESSAGE_ID(SD_MESSAGE_SESSION_START),
551 "SESSION_ID=%s", s->id,
552 "USER_ID=%s", s->user->name,
553 "LEADER="PID_FMT, s->leader,
554 LOG_MESSAGE("New session %s of user %s.", s->id, s->user->name),
555 NULL);
556
557 if (!dual_timestamp_is_set(&s->timestamp))
558 dual_timestamp_get(&s->timestamp);
559
560 if (s->seat)
561 seat_read_active_vt(s->seat);
562
563 s->started = true;
564
565 user_elect_display(s->user);
566
567 /* Save data */
568 session_save(s);
569 user_save(s->user);
570 if (s->seat)
571 seat_save(s->seat);
572
573 /* Send signals */
574 session_send_signal(s, true);
575 user_send_changed(s->user, "Sessions", "Display", NULL);
576 if (s->seat) {
577 if (s->seat->active == s)
578 seat_send_changed(s->seat, "Sessions", "ActiveSession", NULL);
579 else
580 seat_send_changed(s->seat, "Sessions", NULL);
581 }
582
583 return 0;
584 }
585
586 static int session_stop_scope(Session *s, bool force) {
587 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
588 char *job = NULL;
589 int r;
590
591 assert(s);
592
593 if (!s->scope)
594 return 0;
595
596 if (force || manager_shall_kill(s->manager, s->user->name)) {
597 r = manager_stop_unit(s->manager, s->scope, &error, &job);
598 if (r < 0) {
599 log_error("Failed to stop session scope: %s", bus_error_message(&error, r));
600 return r;
601 }
602
603 free(s->scope_job);
604 s->scope_job = job;
605 } else {
606 r = manager_abandon_scope(s->manager, s->scope, &error);
607 if (r < 0) {
608 log_error("Failed to abandon session scope: %s", bus_error_message(&error, r));
609 return r;
610 }
611 }
612
613 return 0;
614 }
615
616 int session_stop(Session *s, bool force) {
617 int r;
618
619 assert(s);
620
621 if (!s->user)
622 return -ESTALE;
623
624 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
625
626 /* We are going down, don't care about FIFOs anymore */
627 session_remove_fifo(s);
628
629 /* Kill cgroup */
630 r = session_stop_scope(s, force);
631
632 s->stopping = true;
633
634 user_elect_display(s->user);
635
636 session_save(s);
637 user_save(s->user);
638
639 return r;
640 }
641
642 int session_finalize(Session *s) {
643 int r = 0;
644 SessionDevice *sd;
645
646 assert(s);
647
648 if (!s->user)
649 return -ESTALE;
650
651 if (s->started)
652 log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
653 LOG_MESSAGE_ID(SD_MESSAGE_SESSION_STOP),
654 "SESSION_ID=%s", s->id,
655 "USER_ID=%s", s->user->name,
656 "LEADER="PID_FMT, s->leader,
657 LOG_MESSAGE("Removed session %s.", s->id),
658 NULL);
659
660 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
661
662 /* Kill session devices */
663 while ((sd = hashmap_first(s->devices)))
664 session_device_free(sd);
665
666 unlink(s->state_file);
667 session_add_to_gc_queue(s);
668 user_add_to_gc_queue(s->user);
669
670 if (s->started) {
671 session_send_signal(s, false);
672 s->started = false;
673 }
674
675 if (s->seat) {
676 if (s->seat->active == s)
677 seat_set_active(s->seat, NULL);
678
679 seat_save(s->seat);
680 seat_send_changed(s->seat, "Sessions", NULL);
681 }
682
683 user_save(s->user);
684 user_send_changed(s->user, "Sessions", "Display", NULL);
685
686 return r;
687 }
688
689 static int release_timeout_callback(sd_event_source *es, uint64_t usec, void *userdata) {
690 Session *s = userdata;
691
692 assert(es);
693 assert(s);
694
695 session_stop(s, false);
696 return 0;
697 }
698
699 void session_release(Session *s) {
700 assert(s);
701
702 if (!s->started || s->stopping)
703 return;
704
705 if (!s->timer_event_source)
706 sd_event_add_time(s->manager->event,
707 &s->timer_event_source,
708 CLOCK_MONOTONIC,
709 now(CLOCK_MONOTONIC) + RELEASE_USEC, 0,
710 release_timeout_callback, s);
711 }
712
713 bool session_is_active(Session *s) {
714 assert(s);
715
716 if (!s->seat)
717 return true;
718
719 return s->seat->active == s;
720 }
721
722 static int get_tty_atime(const char *tty, usec_t *atime) {
723 _cleanup_free_ char *p = NULL;
724 struct stat st;
725
726 assert(tty);
727 assert(atime);
728
729 if (!path_is_absolute(tty)) {
730 p = strappend("/dev/", tty);
731 if (!p)
732 return -ENOMEM;
733
734 tty = p;
735 } else if (!path_startswith(tty, "/dev/"))
736 return -ENOENT;
737
738 if (lstat(tty, &st) < 0)
739 return -errno;
740
741 *atime = timespec_load(&st.st_atim);
742 return 0;
743 }
744
745 static int get_process_ctty_atime(pid_t pid, usec_t *atime) {
746 _cleanup_free_ char *p = NULL;
747 int r;
748
749 assert(pid > 0);
750 assert(atime);
751
752 r = get_ctty(pid, NULL, &p);
753 if (r < 0)
754 return r;
755
756 return get_tty_atime(p, atime);
757 }
758
759 int session_get_idle_hint(Session *s, dual_timestamp *t) {
760 usec_t atime = 0, n;
761 int r;
762
763 assert(s);
764
765 /* Explicit idle hint is set */
766 if (s->idle_hint) {
767 if (t)
768 *t = s->idle_hint_timestamp;
769
770 return s->idle_hint;
771 }
772
773 /* Graphical sessions should really implement a real
774 * idle hint logic */
775 if (s->display)
776 goto dont_know;
777
778 /* For sessions with an explicitly configured tty, let's check
779 * its atime */
780 if (s->tty) {
781 r = get_tty_atime(s->tty, &atime);
782 if (r >= 0)
783 goto found_atime;
784 }
785
786 /* For sessions with a leader but no explicitly configured
787 * tty, let's check the controlling tty of the leader */
788 if (s->leader > 0) {
789 r = get_process_ctty_atime(s->leader, &atime);
790 if (r >= 0)
791 goto found_atime;
792 }
793
794 dont_know:
795 if (t)
796 *t = s->idle_hint_timestamp;
797
798 return 0;
799
800 found_atime:
801 if (t)
802 dual_timestamp_from_realtime(t, atime);
803
804 n = now(CLOCK_REALTIME);
805
806 if (s->manager->idle_action_usec <= 0)
807 return 0;
808
809 return atime + s->manager->idle_action_usec <= n;
810 }
811
812 void session_set_idle_hint(Session *s, bool b) {
813 assert(s);
814
815 if (s->idle_hint == b)
816 return;
817
818 s->idle_hint = b;
819 dual_timestamp_get(&s->idle_hint_timestamp);
820
821 session_send_changed(s, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
822
823 if (s->seat)
824 seat_send_changed(s->seat, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
825
826 user_send_changed(s->user, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
827 manager_send_changed(s->manager, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
828 }
829
830 static int session_dispatch_fifo(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
831 Session *s = userdata;
832
833 assert(s);
834 assert(s->fifo_fd == fd);
835
836 /* EOF on the FIFO means the session died abnormally. */
837
838 session_remove_fifo(s);
839 session_stop(s, false);
840
841 return 1;
842 }
843
844 int session_create_fifo(Session *s) {
845 int r;
846
847 assert(s);
848
849 /* Create FIFO */
850 if (!s->fifo_path) {
851 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
852 if (r < 0)
853 return r;
854
855 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
856 return -ENOMEM;
857
858 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
859 return -errno;
860 }
861
862 /* Open reading side */
863 if (s->fifo_fd < 0) {
864 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
865 if (s->fifo_fd < 0)
866 return -errno;
867
868 }
869
870 if (!s->fifo_event_source) {
871 r = sd_event_add_io(s->manager->event, &s->fifo_event_source, s->fifo_fd, 0, session_dispatch_fifo, s);
872 if (r < 0)
873 return r;
874
875 r = sd_event_source_set_priority(s->fifo_event_source, SD_EVENT_PRIORITY_IDLE);
876 if (r < 0)
877 return r;
878 }
879
880 /* Open writing side */
881 r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
882 if (r < 0)
883 return -errno;
884
885 return r;
886 }
887
888 static void session_remove_fifo(Session *s) {
889 assert(s);
890
891 s->fifo_event_source = sd_event_source_unref(s->fifo_event_source);
892 s->fifo_fd = safe_close(s->fifo_fd);
893
894 if (s->fifo_path) {
895 unlink(s->fifo_path);
896 free(s->fifo_path);
897 s->fifo_path = NULL;
898 }
899 }
900
901 bool session_check_gc(Session *s, bool drop_not_started) {
902 assert(s);
903
904 if (drop_not_started && !s->started)
905 return false;
906
907 if (!s->user)
908 return false;
909
910 if (s->fifo_fd >= 0) {
911 if (pipe_eof(s->fifo_fd) <= 0)
912 return true;
913 }
914
915 if (s->scope_job && manager_job_is_active(s->manager, s->scope_job))
916 return true;
917
918 if (s->scope && manager_unit_is_active(s->manager, s->scope))
919 return true;
920
921 return false;
922 }
923
924 void session_add_to_gc_queue(Session *s) {
925 assert(s);
926
927 if (s->in_gc_queue)
928 return;
929
930 LIST_PREPEND(gc_queue, s->manager->session_gc_queue, s);
931 s->in_gc_queue = true;
932 }
933
934 SessionState session_get_state(Session *s) {
935 assert(s);
936
937 /* always check closing first */
938 if (s->stopping || s->timer_event_source)
939 return SESSION_CLOSING;
940
941 if (s->scope_job || s->fifo_fd < 0)
942 return SESSION_OPENING;
943
944 if (session_is_active(s))
945 return SESSION_ACTIVE;
946
947 return SESSION_ONLINE;
948 }
949
950 int session_kill(Session *s, KillWho who, int signo) {
951 assert(s);
952
953 if (!s->scope)
954 return -ESRCH;
955
956 return manager_kill_unit(s->manager, s->scope, who, signo, NULL);
957 }
958
959 static int session_open_vt(Session *s) {
960 char path[sizeof("/dev/tty") + DECIMAL_STR_MAX(s->vtnr)];
961
962 if (s->vtnr < 1)
963 return -ENODEV;
964
965 if (s->vtfd >= 0)
966 return s->vtfd;
967
968 sprintf(path, "/dev/tty%u", s->vtnr);
969 s->vtfd = open(path, O_RDWR | O_CLOEXEC | O_NONBLOCK | O_NOCTTY);
970 if (s->vtfd < 0) {
971 log_error_errno(errno, "cannot open VT %s of session %s: %m", path, s->id);
972 return -errno;
973 }
974
975 return s->vtfd;
976 }
977
978 int session_prepare_vt(Session *s) {
979 int vt, r;
980 struct vt_mode mode = { 0 };
981
982 if (s->vtnr < 1)
983 return 0;
984
985 vt = session_open_vt(s);
986 if (vt < 0)
987 return vt;
988
989 r = fchown(vt, s->user->uid, -1);
990 if (r < 0) {
991 r = -errno;
992 log_error_errno(errno, "Cannot change owner of /dev/tty%u: %m", s->vtnr);
993 goto error;
994 }
995
996 r = ioctl(vt, KDSKBMODE, K_OFF);
997 if (r < 0) {
998 r = -errno;
999 log_error_errno(errno, "Cannot set K_OFF on /dev/tty%u: %m", s->vtnr);
1000 goto error;
1001 }
1002
1003 r = ioctl(vt, KDSETMODE, KD_GRAPHICS);
1004 if (r < 0) {
1005 r = -errno;
1006 log_error_errno(errno, "Cannot set KD_GRAPHICS on /dev/tty%u: %m", s->vtnr);
1007 goto error;
1008 }
1009
1010 /* Oh, thanks to the VT layer, VT_AUTO does not work with KD_GRAPHICS.
1011 * So we need a dummy handler here which just acknowledges *all* VT
1012 * switch requests. */
1013 mode.mode = VT_PROCESS;
1014 mode.relsig = SIGRTMIN;
1015 mode.acqsig = SIGRTMIN + 1;
1016 r = ioctl(vt, VT_SETMODE, &mode);
1017 if (r < 0) {
1018 r = -errno;
1019 log_error_errno(errno, "Cannot set VT_PROCESS on /dev/tty%u: %m", s->vtnr);
1020 goto error;
1021 }
1022
1023 return 0;
1024
1025 error:
1026 session_restore_vt(s);
1027 return r;
1028 }
1029
1030 void session_restore_vt(Session *s) {
1031 _cleanup_free_ char *utf8 = NULL;
1032 int vt, kb = K_XLATE;
1033 struct vt_mode mode = { 0 };
1034
1035 vt = session_open_vt(s);
1036 if (vt < 0)
1037 return;
1038
1039 ioctl(vt, KDSETMODE, KD_TEXT);
1040
1041 if (read_one_line_file("/sys/module/vt/parameters/default_utf8", &utf8) >= 0 && *utf8 == '1')
1042 kb = K_UNICODE;
1043
1044 ioctl(vt, KDSKBMODE, kb);
1045
1046 mode.mode = VT_AUTO;
1047 ioctl(vt, VT_SETMODE, &mode);
1048
1049 fchown(vt, 0, -1);
1050
1051 s->vtfd = safe_close(s->vtfd);
1052 }
1053
1054 void session_leave_vt(Session *s) {
1055 int r;
1056
1057 assert(s);
1058
1059 /* This is called whenever we get a VT-switch signal from the kernel.
1060 * We acknowledge all of them unconditionally. Note that session are
1061 * free to overwrite those handlers and we only register them for
1062 * sessions with controllers. Legacy sessions are not affected.
1063 * However, if we switch from a non-legacy to a legacy session, we must
1064 * make sure to pause all device before acknowledging the switch. We
1065 * process the real switch only after we are notified via sysfs, so the
1066 * legacy session might have already started using the devices. If we
1067 * don't pause the devices before the switch, we might confuse the
1068 * session we switch to. */
1069
1070 if (s->vtfd < 0)
1071 return;
1072
1073 session_device_pause_all(s);
1074 r = ioctl(s->vtfd, VT_RELDISP, 1);
1075 if (r < 0)
1076 log_debug_errno(errno, "Cannot release VT of session %s: %m", s->id);
1077 }
1078
1079 bool session_is_controller(Session *s, const char *sender) {
1080 assert(s);
1081
1082 return streq_ptr(s->controller, sender);
1083 }
1084
1085 static void session_release_controller(Session *s, bool notify) {
1086 _cleanup_free_ char *name = NULL;
1087 SessionDevice *sd;
1088
1089 if (!s->controller)
1090 return;
1091
1092 name = s->controller;
1093
1094 /* By resetting the controller before releasing the devices, we won't
1095 * send notification signals. This avoids sending useless notifications
1096 * if the controller is released on disconnects. */
1097 if (!notify)
1098 s->controller = NULL;
1099
1100 while ((sd = hashmap_first(s->devices)))
1101 session_device_free(sd);
1102
1103 s->controller = NULL;
1104 manager_drop_busname(s->manager, name);
1105 }
1106
1107 int session_set_controller(Session *s, const char *sender, bool force) {
1108 _cleanup_free_ char *name = NULL;
1109 int r;
1110
1111 assert(s);
1112 assert(sender);
1113
1114 if (session_is_controller(s, sender))
1115 return 0;
1116 if (s->controller && !force)
1117 return -EBUSY;
1118
1119 name = strdup(sender);
1120 if (!name)
1121 return -ENOMEM;
1122
1123 r = manager_watch_busname(s->manager, name);
1124 if (r)
1125 return r;
1126
1127 /* When setting a session controller, we forcibly mute the VT and set
1128 * it into graphics-mode. Applications can override that by changing
1129 * VT state after calling TakeControl(). However, this serves as a good
1130 * default and well-behaving controllers can now ignore VTs entirely.
1131 * Note that we reset the VT on ReleaseControl() and if the controller
1132 * exits.
1133 * If logind crashes/restarts, we restore the controller during restart
1134 * or reset the VT in case it crashed/exited, too. */
1135 r = session_prepare_vt(s);
1136 if (r < 0) {
1137 manager_drop_busname(s->manager, name);
1138 return r;
1139 }
1140
1141 session_release_controller(s, true);
1142 s->controller = name;
1143 name = NULL;
1144 session_save(s);
1145
1146 return 0;
1147 }
1148
1149 void session_drop_controller(Session *s) {
1150 assert(s);
1151
1152 if (!s->controller)
1153 return;
1154
1155 session_release_controller(s, false);
1156 session_save(s);
1157 session_restore_vt(s);
1158 }
1159
1160 static const char* const session_state_table[_SESSION_STATE_MAX] = {
1161 [SESSION_OPENING] = "opening",
1162 [SESSION_ONLINE] = "online",
1163 [SESSION_ACTIVE] = "active",
1164 [SESSION_CLOSING] = "closing"
1165 };
1166
1167 DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
1168
1169 static const char* const session_type_table[_SESSION_TYPE_MAX] = {
1170 [SESSION_UNSPECIFIED] = "unspecified",
1171 [SESSION_TTY] = "tty",
1172 [SESSION_X11] = "x11",
1173 [SESSION_WAYLAND] = "wayland",
1174 [SESSION_MIR] = "mir",
1175 [SESSION_WEB] = "web",
1176 };
1177
1178 DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
1179
1180 static const char* const session_class_table[_SESSION_CLASS_MAX] = {
1181 [SESSION_USER] = "user",
1182 [SESSION_GREETER] = "greeter",
1183 [SESSION_LOCK_SCREEN] = "lock-screen",
1184 [SESSION_BACKGROUND] = "background"
1185 };
1186
1187 DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
1188
1189 static const char* const kill_who_table[_KILL_WHO_MAX] = {
1190 [KILL_LEADER] = "leader",
1191 [KILL_ALL] = "all"
1192 };
1193
1194 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);