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