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