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