]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/login/logind-session.c
core: failed scope units may not be restarted
[thirdparty/systemd.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);