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