]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/login/logind-session.c
logind: extract has_vts() from can_multi_session()
[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 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);