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