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