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