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