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