]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind-session.c
gudev: add missing (nullable) annotations on return values
[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>
90a18413
DH
23#include <fcntl.h>
24#include <linux/vt.h>
25#include <linux/kd.h>
26#include <signal.h>
20263082 27#include <string.h>
90a18413 28#include <sys/ioctl.h>
20263082
LP
29#include <unistd.h>
30
cc377381
LP
31#include "sd-id128.h"
32#include "sd-messages.h"
20263082
LP
33#include "strv.h"
34#include "util.h"
49e942b2 35#include "mkdir.h"
9eb977db 36#include "path-util.h"
a5c32cff 37#include "fileio.h"
cc377381
LP
38#include "audit.h"
39#include "bus-util.h"
40#include "bus-error.h"
fb6becb4 41#include "logind-session.h"
20263082 42
5f41d1f1
LP
43#define RELEASE_USEC (20*USEC_PER_SEC)
44
45static void session_remove_fifo(Session *s);
46
9bf3b535 47static unsigned long devt_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) {
831dedef
DH
48 uint64_t u = *(const dev_t*)p;
49
9bf3b535 50 return uint64_hash_func(&u, hash_key);
831dedef
DH
51}
52
53static int devt_compare_func(const void *_a, const void *_b) {
54 dev_t a, b;
55
56 a = *(const dev_t*) _a;
57 b = *(const dev_t*) _b;
58
59 return a < b ? -1 : (a > b ? 1 : 0);
60}
61
9444b1f2 62Session* session_new(Manager *m, const char *id) {
20263082
LP
63 Session *s;
64
65 assert(m);
66 assert(id);
4b549144 67 assert(session_id_valid(id));
20263082 68
14c3baca 69 s = new0(Session, 1);
20263082
LP
70 if (!s)
71 return NULL;
72
98a28fef 73 s->state_file = strappend("/run/systemd/sessions/", id);
20263082
LP
74 if (!s->state_file) {
75 free(s);
76 return NULL;
77 }
78
831dedef 79 s->devices = hashmap_new(devt_hash_func, devt_compare_func);
118ecf32
DH
80 if (!s->devices) {
81 free(s->state_file);
82 free(s);
83 return NULL;
84 }
85
2b6bf07d 86 s->id = basename(s->state_file);
20263082
LP
87
88 if (hashmap_put(m->sessions, s->id, s) < 0) {
118ecf32 89 hashmap_free(s->devices);
f8e2fb7b 90 free(s->state_file);
20263082
LP
91 free(s);
92 return NULL;
93 }
94
95 s->manager = m;
932e3ee7 96 s->fifo_fd = -1;
90a18413 97 s->vtfd = -1;
20263082
LP
98
99 return s;
100}
101
102void session_free(Session *s) {
118ecf32
DH
103 SessionDevice *sd;
104
20263082
LP
105 assert(s);
106
14c3baca 107 if (s->in_gc_queue)
71fda00f 108 LIST_REMOVE(gc_queue, s->manager->session_gc_queue, s);
14c3baca 109
5f41d1f1
LP
110 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
111
cc377381
LP
112 session_remove_fifo(s);
113
ae5e06bd
DH
114 session_drop_controller(s);
115
118ecf32
DH
116 while ((sd = hashmap_first(s->devices)))
117 session_device_free(sd);
118
119 hashmap_free(s->devices);
120
20263082 121 if (s->user) {
71fda00f 122 LIST_REMOVE(sessions_by_user, s->user->sessions, s);
20263082
LP
123
124 if (s->user->display == s)
125 s->user->display = NULL;
126 }
127
9418f147
LP
128 if (s->seat) {
129 if (s->seat->active == s)
130 s->seat->active = NULL;
d7bd01b5
DH
131 if (s->seat->pending_switch == s)
132 s->seat->pending_switch = NULL;
9418f147 133
49e6fdbf 134 seat_evict_position(s->seat, s);
71fda00f 135 LIST_REMOVE(sessions_by_seat, s->seat->sessions, s);
9418f147 136 }
20263082 137
fb6becb4
LP
138 if (s->scope) {
139 hashmap_remove(s->manager->session_units, s->scope);
140 free(s->scope);
141 }
142
143 free(s->scope_job);
1713813d 144
cc377381 145 sd_bus_message_unref(s->create_message);
20263082
LP
146
147 free(s->tty);
148 free(s->display);
149 free(s->remote_host);
3f49d45a 150 free(s->remote_user);
98a28fef 151 free(s->service);
a4cd87e9 152 free(s->desktop);
20263082
LP
153
154 hashmap_remove(s->manager->sessions, s->id);
98a28fef 155
5f41d1f1
LP
156 s->vt_source = sd_event_source_unref(s->vt_source);
157
d2f92cdf 158 free(s->state_file);
20263082
LP
159 free(s);
160}
161
9444b1f2
LP
162void session_set_user(Session *s, User *u) {
163 assert(s);
164 assert(!s->user);
165
166 s->user = u;
71fda00f 167 LIST_PREPEND(sessions_by_user, u->sessions, s);
9444b1f2
LP
168}
169
20263082 170int session_save(Session *s) {
507f22bd 171 _cleanup_free_ char *temp_path = NULL;
cc377381 172 _cleanup_fclose_ FILE *f = NULL;
20263082
LP
173 int r = 0;
174
175 assert(s);
176
9444b1f2
LP
177 if (!s->user)
178 return -ESTALE;
179
accaeded
LP
180 if (!s->started)
181 return 0;
182
d2e54fae 183 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
20263082 184 if (r < 0)
14c3baca 185 goto finish;
20263082 186
14c3baca
LP
187 r = fopen_temporary(s->state_file, &f, &temp_path);
188 if (r < 0)
189 goto finish;
20263082
LP
190
191 assert(s->user);
192
14c3baca
LP
193 fchmod(fileno(f), 0644);
194
20263082
LP
195 fprintf(f,
196 "# This is private data. Do not parse.\n"
90b2de37 197 "UID="UID_FMT"\n"
20263082
LP
198 "USER=%s\n"
199 "ACTIVE=%i\n"
0604381b 200 "STATE=%s\n"
fb6becb4 201 "REMOTE=%i\n",
90b2de37 202 s->user->uid,
20263082
LP
203 s->user->name,
204 session_is_active(s),
0604381b 205 session_state_to_string(session_get_state(s)),
fb6becb4 206 s->remote);
20263082 207
a91e4e53 208 if (s->type >= 0)
507f22bd 209 fprintf(f, "TYPE=%s\n", session_type_to_string(s->type));
a91e4e53 210
55efac6c 211 if (s->class >= 0)
507f22bd 212 fprintf(f, "CLASS=%s\n", session_class_to_string(s->class));
55efac6c 213
fb6becb4
LP
214 if (s->scope)
215 fprintf(f, "SCOPE=%s\n", s->scope);
216
217 if (s->scope_job)
218 fprintf(f, "SCOPE_JOB=%s\n", s->scope_job);
20263082 219
932e3ee7 220 if (s->fifo_path)
507f22bd 221 fprintf(f, "FIFO=%s\n", s->fifo_path);
932e3ee7 222
20263082 223 if (s->seat)
507f22bd 224 fprintf(f, "SEAT=%s\n", s->seat->id);
20263082
LP
225
226 if (s->tty)
507f22bd 227 fprintf(f, "TTY=%s\n", s->tty);
20263082
LP
228
229 if (s->display)
507f22bd 230 fprintf(f, "DISPLAY=%s\n", s->display);
20263082
LP
231
232 if (s->remote_host)
507f22bd 233 fprintf(f, "REMOTE_HOST=%s\n", s->remote_host);
20263082 234
3f49d45a 235 if (s->remote_user)
507f22bd 236 fprintf(f, "REMOTE_USER=%s\n", s->remote_user);
3f49d45a 237
98a28fef 238 if (s->service)
507f22bd 239 fprintf(f, "SERVICE=%s\n", s->service);
98a28fef 240
a4cd87e9
LP
241 if (s->desktop)
242 fprintf(f, "DESKTOP=%s\n", s->desktop);
243
bf7825ae 244 if (s->seat && seat_has_vts(s->seat))
92bd5ff3 245 fprintf(f, "VTNR=%u\n", s->vtnr);
20263082 246
49e6fdbf
DH
247 if (!s->vtnr)
248 fprintf(f, "POS=%u\n", s->pos);
249
20263082 250 if (s->leader > 0)
90b2de37 251 fprintf(f, "LEADER="PID_FMT"\n", s->leader);
20263082
LP
252
253 if (s->audit_id > 0)
507f22bd 254 fprintf(f, "AUDIT=%"PRIu32"\n", s->audit_id);
20263082 255
9444b1f2
LP
256 if (dual_timestamp_is_set(&s->timestamp))
257 fprintf(f,
90b2de37
ZJS
258 "REALTIME="USEC_FMT"\n"
259 "MONOTONIC="USEC_FMT"\n",
260 s->timestamp.realtime,
261 s->timestamp.monotonic);
9444b1f2 262
6d33772f
DH
263 if (s->controller)
264 fprintf(f, "CONTROLLER=%s\n", s->controller);
265
20263082 266 fflush(f);
14c3baca
LP
267
268 if (ferror(f) || rename(temp_path, s->state_file) < 0) {
20263082
LP
269 r = -errno;
270 unlink(s->state_file);
14c3baca 271 unlink(temp_path);
20263082
LP
272 }
273
14c3baca
LP
274finish:
275 if (r < 0)
90b2de37 276 log_error("Failed to save session data %s: %s", s->state_file, strerror(-r));
14c3baca 277
20263082
LP
278 return r;
279}
280
281int session_load(Session *s) {
9444b1f2 282 _cleanup_free_ char *remote = NULL,
a185c5aa
LP
283 *seat = NULL,
284 *vtnr = NULL,
49e6fdbf 285 *pos = NULL,
a185c5aa 286 *leader = NULL,
55efac6c 287 *type = NULL,
9444b1f2
LP
288 *class = NULL,
289 *uid = NULL,
290 *realtime = NULL,
6d33772f
DH
291 *monotonic = NULL,
292 *controller = NULL;
a185c5aa
LP
293
294 int k, r;
295
20263082
LP
296 assert(s);
297
a185c5aa
LP
298 r = parse_env_file(s->state_file, NEWLINE,
299 "REMOTE", &remote,
fb6becb4
LP
300 "SCOPE", &s->scope,
301 "SCOPE_JOB", &s->scope_job,
932e3ee7 302 "FIFO", &s->fifo_path,
a185c5aa
LP
303 "SEAT", &seat,
304 "TTY", &s->tty,
305 "DISPLAY", &s->display,
306 "REMOTE_HOST", &s->remote_host,
307 "REMOTE_USER", &s->remote_user,
98a28fef 308 "SERVICE", &s->service,
a4cd87e9 309 "DESKTOP", &s->desktop,
a185c5aa 310 "VTNR", &vtnr,
49e6fdbf 311 "POS", &pos,
a185c5aa 312 "LEADER", &leader,
a91e4e53 313 "TYPE", &type,
55efac6c 314 "CLASS", &class,
9444b1f2
LP
315 "UID", &uid,
316 "REALTIME", &realtime,
317 "MONOTONIC", &monotonic,
6d33772f 318 "CONTROLLER", &controller,
a185c5aa
LP
319 NULL);
320
9444b1f2
LP
321 if (r < 0) {
322 log_error("Failed to read %s: %s", s->state_file, strerror(-r));
323 return r;
324 }
325
326 if (!s->user) {
327 uid_t u;
328 User *user;
329
330 if (!uid) {
331 log_error("UID not specified for session %s", s->id);
332 return -ENOENT;
333 }
334
335 r = parse_uid(uid, &u);
336 if (r < 0) {
337 log_error("Failed to parse UID value %s for session %s.", uid, s->id);
338 return r;
339 }
340
341 user = hashmap_get(s->manager->users, ULONG_TO_PTR((unsigned long) u));
342 if (!user) {
343 log_error("User of session %s not known.", s->id);
344 return -ENOENT;
345 }
346
347 session_set_user(s, user);
348 }
a185c5aa
LP
349
350 if (remote) {
351 k = parse_boolean(remote);
352 if (k >= 0)
353 s->remote = k;
354 }
355
c506027a
DH
356 if (vtnr)
357 safe_atou(vtnr, &s->vtnr);
358
9418f147 359 if (seat && !s->seat) {
a185c5aa
LP
360 Seat *o;
361
362 o = hashmap_get(s->manager->seats, seat);
363 if (o)
c506027a
DH
364 r = seat_attach_session(o, s);
365 if (!o || r < 0)
366 log_error("Cannot attach session %s to seat %s", s->id, seat);
a185c5aa
LP
367 }
368
c506027a
DH
369 if (!s->seat || !seat_has_vts(s->seat))
370 s->vtnr = 0;
a185c5aa 371
49e6fdbf
DH
372 if (pos && s->seat) {
373 unsigned int npos;
374
375 safe_atou(pos, &npos);
376 seat_claim_position(s->seat, s, npos);
377 }
378
a185c5aa 379 if (leader) {
f8e2fb7b
LP
380 k = parse_pid(leader, &s->leader);
381 if (k >= 0)
382 audit_session_from_pid(s->leader, &s->audit_id);
a185c5aa
LP
383 }
384
a91e4e53
LP
385 if (type) {
386 SessionType t;
387
388 t = session_type_from_string(type);
389 if (t >= 0)
390 s->type = t;
391 }
392
55efac6c
LP
393 if (class) {
394 SessionClass c;
395
396 c = session_class_from_string(class);
397 if (c >= 0)
398 s->class = c;
399 }
400
b4f78aea
LP
401 if (s->fifo_path) {
402 int fd;
403
404 /* If we open an unopened pipe for reading we will not
405 get an EOF. to trigger an EOF we hence open it for
406 reading, but close it right-away which then will
407 trigger the EOF. */
408
409 fd = session_create_fifo(s);
03e334a1 410 safe_close(fd);
b4f78aea
LP
411 }
412
9444b1f2
LP
413 if (realtime) {
414 unsigned long long l;
415 if (sscanf(realtime, "%llu", &l) > 0)
416 s->timestamp.realtime = l;
417 }
418
419 if (monotonic) {
420 unsigned long long l;
421 if (sscanf(monotonic, "%llu", &l) > 0)
422 s->timestamp.monotonic = l;
423 }
a185c5aa 424
6d33772f
DH
425 if (controller) {
426 if (bus_name_has_owner(s->manager->bus, controller, NULL) > 0)
427 session_set_controller(s, controller, false);
90a18413
DH
428 else
429 session_restore_vt(s);
6d33772f
DH
430 }
431
a185c5aa 432 return r;
20263082
LP
433}
434
435int session_activate(Session *s) {
d7bd01b5
DH
436 unsigned int num_pending;
437
20263082 438 assert(s);
9444b1f2 439 assert(s->user);
20263082 440
20263082
LP
441 if (!s->seat)
442 return -ENOTSUP;
443
444 if (s->seat->active == s)
445 return 0;
446
d7bd01b5
DH
447 /* on seats with VTs, we let VTs manage session-switching */
448 if (seat_has_vts(s->seat)) {
92bd5ff3 449 if (!s->vtnr)
d7bd01b5
DH
450 return -ENOTSUP;
451
452 return chvt(s->vtnr);
453 }
454
455 /* On seats without VTs, we implement session-switching in logind. We
456 * try to pause all session-devices and wait until the session
457 * controller acknowledged them. Once all devices are asleep, we simply
458 * switch the active session and be done.
459 * We save the session we want to switch to in seat->pending_switch and
460 * seat_complete_switch() will perform the final switch. */
461
462 s->seat->pending_switch = s;
463
464 /* if no devices are running, immediately perform the session switch */
465 num_pending = session_device_try_pause_all(s);
466 if (!num_pending)
467 seat_complete_switch(s->seat);
20263082 468
d7bd01b5 469 return 0;
20263082
LP
470}
471
fb6becb4 472static int session_start_scope(Session *s) {
98a28fef
LP
473 int r;
474
475 assert(s);
9444b1f2 476 assert(s->user);
fb6becb4 477 assert(s->user->slice);
98a28fef 478
fb6becb4 479 if (!s->scope) {
cc377381 480 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
d0af76e6 481 _cleanup_free_ char *description = NULL;
39883f62 482 char *scope, *job = NULL;
d0af76e6 483
405e0255
LP
484 description = strjoin("Session ", s->id, " of user ", s->user->name, NULL);
485 if (!description)
486 return log_oom();
487
d0af76e6
LP
488 scope = strjoin("session-", s->id, ".scope", NULL);
489 if (!scope)
ae018d9b
LP
490 return log_oom();
491
646e392e 492 r = manager_start_scope(s->manager, scope, s->leader, s->user->slice, description, "systemd-logind.service", "systemd-user-sessions.service", &error, &job);
d0af76e6 493 if (r < 0) {
042f5988 494 log_error("Failed to start session scope %s: %s %s",
cc377381 495 scope, bus_error_message(&error, r), error.name);
d0af76e6 496 free(scope);
f2d4f98d 497 return r;
d0af76e6
LP
498 } else {
499 s->scope = scope;
500
501 free(s->scope_job);
502 s->scope_job = job;
503 }
20263082
LP
504 }
505
d0af76e6
LP
506 if (s->scope)
507 hashmap_put(s->manager->session_units, s->scope, s);
508
20263082
LP
509 return 0;
510}
511
512int session_start(Session *s) {
513 int r;
514
515 assert(s);
9444b1f2
LP
516
517 if (!s->user)
518 return -ESTALE;
20263082 519
9418f147
LP
520 if (s->started)
521 return 0;
522
ed18b08b
LP
523 r = user_start(s->user);
524 if (r < 0)
525 return r;
526
fb6becb4
LP
527 /* Create cgroup */
528 r = session_start_scope(s);
529 if (r < 0)
530 return r;
531
d9eb81f9 532 log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
1ca6783f 533 MESSAGE_ID(SD_MESSAGE_SESSION_START),
877d54e9
LP
534 "SESSION_ID=%s", s->id,
535 "USER_ID=%s", s->user->name,
de0671ee 536 "LEADER="PID_FMT, s->leader,
877d54e9
LP
537 "MESSAGE=New session %s of user %s.", s->id, s->user->name,
538 NULL);
98a28fef 539
9444b1f2
LP
540 if (!dual_timestamp_is_set(&s->timestamp))
541 dual_timestamp_get(&s->timestamp);
14c3baca 542
e9816c48
LP
543 if (s->seat)
544 seat_read_active_vt(s->seat);
545
9418f147
LP
546 s->started = true;
547
5f41d1f1 548 /* Save data */
e9816c48 549 session_save(s);
7f7bb946 550 user_save(s->user);
5f41d1f1
LP
551 if (s->seat)
552 seat_save(s->seat);
e9816c48 553
5f41d1f1 554 /* Send signals */
da119395 555 session_send_signal(s, true);
5f41d1f1 556 user_send_changed(s->user, "Sessions", NULL);
9418f147
LP
557 if (s->seat) {
558 if (s->seat->active == s)
cc377381 559 seat_send_changed(s->seat, "Sessions", "ActiveSession", NULL);
9418f147 560 else
cc377381 561 seat_send_changed(s->seat, "Sessions", NULL);
9418f147
LP
562 }
563
20263082
LP
564 return 0;
565}
566
9bb69af4 567static int session_stop_scope(Session *s, bool force) {
cc377381 568 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
39883f62 569 char *job = NULL;
20263082 570 int r;
20263082
LP
571
572 assert(s);
573
fb6becb4
LP
574 if (!s->scope)
575 return 0;
9b221b63 576
9bb69af4 577 if (force || manager_shall_kill(s->manager, s->user->name)) {
5f41d1f1
LP
578 r = manager_stop_unit(s->manager, s->scope, &error, &job);
579 if (r < 0) {
580 log_error("Failed to stop session scope: %s", bus_error_message(&error, r));
581 return r;
582 }
20263082 583
5f41d1f1
LP
584 free(s->scope_job);
585 s->scope_job = job;
586 } else {
587 r = manager_abandon_scope(s->manager, s->scope, &error);
588 if (r < 0) {
589 log_error("Failed to abandon session scope: %s", bus_error_message(&error, r));
590 return r;
591 }
592 }
20263082 593
9b221b63 594 return 0;
20263082
LP
595}
596
9bb69af4 597int session_stop(Session *s, bool force) {
405e0255
LP
598 int r;
599
600 assert(s);
601
602 if (!s->user)
603 return -ESTALE;
604
5f41d1f1
LP
605 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
606
607 /* We are going down, don't care about FIFOs anymore */
608 session_remove_fifo(s);
609
405e0255 610 /* Kill cgroup */
9bb69af4 611 r = session_stop_scope(s, force);
405e0255 612
5f41d1f1
LP
613 s->stopping = true;
614
405e0255 615 session_save(s);
cc377381 616 user_save(s->user);
405e0255
LP
617
618 return r;
619}
620
621int session_finalize(Session *s) {
622 int r = 0;
118ecf32 623 SessionDevice *sd;
20263082
LP
624
625 assert(s);
626
9444b1f2
LP
627 if (!s->user)
628 return -ESTALE;
629
ed18b08b 630 if (s->started)
d9eb81f9 631 log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
1ca6783f 632 MESSAGE_ID(SD_MESSAGE_SESSION_STOP),
877d54e9
LP
633 "SESSION_ID=%s", s->id,
634 "USER_ID=%s", s->user->name,
de0671ee 635 "LEADER="PID_FMT, s->leader,
877d54e9
LP
636 "MESSAGE=Removed session %s.", s->id,
637 NULL);
98a28fef 638
5f41d1f1
LP
639 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
640
118ecf32
DH
641 /* Kill session devices */
642 while ((sd = hashmap_first(s->devices)))
643 session_device_free(sd);
644
d2f92cdf
LP
645 unlink(s->state_file);
646 session_add_to_gc_queue(s);
ed18b08b 647 user_add_to_gc_queue(s->user);
14c3baca 648
405e0255 649 if (s->started) {
ed18b08b 650 session_send_signal(s, false);
405e0255
LP
651 s->started = false;
652 }
50fb9793 653
9418f147
LP
654 if (s->seat) {
655 if (s->seat->active == s)
656 seat_set_active(s->seat, NULL);
657
23bd3b62 658 seat_save(s->seat);
5f41d1f1 659 seat_send_changed(s->seat, "Sessions", NULL);
9418f147
LP
660 }
661
23bd3b62 662 user_save(s->user);
5f41d1f1 663 user_send_changed(s->user, "Sessions", NULL);
9418f147 664
20263082
LP
665 return r;
666}
667
5f41d1f1
LP
668static int release_timeout_callback(sd_event_source *es, uint64_t usec, void *userdata) {
669 Session *s = userdata;
670
671 assert(es);
672 assert(s);
673
9bb69af4 674 session_stop(s, false);
5f41d1f1
LP
675 return 0;
676}
677
678void session_release(Session *s) {
679 assert(s);
680
681 if (!s->started || s->stopping)
682 return;
683
684 if (!s->timer_event_source)
6a0f1f6d
LP
685 sd_event_add_time(s->manager->event,
686 &s->timer_event_source,
687 CLOCK_MONOTONIC,
688 now(CLOCK_MONOTONIC) + RELEASE_USEC, 0,
689 release_timeout_callback, s);
5f41d1f1
LP
690}
691
20263082
LP
692bool session_is_active(Session *s) {
693 assert(s);
694
695 if (!s->seat)
696 return true;
697
698 return s->seat->active == s;
699}
700
23406ce5
LP
701static int get_tty_atime(const char *tty, usec_t *atime) {
702 _cleanup_free_ char *p = NULL;
a185c5aa 703 struct stat st;
23406ce5
LP
704
705 assert(tty);
706 assert(atime);
707
708 if (!path_is_absolute(tty)) {
709 p = strappend("/dev/", tty);
710 if (!p)
711 return -ENOMEM;
712
713 tty = p;
714 } else if (!path_startswith(tty, "/dev/"))
715 return -ENOENT;
716
717 if (lstat(tty, &st) < 0)
718 return -errno;
719
720 *atime = timespec_load(&st.st_atim);
721 return 0;
722}
723
724static int get_process_ctty_atime(pid_t pid, usec_t *atime) {
725 _cleanup_free_ char *p = NULL;
726 int r;
727
728 assert(pid > 0);
729 assert(atime);
730
731 r = get_ctty(pid, NULL, &p);
732 if (r < 0)
733 return r;
734
735 return get_tty_atime(p, atime);
736}
737
738int session_get_idle_hint(Session *s, dual_timestamp *t) {
23406ce5
LP
739 usec_t atime = 0, n;
740 int r;
a185c5aa
LP
741
742 assert(s);
743
23406ce5 744 /* Explicit idle hint is set */
a185c5aa
LP
745 if (s->idle_hint) {
746 if (t)
747 *t = s->idle_hint_timestamp;
748
749 return s->idle_hint;
750 }
751
0762eaa3 752 /* Graphical sessions should really implement a real
23406ce5
LP
753 * idle hint logic */
754 if (s->display)
a185c5aa
LP
755 goto dont_know;
756
23406ce5
LP
757 /* For sessions with an explicitly configured tty, let's check
758 * its atime */
759 if (s->tty) {
760 r = get_tty_atime(s->tty, &atime);
761 if (r >= 0)
762 goto found_atime;
763 }
a185c5aa 764
23406ce5
LP
765 /* For sessions with a leader but no explicitly configured
766 * tty, let's check the controlling tty of the leader */
767 if (s->leader > 0) {
768 r = get_process_ctty_atime(s->leader, &atime);
769 if (r >= 0)
770 goto found_atime;
a185c5aa
LP
771 }
772
a185c5aa
LP
773dont_know:
774 if (t)
775 *t = s->idle_hint_timestamp;
776
777 return 0;
23406ce5
LP
778
779found_atime:
780 if (t)
781 dual_timestamp_from_realtime(t, atime);
782
783 n = now(CLOCK_REALTIME);
784
785 if (s->manager->idle_action_usec <= 0)
786 return 0;
787
788 return atime + s->manager->idle_action_usec <= n;
a185c5aa
LP
789}
790
bef422ae
LP
791void session_set_idle_hint(Session *s, bool b) {
792 assert(s);
793
794 if (s->idle_hint == b)
795 return;
796
797 s->idle_hint = b;
798 dual_timestamp_get(&s->idle_hint_timestamp);
9418f147 799
cc377381 800 session_send_changed(s, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
9418f147
LP
801
802 if (s->seat)
cc377381
LP
803 seat_send_changed(s->seat, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
804
805 user_send_changed(s->user, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
806 manager_send_changed(s->manager, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
807}
808
809static int session_dispatch_fifo(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
810 Session *s = userdata;
811
812 assert(s);
813 assert(s->fifo_fd == fd);
814
815 /* EOF on the FIFO means the session died abnormally. */
816
817 session_remove_fifo(s);
9bb69af4 818 session_stop(s, false);
cc377381
LP
819
820 return 1;
bef422ae
LP
821}
822
932e3ee7
LP
823int session_create_fifo(Session *s) {
824 int r;
825
31b79c2b
LP
826 assert(s);
827
b4f78aea 828 /* Create FIFO */
932e3ee7 829 if (!s->fifo_path) {
d2e54fae 830 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
e6061ab2
LP
831 if (r < 0)
832 return r;
833
932e3ee7
LP
834 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
835 return -ENOMEM;
31b79c2b 836
932e3ee7
LP
837 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
838 return -errno;
839 }
31b79c2b 840
932e3ee7 841 /* Open reading side */
b4f78aea 842 if (s->fifo_fd < 0) {
b4f78aea
LP
843 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
844 if (s->fifo_fd < 0)
845 return -errno;
846
cc377381
LP
847 }
848
849 if (!s->fifo_event_source) {
151b9b96 850 r = sd_event_add_io(s->manager->event, &s->fifo_event_source, s->fifo_fd, 0, session_dispatch_fifo, s);
b4f78aea
LP
851 if (r < 0)
852 return r;
853
718db961 854 r = sd_event_source_set_priority(s->fifo_event_source, SD_EVENT_PRIORITY_IDLE);
cc377381
LP
855 if (r < 0)
856 return r;
b4f78aea 857 }
932e3ee7
LP
858
859 /* Open writing side */
860 r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
861 if (r < 0)
862 return -errno;
31b79c2b 863
932e3ee7
LP
864 return r;
865}
866
5f41d1f1 867static void session_remove_fifo(Session *s) {
932e3ee7
LP
868 assert(s);
869
03e334a1
LP
870 s->fifo_event_source = sd_event_source_unref(s->fifo_event_source);
871 s->fifo_fd = safe_close(s->fifo_fd);
932e3ee7
LP
872
873 if (s->fifo_path) {
874 unlink(s->fifo_path);
875 free(s->fifo_path);
876 s->fifo_path = NULL;
877 }
31b79c2b
LP
878}
879
cc377381 880bool session_check_gc(Session *s, bool drop_not_started) {
20263082
LP
881 assert(s);
882
4a4b033f 883 if (drop_not_started && !s->started)
cc377381 884 return false;
932e3ee7 885
9444b1f2 886 if (!s->user)
cc377381 887 return false;
9444b1f2 888
932e3ee7 889 if (s->fifo_fd >= 0) {
5f41d1f1 890 if (pipe_eof(s->fifo_fd) <= 0)
cc377381 891 return true;
20263082
LP
892 }
893
cc377381
LP
894 if (s->scope_job && manager_job_is_active(s->manager, s->scope_job))
895 return true;
20263082 896
cc377381
LP
897 if (s->scope && manager_unit_is_active(s->manager, s->scope))
898 return true;
20263082 899
cc377381 900 return false;
20263082
LP
901}
902
14c3baca
LP
903void session_add_to_gc_queue(Session *s) {
904 assert(s);
905
906 if (s->in_gc_queue)
907 return;
908
71fda00f 909 LIST_PREPEND(gc_queue, s->manager->session_gc_queue, s);
14c3baca
LP
910 s->in_gc_queue = true;
911}
912
0604381b
LP
913SessionState session_get_state(Session *s) {
914 assert(s);
915
8fe63cd4 916 /* always check closing first */
5f41d1f1
LP
917 if (s->stopping || s->timer_event_source)
918 return SESSION_CLOSING;
919
8fe63cd4 920 if (s->scope_job || s->fifo_fd < 0)
405e0255 921 return SESSION_OPENING;
fb6becb4 922
0604381b
LP
923 if (session_is_active(s))
924 return SESSION_ACTIVE;
925
926 return SESSION_ONLINE;
927}
928
de07ab16 929int session_kill(Session *s, KillWho who, int signo) {
de07ab16
LP
930 assert(s);
931
fb6becb4 932 if (!s->scope)
de07ab16
LP
933 return -ESRCH;
934
fb6becb4 935 return manager_kill_unit(s->manager, s->scope, who, signo, NULL);
de07ab16
LP
936}
937
90a18413 938static int session_open_vt(Session *s) {
5f41d1f1 939 char path[sizeof("/dev/tty") + DECIMAL_STR_MAX(s->vtnr)];
90a18413 940
92bd5ff3 941 if (!s->vtnr)
90a18413
DH
942 return -1;
943
944 if (s->vtfd >= 0)
945 return s->vtfd;
946
92bd5ff3 947 sprintf(path, "/dev/tty%u", s->vtnr);
90a18413
DH
948 s->vtfd = open(path, O_RDWR | O_CLOEXEC | O_NONBLOCK | O_NOCTTY);
949 if (s->vtfd < 0) {
950 log_error("cannot open VT %s of session %s: %m", path, s->id);
03e334a1 951 return -errno;
90a18413
DH
952 }
953
954 return s->vtfd;
955}
956
957static int session_vt_fn(sd_event_source *source, const struct signalfd_siginfo *si, void *data) {
958 Session *s = data;
959
960 if (s->vtfd >= 0)
961 ioctl(s->vtfd, VT_RELDISP, 1);
962
963 return 0;
964}
965
8b8fa8b8 966void session_prepare_vt(Session *s) {
90a18413
DH
967 int vt, r;
968 struct vt_mode mode = { 0 };
969 sigset_t mask;
970
971 vt = session_open_vt(s);
972 if (vt < 0)
973 return;
974
d6176c6c
RS
975 r = fchown(vt, s->user->uid, -1);
976 if (r < 0)
977 goto error;
978
90a18413
DH
979 r = ioctl(vt, KDSKBMODE, K_OFF);
980 if (r < 0)
981 goto error;
982
983 r = ioctl(vt, KDSETMODE, KD_GRAPHICS);
984 if (r < 0)
985 goto error;
986
987 sigemptyset(&mask);
988 sigaddset(&mask, SIGUSR1);
989 sigprocmask(SIG_BLOCK, &mask, NULL);
990
151b9b96 991 r = sd_event_add_signal(s->manager->event, &s->vt_source, SIGUSR1, session_vt_fn, s);
90a18413
DH
992 if (r < 0)
993 goto error;
994
995 /* Oh, thanks to the VT layer, VT_AUTO does not work with KD_GRAPHICS.
996 * So we need a dummy handler here which just acknowledges *all* VT
997 * switch requests. */
998 mode.mode = VT_PROCESS;
999 mode.relsig = SIGUSR1;
1000 mode.acqsig = SIGUSR1;
1001 r = ioctl(vt, VT_SETMODE, &mode);
1002 if (r < 0)
1003 goto error;
1004
1005 return;
1006
1007error:
92bd5ff3 1008 log_error("cannot mute VT %u for session %s (%d/%d)", s->vtnr, s->id, r, errno);
90a18413
DH
1009 session_restore_vt(s);
1010}
1011
1012void session_restore_vt(Session *s) {
a0eb2a75 1013 _cleanup_free_ char *utf8 = NULL;
90a18413
DH
1014 int vt, kb = K_XLATE;
1015 struct vt_mode mode = { 0 };
1016
1017 vt = session_open_vt(s);
1018 if (vt < 0)
1019 return;
1020
5f41d1f1 1021 s->vt_source = sd_event_source_unref(s->vt_source);
90a18413
DH
1022
1023 ioctl(vt, KDSETMODE, KD_TEXT);
1024
1025 if (read_one_line_file("/sys/module/vt/parameters/default_utf8", &utf8) >= 0 && *utf8 == '1')
1026 kb = K_UNICODE;
03e334a1 1027
90a18413
DH
1028 ioctl(vt, KDSKBMODE, kb);
1029
1030 mode.mode = VT_AUTO;
1031 ioctl(vt, VT_SETMODE, &mode);
1032
d6176c6c
RS
1033 fchown(vt, 0, -1);
1034
03e334a1 1035 s->vtfd = safe_close(s->vtfd);
90a18413
DH
1036}
1037
cc377381 1038bool session_is_controller(Session *s, const char *sender) {
ae5e06bd
DH
1039 assert(s);
1040
1041 return streq_ptr(s->controller, sender);
1042}
1043
6d33772f
DH
1044static void session_swap_controller(Session *s, char *name) {
1045 SessionDevice *sd;
1046
1047 if (s->controller) {
1048 manager_drop_busname(s->manager, s->controller);
1049 free(s->controller);
1050 s->controller = NULL;
1051
1052 /* Drop all devices as they're now unused. Do that after the
1053 * controller is released to avoid sending out useles
1054 * dbus signals. */
1055 while ((sd = hashmap_first(s->devices)))
1056 session_device_free(sd);
90a18413
DH
1057
1058 if (!name)
1059 session_restore_vt(s);
6d33772f
DH
1060 }
1061
1062 s->controller = name;
1063 session_save(s);
1064}
1065
ae5e06bd
DH
1066int session_set_controller(Session *s, const char *sender, bool force) {
1067 char *t;
1068 int r;
1069
1070 assert(s);
1071 assert(sender);
1072
1073 if (session_is_controller(s, sender))
1074 return 0;
1075 if (s->controller && !force)
1076 return -EBUSY;
1077
1078 t = strdup(sender);
1079 if (!t)
1080 return -ENOMEM;
1081
1082 r = manager_watch_busname(s->manager, sender);
1083 if (r) {
1084 free(t);
1085 return r;
1086 }
1087
6d33772f 1088 session_swap_controller(s, t);
ae5e06bd 1089
90a18413
DH
1090 /* When setting a session controller, we forcibly mute the VT and set
1091 * it into graphics-mode. Applications can override that by changing
1092 * VT state after calling TakeControl(). However, this serves as a good
1093 * default and well-behaving controllers can now ignore VTs entirely.
1094 * Note that we reset the VT on ReleaseControl() and if the controller
1095 * exits.
1096 * If logind crashes/restarts, we restore the controller during restart
1097 * or reset the VT in case it crashed/exited, too. */
8b8fa8b8 1098 session_prepare_vt(s);
90a18413 1099
ae5e06bd
DH
1100 return 0;
1101}
1102
1103void session_drop_controller(Session *s) {
1104 assert(s);
1105
1106 if (!s->controller)
1107 return;
1108
6d33772f 1109 session_swap_controller(s, NULL);
ae5e06bd
DH
1110}
1111
fb6becb4
LP
1112static const char* const session_state_table[_SESSION_STATE_MAX] = {
1113 [SESSION_OPENING] = "opening",
0604381b
LP
1114 [SESSION_ONLINE] = "online",
1115 [SESSION_ACTIVE] = "active",
1116 [SESSION_CLOSING] = "closing"
1117};
1118
1119DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
1120
20263082 1121static const char* const session_type_table[_SESSION_TYPE_MAX] = {
2c5859af 1122 [SESSION_UNSPECIFIED] = "unspecified",
3f49d45a 1123 [SESSION_TTY] = "tty",
98a28fef 1124 [SESSION_X11] = "x11",
d9eb81f9 1125 [SESSION_WAYLAND] = "wayland",
9541666b 1126 [SESSION_MIR] = "mir",
20263082
LP
1127};
1128
1129DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
de07ab16 1130
55efac6c
LP
1131static const char* const session_class_table[_SESSION_CLASS_MAX] = {
1132 [SESSION_USER] = "user",
1133 [SESSION_GREETER] = "greeter",
e2acb67b
LP
1134 [SESSION_LOCK_SCREEN] = "lock-screen",
1135 [SESSION_BACKGROUND] = "background"
55efac6c
LP
1136};
1137
1138DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
1139
de07ab16
LP
1140static const char* const kill_who_table[_KILL_WHO_MAX] = {
1141 [KILL_LEADER] = "leader",
1142 [KILL_ALL] = "all"
1143};
1144
1145DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);