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