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