chiark / gitweb /
logind: ignore failing close() on session-devices
[elogind.git] / src / login / logind-session.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2011 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <errno.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <fcntl.h>
26
27 #include "sd-id128.h"
28 #include "sd-messages.h"
29 #include "strv.h"
30 #include "util.h"
31 #include "mkdir.h"
32 #include "path-util.h"
33 #include "fileio.h"
34 #include "audit.h"
35 #include "bus-util.h"
36 #include "bus-error.h"
37 #include "logind-session.h"
38
39 static unsigned devt_hash_func(const void *p) {
40         uint64_t u = *(const dev_t*)p;
41
42         return uint64_hash_func(&u);
43 }
44
45 static int devt_compare_func(const void *_a, const void *_b) {
46         dev_t a, b;
47
48         a = *(const dev_t*) _a;
49         b = *(const dev_t*) _b;
50
51         return a < b ? -1 : (a > b ? 1 : 0);
52 }
53
54 Session* session_new(Manager *m, const char *id) {
55         Session *s;
56
57         assert(m);
58         assert(id);
59         assert(session_id_valid(id));
60
61         s = new0(Session, 1);
62         if (!s)
63                 return NULL;
64
65         s->state_file = strappend("/run/systemd/sessions/", id);
66         if (!s->state_file) {
67                 free(s);
68                 return NULL;
69         }
70
71         s->devices = hashmap_new(devt_hash_func, devt_compare_func);
72         if (!s->devices) {
73                 free(s->state_file);
74                 free(s);
75                 return NULL;
76         }
77
78         s->id = path_get_file_name(s->state_file);
79
80         if (hashmap_put(m->sessions, s->id, s) < 0) {
81                 hashmap_free(s->devices);
82                 free(s->state_file);
83                 free(s);
84                 return NULL;
85         }
86
87         s->manager = m;
88         s->fifo_fd = -1;
89
90         return s;
91 }
92
93 void session_free(Session *s) {
94         SessionDevice *sd;
95
96         assert(s);
97
98         if (s->in_gc_queue)
99                 LIST_REMOVE(gc_queue, s->manager->session_gc_queue, s);
100
101         session_remove_fifo(s);
102
103         session_drop_controller(s);
104
105         while ((sd = hashmap_first(s->devices)))
106                 session_device_free(sd);
107
108         hashmap_free(s->devices);
109
110         if (s->user) {
111                 LIST_REMOVE(sessions_by_user, s->user->sessions, s);
112
113                 if (s->user->display == s)
114                         s->user->display = NULL;
115         }
116
117         if (s->seat) {
118                 if (s->seat->active == s)
119                         s->seat->active = NULL;
120                 if (s->seat->pending_switch == s)
121                         s->seat->pending_switch = NULL;
122
123                 LIST_REMOVE(sessions_by_seat, s->seat->sessions, s);
124         }
125
126         if (s->scope) {
127                 hashmap_remove(s->manager->session_units, s->scope);
128                 free(s->scope);
129         }
130
131         free(s->scope_job);
132
133         sd_bus_message_unref(s->create_message);
134
135         free(s->tty);
136         free(s->display);
137         free(s->remote_host);
138         free(s->remote_user);
139         free(s->service);
140
141         hashmap_remove(s->manager->sessions, s->id);
142
143         free(s->state_file);
144         free(s);
145 }
146
147 void session_set_user(Session *s, User *u) {
148         assert(s);
149         assert(!s->user);
150
151         s->user = u;
152         LIST_PREPEND(sessions_by_user, u->sessions, s);
153 }
154
155 int session_save(Session *s) {
156         _cleanup_free_ char *temp_path = NULL;
157         _cleanup_fclose_ FILE *f = NULL;
158         int r = 0;
159
160         assert(s);
161
162         if (!s->user)
163                 return -ESTALE;
164
165         if (!s->started)
166                 return 0;
167
168         r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
169         if (r < 0)
170                 goto finish;
171
172         r = fopen_temporary(s->state_file, &f, &temp_path);
173         if (r < 0)
174                 goto finish;
175
176         assert(s->user);
177
178         fchmod(fileno(f), 0644);
179
180         fprintf(f,
181                 "# This is private data. Do not parse.\n"
182                 "UID=%lu\n"
183                 "USER=%s\n"
184                 "ACTIVE=%i\n"
185                 "STATE=%s\n"
186                 "REMOTE=%i\n",
187                 (unsigned long) s->user->uid,
188                 s->user->name,
189                 session_is_active(s),
190                 session_state_to_string(session_get_state(s)),
191                 s->remote);
192
193         if (s->type >= 0)
194                 fprintf(f, "TYPE=%s\n", session_type_to_string(s->type));
195
196         if (s->class >= 0)
197                 fprintf(f, "CLASS=%s\n", session_class_to_string(s->class));
198
199         if (s->scope)
200                 fprintf(f, "SCOPE=%s\n", s->scope);
201
202         if (s->scope_job)
203                 fprintf(f, "SCOPE_JOB=%s\n", s->scope_job);
204
205         if (s->fifo_path)
206                 fprintf(f, "FIFO=%s\n", s->fifo_path);
207
208         if (s->seat)
209                 fprintf(f, "SEAT=%s\n", s->seat->id);
210
211         if (s->tty)
212                 fprintf(f, "TTY=%s\n", s->tty);
213
214         if (s->display)
215                 fprintf(f, "DISPLAY=%s\n", s->display);
216
217         if (s->remote_host)
218                 fprintf(f, "REMOTE_HOST=%s\n", s->remote_host);
219
220         if (s->remote_user)
221                 fprintf(f, "REMOTE_USER=%s\n", s->remote_user);
222
223         if (s->service)
224                 fprintf(f, "SERVICE=%s\n", s->service);
225
226         if (s->seat && seat_has_vts(s->seat))
227                 fprintf(f, "VTNR=%i\n", s->vtnr);
228
229         if (s->leader > 0)
230                 fprintf(f, "LEADER=%lu\n", (unsigned long) s->leader);
231
232         if (s->audit_id > 0)
233                 fprintf(f, "AUDIT=%"PRIu32"\n", s->audit_id);
234
235         if (dual_timestamp_is_set(&s->timestamp))
236                 fprintf(f,
237                         "REALTIME=%llu\n"
238                         "MONOTONIC=%llu\n",
239                         (unsigned long long) s->timestamp.realtime,
240                         (unsigned long long) s->timestamp.monotonic);
241
242         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         int r;
498
499         assert(s);
500         assert(s->user);
501         assert(s->user->slice);
502
503         if (!s->scope) {
504                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
505                 _cleanup_free_ char *description = NULL;
506                 const char *kill_mode;
507                 char *scope, *job;
508
509                 description = strjoin("Session ", s->id, " of user ", s->user->name, NULL);
510                 if (!description)
511                         return log_oom();
512
513                 scope = strjoin("session-", s->id, ".scope", NULL);
514                 if (!scope)
515                         return log_oom();
516
517                 kill_mode = manager_shall_kill(s->manager, s->user->name) ? "control-group" : "none";
518
519                 r = manager_start_scope(s->manager, scope, s->leader, s->user->slice, description, "systemd-user-sessions.service", kill_mode, &error, &job);
520                 if (r < 0) {
521                         log_error("Failed to start session scope %s: %s %s",
522                                   scope, bus_error_message(&error, r), error.name);
523                         free(scope);
524                         return r;
525                 } else {
526                         s->scope = scope;
527
528                         free(s->scope_job);
529                         s->scope_job = job;
530                 }
531         }
532
533         if (s->scope)
534                 hashmap_put(s->manager->session_units, s->scope, s);
535
536         return 0;
537 }
538
539 int session_start(Session *s) {
540         int r;
541
542         assert(s);
543
544         if (!s->user)
545                 return -ESTALE;
546
547         if (s->started)
548                 return 0;
549
550         r = user_start(s->user);
551         if (r < 0)
552                 return r;
553
554         /* Create cgroup */
555         r = session_start_scope(s);
556         if (r < 0)
557                 return r;
558
559         log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
560                    MESSAGE_ID(SD_MESSAGE_SESSION_START),
561                    "SESSION_ID=%s", s->id,
562                    "USER_ID=%s", s->user->name,
563                    "LEADER=%lu", (unsigned long) s->leader,
564                    "MESSAGE=New session %s of user %s.", s->id, s->user->name,
565                    NULL);
566
567         /* Create X11 symlink */
568         session_link_x11_socket(s);
569
570         if (!dual_timestamp_is_set(&s->timestamp))
571                 dual_timestamp_get(&s->timestamp);
572
573         if (s->seat)
574                 seat_read_active_vt(s->seat);
575
576         s->started = true;
577
578         /* Save session data */
579         session_save(s);
580         user_save(s->user);
581
582         session_send_signal(s, true);
583
584         if (s->seat) {
585                 seat_save(s->seat);
586
587                 if (s->seat->active == s)
588                         seat_send_changed(s->seat, "Sessions", "ActiveSession", NULL);
589                 else
590                         seat_send_changed(s->seat, "Sessions", NULL);
591         }
592
593         user_send_changed(s->user, "Sessions", NULL);
594
595         return 0;
596 }
597
598 static int session_stop_scope(Session *s) {
599         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
600         char *job;
601         int r;
602
603         assert(s);
604
605         if (!s->scope)
606                 return 0;
607
608         r = manager_stop_unit(s->manager, s->scope, &error, &job);
609         if (r < 0) {
610                 log_error("Failed to stop session scope: %s", bus_error_message(&error, r));
611                 return r;
612         }
613
614         free(s->scope_job);
615         s->scope_job = job;
616
617         return 0;
618 }
619
620 static int session_unlink_x11_socket(Session *s) {
621         _cleanup_free_ char *t = NULL;
622         int r;
623
624         assert(s);
625         assert(s->user);
626
627         if (s->user->display != s)
628                 return 0;
629
630         s->user->display = NULL;
631
632         t = strappend(s->user->runtime_path, "/X11-display");
633         if (!t)
634                 return log_oom();
635
636         r = unlink(t);
637         return r < 0 ? -errno : 0;
638 }
639
640 int session_stop(Session *s) {
641         int r;
642
643         assert(s);
644
645         if (!s->user)
646                 return -ESTALE;
647
648         /* Kill cgroup */
649         r = session_stop_scope(s);
650
651         session_save(s);
652         user_save(s->user);
653
654         return r;
655 }
656
657 int session_finalize(Session *s) {
658         int r = 0;
659         SessionDevice *sd;
660
661         assert(s);
662
663         if (!s->user)
664                 return -ESTALE;
665
666         if (s->started)
667                 log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
668                            MESSAGE_ID(SD_MESSAGE_SESSION_STOP),
669                            "SESSION_ID=%s", s->id,
670                            "USER_ID=%s", s->user->name,
671                            "LEADER=%lu", (unsigned long) s->leader,
672                            "MESSAGE=Removed session %s.", s->id,
673                            NULL);
674
675         /* Kill session devices */
676         while ((sd = hashmap_first(s->devices)))
677                 session_device_free(sd);
678
679         /* Remove X11 symlink */
680         session_unlink_x11_socket(s);
681
682         unlink(s->state_file);
683         session_add_to_gc_queue(s);
684         user_add_to_gc_queue(s->user);
685
686         if (s->started) {
687                 session_send_signal(s, false);
688                 s->started = false;
689         }
690
691         if (s->seat) {
692                 if (s->seat->active == s)
693                         seat_set_active(s->seat, NULL);
694
695                 seat_send_changed(s->seat, "Sessions", NULL);
696                 seat_save(s->seat);
697         }
698
699         user_send_changed(s->user, "Sessions", NULL);
700         user_save(s->user);
701
702         return r;
703 }
704
705 bool session_is_active(Session *s) {
706         assert(s);
707
708         if (!s->seat)
709                 return true;
710
711         return s->seat->active == s;
712 }
713
714 static int get_tty_atime(const char *tty, usec_t *atime) {
715         _cleanup_free_ char *p = NULL;
716         struct stat st;
717
718         assert(tty);
719         assert(atime);
720
721         if (!path_is_absolute(tty)) {
722                 p = strappend("/dev/", tty);
723                 if (!p)
724                         return -ENOMEM;
725
726                 tty = p;
727         } else if (!path_startswith(tty, "/dev/"))
728                 return -ENOENT;
729
730         if (lstat(tty, &st) < 0)
731                 return -errno;
732
733         *atime = timespec_load(&st.st_atim);
734         return 0;
735 }
736
737 static int get_process_ctty_atime(pid_t pid, usec_t *atime) {
738         _cleanup_free_ char *p = NULL;
739         int r;
740
741         assert(pid > 0);
742         assert(atime);
743
744         r = get_ctty(pid, NULL, &p);
745         if (r < 0)
746                 return r;
747
748         return get_tty_atime(p, atime);
749 }
750
751 int session_get_idle_hint(Session *s, dual_timestamp *t) {
752         usec_t atime = 0, n;
753         int r;
754
755         assert(s);
756
757         /* Explicit idle hint is set */
758         if (s->idle_hint) {
759                 if (t)
760                         *t = s->idle_hint_timestamp;
761
762                 return s->idle_hint;
763         }
764
765         /* Graphical sessions should really implement a real
766          * idle hint logic */
767         if (s->display)
768                 goto dont_know;
769
770         /* For sessions with an explicitly configured tty, let's check
771          * its atime */
772         if (s->tty) {
773                 r = get_tty_atime(s->tty, &atime);
774                 if (r >= 0)
775                         goto found_atime;
776         }
777
778         /* For sessions with a leader but no explicitly configured
779          * tty, let's check the controlling tty of the leader */
780         if (s->leader > 0) {
781                 r = get_process_ctty_atime(s->leader, &atime);
782                 if (r >= 0)
783                         goto found_atime;
784         }
785
786 dont_know:
787         if (t)
788                 *t = s->idle_hint_timestamp;
789
790         return 0;
791
792 found_atime:
793         if (t)
794                 dual_timestamp_from_realtime(t, atime);
795
796         n = now(CLOCK_REALTIME);
797
798         if (s->manager->idle_action_usec <= 0)
799                 return 0;
800
801         return atime + s->manager->idle_action_usec <= n;
802 }
803
804 void session_set_idle_hint(Session *s, bool b) {
805         assert(s);
806
807         if (s->idle_hint == b)
808                 return;
809
810         s->idle_hint = b;
811         dual_timestamp_get(&s->idle_hint_timestamp);
812
813         session_send_changed(s, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
814
815         if (s->seat)
816                 seat_send_changed(s->seat, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
817
818         user_send_changed(s->user, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
819         manager_send_changed(s->manager, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
820 }
821
822 static int session_dispatch_fifo(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
823         Session *s = userdata;
824
825         assert(s);
826         assert(s->fifo_fd == fd);
827
828         /* EOF on the FIFO means the session died abnormally. */
829
830         session_remove_fifo(s);
831         session_stop(s);
832
833         return 1;
834 }
835
836 int session_create_fifo(Session *s) {
837         int r;
838
839         assert(s);
840
841         /* Create FIFO */
842         if (!s->fifo_path) {
843                 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
844                 if (r < 0)
845                         return r;
846
847                 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
848                         return -ENOMEM;
849
850                 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
851                         return -errno;
852         }
853
854         /* Open reading side */
855         if (s->fifo_fd < 0) {
856                 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
857                 if (s->fifo_fd < 0)
858                         return -errno;
859
860         }
861
862         if (!s->fifo_event_source) {
863                 r = sd_event_add_io(s->manager->event, s->fifo_fd, 0, session_dispatch_fifo, s, &s->fifo_event_source);
864                 if (r < 0)
865                         return r;
866
867                 r = sd_event_source_set_priority(s->fifo_event_source, SD_EVENT_PRIORITY_IDLE);
868                 if (r < 0)
869                         return r;
870         }
871
872         /* Open writing side */
873         r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
874         if (r < 0)
875                 return -errno;
876
877         return r;
878 }
879
880 void session_remove_fifo(Session *s) {
881         assert(s);
882
883         if (s->fifo_event_source)
884                 s->fifo_event_source = sd_event_source_unref(s->fifo_event_source);
885
886         if (s->fifo_fd >= 0) {
887                 close_nointr_nofail(s->fifo_fd);
888                 s->fifo_fd = -1;
889         }
890
891         if (s->fifo_path) {
892                 unlink(s->fifo_path);
893                 free(s->fifo_path);
894                 s->fifo_path = NULL;
895         }
896 }
897
898 bool session_check_gc(Session *s, bool drop_not_started) {
899         int r;
900
901         assert(s);
902
903         if (drop_not_started && !s->started)
904                 return false;
905
906         if (!s->user)
907                 return false;
908
909         if (s->fifo_fd >= 0) {
910                 r = pipe_eof(s->fifo_fd);
911                 if (r < 0)
912                         return true;
913
914                 if (r == 0)
915                         return true;
916         }
917
918         if (s->scope_job && manager_job_is_active(s->manager, s->scope_job))
919                 return true;
920
921         if (s->scope && manager_unit_is_active(s->manager, s->scope))
922                 return true;
923
924         return false;
925 }
926
927 void session_add_to_gc_queue(Session *s) {
928         assert(s);
929
930         if (s->in_gc_queue)
931                 return;
932
933         LIST_PREPEND(gc_queue, s->manager->session_gc_queue, s);
934         s->in_gc_queue = true;
935 }
936
937 SessionState session_get_state(Session *s) {
938         assert(s);
939
940         if (s->closing)
941                 return SESSION_CLOSING;
942
943         if (s->scope_job)
944                 return SESSION_OPENING;
945
946         if (s->fifo_fd < 0)
947                 return SESSION_CLOSING;
948
949         if (session_is_active(s))
950                 return SESSION_ACTIVE;
951
952         return SESSION_ONLINE;
953 }
954
955 int session_kill(Session *s, KillWho who, int signo) {
956         assert(s);
957
958         if (!s->scope)
959                 return -ESRCH;
960
961         return manager_kill_unit(s->manager, s->scope, who, signo, NULL);
962 }
963
964 bool session_is_controller(Session *s, const char *sender) {
965         assert(s);
966
967         return streq_ptr(s->controller, sender);
968 }
969
970 int session_set_controller(Session *s, const char *sender, bool force) {
971         char *t;
972         int r;
973
974         assert(s);
975         assert(sender);
976
977         if (session_is_controller(s, sender))
978                 return 0;
979         if (s->controller && !force)
980                 return -EBUSY;
981
982         t = strdup(sender);
983         if (!t)
984                 return -ENOMEM;
985
986         r = manager_watch_busname(s->manager, sender);
987         if (r) {
988                 free(t);
989                 return r;
990         }
991
992         session_drop_controller(s);
993
994         s->controller = t;
995         return 0;
996 }
997
998 void session_drop_controller(Session *s) {
999         SessionDevice *sd;
1000
1001         assert(s);
1002
1003         if (!s->controller)
1004                 return;
1005
1006         manager_drop_busname(s->manager, s->controller);
1007         free(s->controller);
1008         s->controller = NULL;
1009
1010         /* Drop all devices as they're now unused. Do that after the controller
1011          * is released to avoid sending out useles dbus signals. */
1012         while ((sd = hashmap_first(s->devices)))
1013                 session_device_free(sd);
1014 }
1015
1016 static const char* const session_state_table[_SESSION_STATE_MAX] = {
1017         [SESSION_OPENING] = "opening",
1018         [SESSION_ONLINE] = "online",
1019         [SESSION_ACTIVE] = "active",
1020         [SESSION_CLOSING] = "closing"
1021 };
1022
1023 DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
1024
1025 static const char* const session_type_table[_SESSION_TYPE_MAX] = {
1026         [SESSION_TTY] = "tty",
1027         [SESSION_X11] = "x11",
1028         [SESSION_UNSPECIFIED] = "unspecified"
1029 };
1030
1031 DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
1032
1033 static const char* const session_class_table[_SESSION_CLASS_MAX] = {
1034         [SESSION_USER] = "user",
1035         [SESSION_GREETER] = "greeter",
1036         [SESSION_LOCK_SCREEN] = "lock-screen",
1037         [SESSION_BACKGROUND] = "background"
1038 };
1039
1040 DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
1041
1042 static const char* const kill_who_table[_KILL_WHO_MAX] = {
1043         [KILL_LEADER] = "leader",
1044         [KILL_ALL] = "all"
1045 };
1046
1047 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);