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