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