chiark / gitweb /
Update TODO
[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_has_vts(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_has_vts(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         assert(s);
364         assert(s->user);
365
366         if (s->vtnr <= 0)
367                 return -ENOTSUP;
368
369         if (!s->seat)
370                 return -ENOTSUP;
371
372         if (s->seat->active == s)
373                 return 0;
374
375         assert(seat_has_vts(s->seat));
376
377         return chvt(s->vtnr);
378 }
379
380 static int session_link_x11_socket(Session *s) {
381         _cleanup_free_ char *t = NULL, *f = NULL;
382         char *c;
383         size_t k;
384
385         assert(s);
386         assert(s->user);
387         assert(s->user->runtime_path);
388
389         if (s->user->display)
390                 return 0;
391
392         if (!s->display || !display_is_local(s->display))
393                 return 0;
394
395         k = strspn(s->display+1, "0123456789");
396         f = new(char, sizeof("/tmp/.X11-unix/X") + k);
397         if (!f)
398                 return log_oom();
399
400         c = stpcpy(f, "/tmp/.X11-unix/X");
401         memcpy(c, s->display+1, k);
402         c[k] = 0;
403
404         if (access(f, F_OK) < 0) {
405                 log_warning("Session %s has display %s with non-existing socket %s.", s->id, s->display, f);
406                 return -ENOENT;
407         }
408
409         /* Note that this cannot be in a subdir to avoid
410          * vulnerabilities since we are privileged but the runtime
411          * path is owned by the user */
412
413         t = strappend(s->user->runtime_path, "/X11-display");
414         if (!t)
415                 return log_oom();
416
417         if (link(f, t) < 0) {
418                 if (errno == EEXIST) {
419                         unlink(t);
420
421                         if (link(f, t) >= 0)
422                                 goto done;
423                 }
424
425                 if (symlink(f, t) < 0) {
426
427                         if (errno == EEXIST) {
428                                 unlink(t);
429
430                                 if (symlink(f, t) >= 0)
431                                         goto done;
432                         }
433
434                         log_error("Failed to link %s to %s: %m", f, t);
435                         return -errno;
436                 }
437         }
438
439 done:
440         log_info("Linked %s to %s.", f, t);
441         s->user->display = s;
442
443         return 0;
444 }
445
446 static int session_start_scope(Session *s) {
447         DBusError error;
448         int r;
449
450         assert(s);
451         assert(s->user);
452         assert(s->user->slice);
453
454         dbus_error_init(&error);
455
456         if (!s->scope) {
457                 _cleanup_free_ char *description = NULL;
458                 const char *kill_mode;
459                 char *scope, *job;
460
461                 description = strjoin("Session ", s->id, " of user ", s->user->name, NULL);
462                 if (!description)
463                         return log_oom();
464
465                 scope = strjoin("session-", s->id, ".scope", NULL);
466                 if (!scope)
467                         return log_oom();
468
469                 kill_mode = manager_shall_kill(s->manager, s->user->name) ? "control-group" : "none";
470
471                 r = manager_start_scope(s->manager, scope, s->leader, s->user->slice, description, "systemd-user-sessions.service", kill_mode, &error, &job);
472                 if (r < 0) {
473                         log_error("Failed to start session scope %s: %s %s",
474                                   scope, bus_error(&error, r), error.name);
475                         dbus_error_free(&error);
476
477                         free(scope);
478                         return r;
479                 } else {
480                         s->scope = scope;
481
482                         free(s->scope_job);
483                         s->scope_job = job;
484                 }
485         }
486
487         if (s->scope)
488                 hashmap_put(s->manager->session_units, s->scope, s);
489
490         return 0;
491 }
492
493 int session_start(Session *s) {
494         int r;
495
496         assert(s);
497
498         if (!s->user)
499                 return -ESTALE;
500
501         if (s->started)
502                 return 0;
503
504         r = user_start(s->user);
505         if (r < 0)
506                 return r;
507
508         /* Create cgroup */
509         r = session_start_scope(s);
510         if (r < 0)
511                 return r;
512
513         log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
514                    MESSAGE_ID(SD_MESSAGE_SESSION_START),
515                    "SESSION_ID=%s", s->id,
516                    "USER_ID=%s", s->user->name,
517                    "LEADER=%lu", (unsigned long) s->leader,
518                    "MESSAGE=New session %s of user %s.", s->id, s->user->name,
519                    NULL);
520
521         /* Create X11 symlink */
522         session_link_x11_socket(s);
523
524         if (!dual_timestamp_is_set(&s->timestamp))
525                 dual_timestamp_get(&s->timestamp);
526
527         if (s->seat)
528                 seat_read_active_vt(s->seat);
529
530         s->started = true;
531
532         /* Save session data */
533         session_save(s);
534         user_save(s->user);
535
536         session_send_signal(s, true);
537
538         if (s->seat) {
539                 seat_save(s->seat);
540
541                 if (s->seat->active == s)
542                         seat_send_changed(s->seat, "Sessions\0ActiveSession\0");
543                 else
544                         seat_send_changed(s->seat, "Sessions\0");
545         }
546
547         user_send_changed(s->user, "Sessions\0");
548
549         return 0;
550 }
551
552 static int session_stop_scope(Session *s) {
553         DBusError error;
554         char *job;
555         int r;
556
557         assert(s);
558
559         dbus_error_init(&error);
560
561         if (!s->scope)
562                 return 0;
563
564         r = manager_stop_unit(s->manager, s->scope, &error, &job);
565         if (r < 0) {
566                 log_error("Failed to stop session scope: %s", bus_error(&error, r));
567                 dbus_error_free(&error);
568                 return r;
569         }
570
571         free(s->scope_job);
572         s->scope_job = job;
573
574         return 0;
575 }
576
577 static int session_unlink_x11_socket(Session *s) {
578         _cleanup_free_ char *t = NULL;
579         int r;
580
581         assert(s);
582         assert(s->user);
583
584         if (s->user->display != s)
585                 return 0;
586
587         s->user->display = NULL;
588
589         t = strappend(s->user->runtime_path, "/X11-display");
590         if (!t)
591                 return log_oom();
592
593         r = unlink(t);
594         return r < 0 ? -errno : 0;
595 }
596
597 int session_stop(Session *s) {
598         int r;
599
600         assert(s);
601
602         if (!s->user)
603                 return -ESTALE;
604
605         /* Kill cgroup */
606         r = session_stop_scope(s);
607
608         session_save(s);
609
610         return r;
611 }
612
613 int session_finalize(Session *s) {
614         int r = 0;
615
616         assert(s);
617
618         if (!s->user)
619                 return -ESTALE;
620
621         if (s->started)
622                 log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
623                            MESSAGE_ID(SD_MESSAGE_SESSION_STOP),
624                            "SESSION_ID=%s", s->id,
625                            "USER_ID=%s", s->user->name,
626                            "LEADER=%lu", (unsigned long) s->leader,
627                            "MESSAGE=Removed session %s.", s->id,
628                            NULL);
629
630         /* Remove X11 symlink */
631         session_unlink_x11_socket(s);
632
633         unlink(s->state_file);
634         session_add_to_gc_queue(s);
635         user_add_to_gc_queue(s->user);
636
637         if (s->started) {
638                 session_send_signal(s, false);
639                 s->started = false;
640         }
641
642         if (s->seat) {
643                 if (s->seat->active == s)
644                         seat_set_active(s->seat, NULL);
645
646                 seat_send_changed(s->seat, "Sessions\0");
647                 seat_save(s->seat);
648         }
649
650         user_send_changed(s->user, "Sessions\0");
651         user_save(s->user);
652
653         return r;
654 }
655
656 bool session_is_active(Session *s) {
657         assert(s);
658
659         if (!s->seat)
660                 return true;
661
662         return s->seat->active == s;
663 }
664
665 static int get_tty_atime(const char *tty, usec_t *atime) {
666         _cleanup_free_ char *p = NULL;
667         struct stat st;
668
669         assert(tty);
670         assert(atime);
671
672         if (!path_is_absolute(tty)) {
673                 p = strappend("/dev/", tty);
674                 if (!p)
675                         return -ENOMEM;
676
677                 tty = p;
678         } else if (!path_startswith(tty, "/dev/"))
679                 return -ENOENT;
680
681         if (lstat(tty, &st) < 0)
682                 return -errno;
683
684         *atime = timespec_load(&st.st_atim);
685         return 0;
686 }
687
688 static int get_process_ctty_atime(pid_t pid, usec_t *atime) {
689         _cleanup_free_ char *p = NULL;
690         int r;
691
692         assert(pid > 0);
693         assert(atime);
694
695         r = get_ctty(pid, NULL, &p);
696         if (r < 0)
697                 return r;
698
699         return get_tty_atime(p, atime);
700 }
701
702 int session_get_idle_hint(Session *s, dual_timestamp *t) {
703         usec_t atime = 0, n;
704         int r;
705
706         assert(s);
707
708         /* Explicit idle hint is set */
709         if (s->idle_hint) {
710                 if (t)
711                         *t = s->idle_hint_timestamp;
712
713                 return s->idle_hint;
714         }
715
716         /* Graphical sessions should really implement a real
717          * idle hint logic */
718         if (s->display)
719                 goto dont_know;
720
721         /* For sessions with an explicitly configured tty, let's check
722          * its atime */
723         if (s->tty) {
724                 r = get_tty_atime(s->tty, &atime);
725                 if (r >= 0)
726                         goto found_atime;
727         }
728
729         /* For sessions with a leader but no explicitly configured
730          * tty, let's check the controlling tty of the leader */
731         if (s->leader > 0) {
732                 r = get_process_ctty_atime(s->leader, &atime);
733                 if (r >= 0)
734                         goto found_atime;
735         }
736
737 dont_know:
738         if (t)
739                 *t = s->idle_hint_timestamp;
740
741         return 0;
742
743 found_atime:
744         if (t)
745                 dual_timestamp_from_realtime(t, atime);
746
747         n = now(CLOCK_REALTIME);
748
749         if (s->manager->idle_action_usec <= 0)
750                 return 0;
751
752         return atime + s->manager->idle_action_usec <= n;
753 }
754
755 void session_set_idle_hint(Session *s, bool b) {
756         assert(s);
757
758         if (s->idle_hint == b)
759                 return;
760
761         s->idle_hint = b;
762         dual_timestamp_get(&s->idle_hint_timestamp);
763
764         session_send_changed(s,
765                              "IdleHint\0"
766                              "IdleSinceHint\0"
767                              "IdleSinceHintMonotonic\0");
768
769         if (s->seat)
770                 seat_send_changed(s->seat,
771                                   "IdleHint\0"
772                                   "IdleSinceHint\0"
773                                   "IdleSinceHintMonotonic\0");
774
775         user_send_changed(s->user,
776                           "IdleHint\0"
777                           "IdleSinceHint\0"
778                           "IdleSinceHintMonotonic\0");
779
780         manager_send_changed(s->manager,
781                              "IdleHint\0"
782                              "IdleSinceHint\0"
783                              "IdleSinceHintMonotonic\0");
784 }
785
786 int session_create_fifo(Session *s) {
787         int r;
788
789         assert(s);
790
791         /* Create FIFO */
792         if (!s->fifo_path) {
793                 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
794                 if (r < 0)
795                         return r;
796
797                 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
798                         return -ENOMEM;
799
800                 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
801                         return -errno;
802         }
803
804         /* Open reading side */
805         if (s->fifo_fd < 0) {
806                 struct epoll_event ev = {};
807
808                 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
809                 if (s->fifo_fd < 0)
810                         return -errno;
811
812                 r = hashmap_put(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1), s);
813                 if (r < 0)
814                         return r;
815
816                 ev.events = 0;
817                 ev.data.u32 = FD_OTHER_BASE + s->fifo_fd;
818
819                 if (epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_ADD, s->fifo_fd, &ev) < 0)
820                         return -errno;
821         }
822
823         /* Open writing side */
824         r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
825         if (r < 0)
826                 return -errno;
827
828         return r;
829 }
830
831 void session_remove_fifo(Session *s) {
832         assert(s);
833
834         if (s->fifo_fd >= 0) {
835                 assert_se(hashmap_remove(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1)) == s);
836                 assert_se(epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_DEL, s->fifo_fd, NULL) == 0);
837                 close_nointr_nofail(s->fifo_fd);
838                 s->fifo_fd = -1;
839
840                 session_save(s);
841                 user_save(s->user);
842         }
843
844         if (s->fifo_path) {
845                 unlink(s->fifo_path);
846                 free(s->fifo_path);
847                 s->fifo_path = NULL;
848         }
849 }
850
851 int session_check_gc(Session *s, bool drop_not_started) {
852         int r;
853
854         assert(s);
855
856         if (drop_not_started && !s->started)
857                 return 0;
858
859         if (!s->user)
860                 return 0;
861
862         if (s->fifo_fd >= 0) {
863                 r = pipe_eof(s->fifo_fd);
864                 if (r < 0)
865                         return r;
866
867                 if (r == 0)
868                         return 1;
869         }
870
871         if (s->scope_job)
872                 return 1;
873
874         if (s->scope)
875                 return manager_unit_is_active(s->manager, s->scope) != 0;
876
877         return 0;
878 }
879
880 void session_add_to_gc_queue(Session *s) {
881         assert(s);
882
883         if (s->in_gc_queue)
884                 return;
885
886         LIST_PREPEND(Session, gc_queue, s->manager->session_gc_queue, s);
887         s->in_gc_queue = true;
888 }
889
890 SessionState session_get_state(Session *s) {
891         assert(s);
892
893         if (s->closing)
894                 return SESSION_CLOSING;
895
896         if (s->scope_job)
897                 return SESSION_OPENING;
898
899         if (s->fifo_fd < 0)
900                 return SESSION_CLOSING;
901
902         if (session_is_active(s))
903                 return SESSION_ACTIVE;
904
905         return SESSION_ONLINE;
906 }
907
908 int session_kill(Session *s, KillWho who, int signo) {
909         assert(s);
910
911         if (!s->scope)
912                 return -ESRCH;
913
914         return manager_kill_unit(s->manager, s->scope, who, signo, NULL);
915 }
916
917 bool session_is_controller(Session *s, const char *sender)
918 {
919         assert(s);
920
921         return streq_ptr(s->controller, sender);
922 }
923
924 int session_set_controller(Session *s, const char *sender, bool force) {
925         char *t;
926         int r;
927
928         assert(s);
929         assert(sender);
930
931         if (session_is_controller(s, sender))
932                 return 0;
933         if (s->controller && !force)
934                 return -EBUSY;
935
936         t = strdup(sender);
937         if (!t)
938                 return -ENOMEM;
939
940         r = manager_watch_busname(s->manager, sender);
941         if (r) {
942                 free(t);
943                 return r;
944         }
945
946         session_drop_controller(s);
947
948         s->controller = t;
949         return 0;
950 }
951
952 void session_drop_controller(Session *s) {
953         assert(s);
954
955         if (!s->controller)
956                 return;
957
958         manager_drop_busname(s->manager, s->controller);
959         free(s->controller);
960         s->controller = NULL;
961 }
962
963 static const char* const session_state_table[_SESSION_STATE_MAX] = {
964         [SESSION_OPENING] = "opening",
965         [SESSION_ONLINE] = "online",
966         [SESSION_ACTIVE] = "active",
967         [SESSION_CLOSING] = "closing"
968 };
969
970 DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
971
972 static const char* const session_type_table[_SESSION_TYPE_MAX] = {
973         [SESSION_TTY] = "tty",
974         [SESSION_X11] = "x11",
975         [SESSION_UNSPECIFIED] = "unspecified"
976 };
977
978 DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
979
980 static const char* const session_class_table[_SESSION_CLASS_MAX] = {
981         [SESSION_USER] = "user",
982         [SESSION_GREETER] = "greeter",
983         [SESSION_LOCK_SCREEN] = "lock-screen",
984         [SESSION_BACKGROUND] = "background"
985 };
986
987 DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
988
989 static const char* const kill_who_table[_KILL_WHO_MAX] = {
990         [KILL_LEADER] = "leader",
991         [KILL_ALL] = "all"
992 };
993
994 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);