chiark / gitweb /
logind: introduce session-devices
[elogind.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);