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