]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind-session.c
install: networkd.service depend on !--disable
[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);
410 if (fd >= 0)
411 close_nointr_nofail(fd);
412 }
413
9444b1f2
LP
414 if (realtime) {
415 unsigned long long l;
416 if (sscanf(realtime, "%llu", &l) > 0)
417 s->timestamp.realtime = l;
418 }
419
420 if (monotonic) {
421 unsigned long long l;
422 if (sscanf(monotonic, "%llu", &l) > 0)
423 s->timestamp.monotonic = l;
424 }
a185c5aa 425
6d33772f
DH
426 if (controller) {
427 if (bus_name_has_owner(s->manager->bus, controller, NULL) > 0)
428 session_set_controller(s, controller, false);
90a18413
DH
429 else
430 session_restore_vt(s);
6d33772f
DH
431 }
432
a185c5aa 433 return r;
20263082
LP
434}
435
436int session_activate(Session *s) {
d7bd01b5
DH
437 unsigned int num_pending;
438
20263082 439 assert(s);
9444b1f2 440 assert(s->user);
20263082 441
20263082
LP
442 if (!s->seat)
443 return -ENOTSUP;
444
445 if (s->seat->active == s)
446 return 0;
447
d7bd01b5
DH
448 /* on seats with VTs, we let VTs manage session-switching */
449 if (seat_has_vts(s->seat)) {
92bd5ff3 450 if (!s->vtnr)
d7bd01b5
DH
451 return -ENOTSUP;
452
453 return chvt(s->vtnr);
454 }
455
456 /* On seats without VTs, we implement session-switching in logind. We
457 * try to pause all session-devices and wait until the session
458 * controller acknowledged them. Once all devices are asleep, we simply
459 * switch the active session and be done.
460 * We save the session we want to switch to in seat->pending_switch and
461 * seat_complete_switch() will perform the final switch. */
462
463 s->seat->pending_switch = s;
464
465 /* if no devices are running, immediately perform the session switch */
466 num_pending = session_device_try_pause_all(s);
467 if (!num_pending)
468 seat_complete_switch(s->seat);
20263082 469
d7bd01b5 470 return 0;
20263082
LP
471}
472
fb6becb4 473static int session_start_scope(Session *s) {
98a28fef
LP
474 int r;
475
476 assert(s);
9444b1f2 477 assert(s->user);
fb6becb4 478 assert(s->user->slice);
98a28fef 479
fb6becb4 480 if (!s->scope) {
cc377381 481 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
d0af76e6 482 _cleanup_free_ char *description = NULL;
39883f62 483 char *scope, *job = NULL;
d0af76e6 484
405e0255
LP
485 description = strjoin("Session ", s->id, " of user ", s->user->name, NULL);
486 if (!description)
487 return log_oom();
488
d0af76e6
LP
489 scope = strjoin("session-", s->id, ".scope", NULL);
490 if (!scope)
ae018d9b
LP
491 return log_oom();
492
ba4c5d93 493 r = manager_start_scope(s->manager, scope, s->leader, s->user->slice, description, "systemd-logind.service", "systemd-user-session.service", &error, &job);
d0af76e6 494 if (r < 0) {
042f5988 495 log_error("Failed to start session scope %s: %s %s",
cc377381 496 scope, bus_error_message(&error, r), error.name);
d0af76e6 497 free(scope);
f2d4f98d 498 return r;
d0af76e6
LP
499 } else {
500 s->scope = scope;
501
502 free(s->scope_job);
503 s->scope_job = job;
504 }
20263082
LP
505 }
506
d0af76e6
LP
507 if (s->scope)
508 hashmap_put(s->manager->session_units, s->scope, s);
509
20263082
LP
510 return 0;
511}
512
513int session_start(Session *s) {
514 int r;
515
516 assert(s);
9444b1f2
LP
517
518 if (!s->user)
519 return -ESTALE;
20263082 520
9418f147
LP
521 if (s->started)
522 return 0;
523
ed18b08b
LP
524 r = user_start(s->user);
525 if (r < 0)
526 return r;
527
fb6becb4
LP
528 /* Create cgroup */
529 r = session_start_scope(s);
530 if (r < 0)
531 return r;
532
d9eb81f9 533 log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
1ca6783f 534 MESSAGE_ID(SD_MESSAGE_SESSION_START),
877d54e9
LP
535 "SESSION_ID=%s", s->id,
536 "USER_ID=%s", s->user->name,
537 "LEADER=%lu", (unsigned long) s->leader,
538 "MESSAGE=New session %s of user %s.", s->id, s->user->name,
539 NULL);
98a28fef 540
9444b1f2
LP
541 if (!dual_timestamp_is_set(&s->timestamp))
542 dual_timestamp_get(&s->timestamp);
14c3baca 543
e9816c48
LP
544 if (s->seat)
545 seat_read_active_vt(s->seat);
546
9418f147
LP
547 s->started = true;
548
5f41d1f1 549 /* Save data */
e9816c48 550 session_save(s);
7f7bb946 551 user_save(s->user);
5f41d1f1
LP
552 if (s->seat)
553 seat_save(s->seat);
e9816c48 554
5f41d1f1 555 /* Send signals */
da119395 556 session_send_signal(s, true);
5f41d1f1 557 user_send_changed(s->user, "Sessions", NULL);
9418f147
LP
558 if (s->seat) {
559 if (s->seat->active == s)
cc377381 560 seat_send_changed(s->seat, "Sessions", "ActiveSession", NULL);
9418f147 561 else
cc377381 562 seat_send_changed(s->seat, "Sessions", NULL);
9418f147
LP
563 }
564
20263082
LP
565 return 0;
566}
567
9bb69af4 568static int session_stop_scope(Session *s, bool force) {
cc377381 569 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
39883f62 570 char *job = NULL;
20263082 571 int r;
20263082
LP
572
573 assert(s);
574
fb6becb4
LP
575 if (!s->scope)
576 return 0;
9b221b63 577
9bb69af4 578 if (force || manager_shall_kill(s->manager, s->user->name)) {
5f41d1f1
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_message(&error, r));
582 return r;
583 }
20263082 584
5f41d1f1
LP
585 free(s->scope_job);
586 s->scope_job = job;
587 } else {
588 r = manager_abandon_scope(s->manager, s->scope, &error);
589 if (r < 0) {
590 log_error("Failed to abandon session scope: %s", bus_error_message(&error, r));
591 return r;
592 }
593 }
20263082 594
9b221b63 595 return 0;
20263082
LP
596}
597
9bb69af4 598int session_stop(Session *s, bool force) {
405e0255
LP
599 int r;
600
601 assert(s);
602
603 if (!s->user)
604 return -ESTALE;
605
5f41d1f1
LP
606 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
607
608 /* We are going down, don't care about FIFOs anymore */
609 session_remove_fifo(s);
610
405e0255 611 /* Kill cgroup */
9bb69af4 612 r = session_stop_scope(s, force);
405e0255 613
5f41d1f1
LP
614 s->stopping = true;
615
405e0255 616 session_save(s);
cc377381 617 user_save(s->user);
405e0255
LP
618
619 return r;
620}
621
622int session_finalize(Session *s) {
623 int r = 0;
118ecf32 624 SessionDevice *sd;
20263082
LP
625
626 assert(s);
627
9444b1f2
LP
628 if (!s->user)
629 return -ESTALE;
630
ed18b08b 631 if (s->started)
d9eb81f9 632 log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
1ca6783f 633 MESSAGE_ID(SD_MESSAGE_SESSION_STOP),
877d54e9
LP
634 "SESSION_ID=%s", s->id,
635 "USER_ID=%s", s->user->name,
636 "LEADER=%lu", (unsigned long) s->leader,
637 "MESSAGE=Removed session %s.", s->id,
638 NULL);
98a28fef 639
5f41d1f1
LP
640 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
641
118ecf32
DH
642 /* Kill session devices */
643 while ((sd = hashmap_first(s->devices)))
644 session_device_free(sd);
645
d2f92cdf
LP
646 unlink(s->state_file);
647 session_add_to_gc_queue(s);
ed18b08b 648 user_add_to_gc_queue(s->user);
14c3baca 649
405e0255 650 if (s->started) {
ed18b08b 651 session_send_signal(s, false);
405e0255
LP
652 s->started = false;
653 }
50fb9793 654
9418f147
LP
655 if (s->seat) {
656 if (s->seat->active == s)
657 seat_set_active(s->seat, NULL);
658
23bd3b62 659 seat_save(s->seat);
5f41d1f1 660 seat_send_changed(s->seat, "Sessions", NULL);
9418f147
LP
661 }
662
23bd3b62 663 user_save(s->user);
5f41d1f1 664 user_send_changed(s->user, "Sessions", NULL);
9418f147 665
20263082
LP
666 return r;
667}
668
5f41d1f1
LP
669static int release_timeout_callback(sd_event_source *es, uint64_t usec, void *userdata) {
670 Session *s = userdata;
671
672 assert(es);
673 assert(s);
674
9bb69af4 675 session_stop(s, false);
5f41d1f1
LP
676 return 0;
677}
678
679void session_release(Session *s) {
680 assert(s);
681
682 if (!s->started || s->stopping)
683 return;
684
685 if (!s->timer_event_source)
151b9b96 686 sd_event_add_monotonic(s->manager->event, &s->timer_event_source, now(CLOCK_MONOTONIC) + RELEASE_USEC, 0, release_timeout_callback, s);
5f41d1f1
LP
687}
688
20263082
LP
689bool session_is_active(Session *s) {
690 assert(s);
691
692 if (!s->seat)
693 return true;
694
695 return s->seat->active == s;
696}
697
23406ce5
LP
698static int get_tty_atime(const char *tty, usec_t *atime) {
699 _cleanup_free_ char *p = NULL;
a185c5aa 700 struct stat st;
23406ce5
LP
701
702 assert(tty);
703 assert(atime);
704
705 if (!path_is_absolute(tty)) {
706 p = strappend("/dev/", tty);
707 if (!p)
708 return -ENOMEM;
709
710 tty = p;
711 } else if (!path_startswith(tty, "/dev/"))
712 return -ENOENT;
713
714 if (lstat(tty, &st) < 0)
715 return -errno;
716
717 *atime = timespec_load(&st.st_atim);
718 return 0;
719}
720
721static int get_process_ctty_atime(pid_t pid, usec_t *atime) {
722 _cleanup_free_ char *p = NULL;
723 int r;
724
725 assert(pid > 0);
726 assert(atime);
727
728 r = get_ctty(pid, NULL, &p);
729 if (r < 0)
730 return r;
731
732 return get_tty_atime(p, atime);
733}
734
735int session_get_idle_hint(Session *s, dual_timestamp *t) {
23406ce5
LP
736 usec_t atime = 0, n;
737 int r;
a185c5aa
LP
738
739 assert(s);
740
23406ce5 741 /* Explicit idle hint is set */
a185c5aa
LP
742 if (s->idle_hint) {
743 if (t)
744 *t = s->idle_hint_timestamp;
745
746 return s->idle_hint;
747 }
748
0762eaa3 749 /* Graphical sessions should really implement a real
23406ce5
LP
750 * idle hint logic */
751 if (s->display)
a185c5aa
LP
752 goto dont_know;
753
23406ce5
LP
754 /* For sessions with an explicitly configured tty, let's check
755 * its atime */
756 if (s->tty) {
757 r = get_tty_atime(s->tty, &atime);
758 if (r >= 0)
759 goto found_atime;
760 }
a185c5aa 761
23406ce5
LP
762 /* For sessions with a leader but no explicitly configured
763 * tty, let's check the controlling tty of the leader */
764 if (s->leader > 0) {
765 r = get_process_ctty_atime(s->leader, &atime);
766 if (r >= 0)
767 goto found_atime;
a185c5aa
LP
768 }
769
a185c5aa
LP
770dont_know:
771 if (t)
772 *t = s->idle_hint_timestamp;
773
774 return 0;
23406ce5
LP
775
776found_atime:
777 if (t)
778 dual_timestamp_from_realtime(t, atime);
779
780 n = now(CLOCK_REALTIME);
781
782 if (s->manager->idle_action_usec <= 0)
783 return 0;
784
785 return atime + s->manager->idle_action_usec <= n;
a185c5aa
LP
786}
787
bef422ae
LP
788void session_set_idle_hint(Session *s, bool b) {
789 assert(s);
790
791 if (s->idle_hint == b)
792 return;
793
794 s->idle_hint = b;
795 dual_timestamp_get(&s->idle_hint_timestamp);
9418f147 796
cc377381 797 session_send_changed(s, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
9418f147
LP
798
799 if (s->seat)
cc377381
LP
800 seat_send_changed(s->seat, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
801
802 user_send_changed(s->user, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
803 manager_send_changed(s->manager, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
804}
805
806static int session_dispatch_fifo(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
807 Session *s = userdata;
808
809 assert(s);
810 assert(s->fifo_fd == fd);
811
812 /* EOF on the FIFO means the session died abnormally. */
813
814 session_remove_fifo(s);
9bb69af4 815 session_stop(s, false);
cc377381
LP
816
817 return 1;
bef422ae
LP
818}
819
932e3ee7
LP
820int session_create_fifo(Session *s) {
821 int r;
822
31b79c2b
LP
823 assert(s);
824
b4f78aea 825 /* Create FIFO */
932e3ee7 826 if (!s->fifo_path) {
d2e54fae 827 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
e6061ab2
LP
828 if (r < 0)
829 return r;
830
932e3ee7
LP
831 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
832 return -ENOMEM;
31b79c2b 833
932e3ee7
LP
834 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
835 return -errno;
836 }
31b79c2b 837
932e3ee7 838 /* Open reading side */
b4f78aea 839 if (s->fifo_fd < 0) {
b4f78aea
LP
840 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
841 if (s->fifo_fd < 0)
842 return -errno;
843
cc377381
LP
844 }
845
846 if (!s->fifo_event_source) {
151b9b96 847 r = sd_event_add_io(s->manager->event, &s->fifo_event_source, s->fifo_fd, 0, session_dispatch_fifo, s);
b4f78aea
LP
848 if (r < 0)
849 return r;
850
718db961 851 r = sd_event_source_set_priority(s->fifo_event_source, SD_EVENT_PRIORITY_IDLE);
cc377381
LP
852 if (r < 0)
853 return r;
b4f78aea 854 }
932e3ee7
LP
855
856 /* Open writing side */
857 r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
858 if (r < 0)
859 return -errno;
31b79c2b 860
932e3ee7
LP
861 return r;
862}
863
5f41d1f1 864static void session_remove_fifo(Session *s) {
932e3ee7
LP
865 assert(s);
866
cc377381
LP
867 if (s->fifo_event_source)
868 s->fifo_event_source = sd_event_source_unref(s->fifo_event_source);
869
932e3ee7 870 if (s->fifo_fd >= 0) {
932e3ee7
LP
871 close_nointr_nofail(s->fifo_fd);
872 s->fifo_fd = -1;
873 }
874
875 if (s->fifo_path) {
876 unlink(s->fifo_path);
877 free(s->fifo_path);
878 s->fifo_path = NULL;
879 }
31b79c2b
LP
880}
881
cc377381 882bool session_check_gc(Session *s, bool drop_not_started) {
20263082
LP
883 assert(s);
884
4a4b033f 885 if (drop_not_started && !s->started)
cc377381 886 return false;
932e3ee7 887
9444b1f2 888 if (!s->user)
cc377381 889 return false;
9444b1f2 890
932e3ee7 891 if (s->fifo_fd >= 0) {
5f41d1f1 892 if (pipe_eof(s->fifo_fd) <= 0)
cc377381 893 return true;
20263082
LP
894 }
895
cc377381
LP
896 if (s->scope_job && manager_job_is_active(s->manager, s->scope_job))
897 return true;
20263082 898
cc377381
LP
899 if (s->scope && manager_unit_is_active(s->manager, s->scope))
900 return true;
20263082 901
cc377381 902 return false;
20263082
LP
903}
904
14c3baca
LP
905void session_add_to_gc_queue(Session *s) {
906 assert(s);
907
908 if (s->in_gc_queue)
909 return;
910
71fda00f 911 LIST_PREPEND(gc_queue, s->manager->session_gc_queue, s);
14c3baca
LP
912 s->in_gc_queue = true;
913}
914
0604381b
LP
915SessionState session_get_state(Session *s) {
916 assert(s);
917
8fe63cd4 918 /* always check closing first */
5f41d1f1
LP
919 if (s->stopping || s->timer_event_source)
920 return SESSION_CLOSING;
921
8fe63cd4 922 if (s->scope_job || s->fifo_fd < 0)
405e0255 923 return SESSION_OPENING;
fb6becb4 924
0604381b
LP
925 if (session_is_active(s))
926 return SESSION_ACTIVE;
927
928 return SESSION_ONLINE;
929}
930
de07ab16 931int session_kill(Session *s, KillWho who, int signo) {
de07ab16
LP
932 assert(s);
933
fb6becb4 934 if (!s->scope)
de07ab16
LP
935 return -ESRCH;
936
fb6becb4 937 return manager_kill_unit(s->manager, s->scope, who, signo, NULL);
de07ab16
LP
938}
939
90a18413 940static int session_open_vt(Session *s) {
5f41d1f1 941 char path[sizeof("/dev/tty") + DECIMAL_STR_MAX(s->vtnr)];
90a18413 942
92bd5ff3 943 if (!s->vtnr)
90a18413
DH
944 return -1;
945
946 if (s->vtfd >= 0)
947 return s->vtfd;
948
92bd5ff3 949 sprintf(path, "/dev/tty%u", s->vtnr);
90a18413
DH
950 s->vtfd = open(path, O_RDWR | O_CLOEXEC | O_NONBLOCK | O_NOCTTY);
951 if (s->vtfd < 0) {
952 log_error("cannot open VT %s of session %s: %m", path, s->id);
953 return -1;
954 }
955
956 return s->vtfd;
957}
958
959static int session_vt_fn(sd_event_source *source, const struct signalfd_siginfo *si, void *data) {
960 Session *s = data;
961
962 if (s->vtfd >= 0)
963 ioctl(s->vtfd, VT_RELDISP, 1);
964
965 return 0;
966}
967
968void session_mute_vt(Session *s) {
969 int vt, r;
970 struct vt_mode mode = { 0 };
971 sigset_t mask;
972
973 vt = session_open_vt(s);
974 if (vt < 0)
975 return;
976
977 r = ioctl(vt, KDSKBMODE, K_OFF);
978 if (r < 0)
979 goto error;
980
981 r = ioctl(vt, KDSETMODE, KD_GRAPHICS);
982 if (r < 0)
983 goto error;
984
985 sigemptyset(&mask);
986 sigaddset(&mask, SIGUSR1);
987 sigprocmask(SIG_BLOCK, &mask, NULL);
988
151b9b96 989 r = sd_event_add_signal(s->manager->event, &s->vt_source, SIGUSR1, session_vt_fn, s);
90a18413
DH
990 if (r < 0)
991 goto error;
992
993 /* Oh, thanks to the VT layer, VT_AUTO does not work with KD_GRAPHICS.
994 * So we need a dummy handler here which just acknowledges *all* VT
995 * switch requests. */
996 mode.mode = VT_PROCESS;
997 mode.relsig = SIGUSR1;
998 mode.acqsig = SIGUSR1;
999 r = ioctl(vt, VT_SETMODE, &mode);
1000 if (r < 0)
1001 goto error;
1002
1003 return;
1004
1005error:
92bd5ff3 1006 log_error("cannot mute VT %u for session %s (%d/%d)", s->vtnr, s->id, r, errno);
90a18413
DH
1007 session_restore_vt(s);
1008}
1009
1010void session_restore_vt(Session *s) {
1011 _cleanup_free_ char *utf8;
1012 int vt, kb = K_XLATE;
1013 struct vt_mode mode = { 0 };
1014
1015 vt = session_open_vt(s);
1016 if (vt < 0)
1017 return;
1018
5f41d1f1 1019 s->vt_source = sd_event_source_unref(s->vt_source);
90a18413
DH
1020
1021 ioctl(vt, KDSETMODE, KD_TEXT);
1022
1023 if (read_one_line_file("/sys/module/vt/parameters/default_utf8", &utf8) >= 0 && *utf8 == '1')
1024 kb = K_UNICODE;
1025 ioctl(vt, KDSKBMODE, kb);
1026
1027 mode.mode = VT_AUTO;
1028 ioctl(vt, VT_SETMODE, &mode);
1029
1030 close_nointr_nofail(vt);
1031 s->vtfd = -1;
1032}
1033
cc377381 1034bool session_is_controller(Session *s, const char *sender) {
ae5e06bd
DH
1035 assert(s);
1036
1037 return streq_ptr(s->controller, sender);
1038}
1039
6d33772f
DH
1040static void session_swap_controller(Session *s, char *name) {
1041 SessionDevice *sd;
1042
1043 if (s->controller) {
1044 manager_drop_busname(s->manager, s->controller);
1045 free(s->controller);
1046 s->controller = NULL;
1047
1048 /* Drop all devices as they're now unused. Do that after the
1049 * controller is released to avoid sending out useles
1050 * dbus signals. */
1051 while ((sd = hashmap_first(s->devices)))
1052 session_device_free(sd);
90a18413
DH
1053
1054 if (!name)
1055 session_restore_vt(s);
6d33772f
DH
1056 }
1057
1058 s->controller = name;
1059 session_save(s);
1060}
1061
ae5e06bd
DH
1062int session_set_controller(Session *s, const char *sender, bool force) {
1063 char *t;
1064 int r;
1065
1066 assert(s);
1067 assert(sender);
1068
1069 if (session_is_controller(s, sender))
1070 return 0;
1071 if (s->controller && !force)
1072 return -EBUSY;
1073
1074 t = strdup(sender);
1075 if (!t)
1076 return -ENOMEM;
1077
1078 r = manager_watch_busname(s->manager, sender);
1079 if (r) {
1080 free(t);
1081 return r;
1082 }
1083
6d33772f 1084 session_swap_controller(s, t);
ae5e06bd 1085
90a18413
DH
1086 /* When setting a session controller, we forcibly mute the VT and set
1087 * it into graphics-mode. Applications can override that by changing
1088 * VT state after calling TakeControl(). However, this serves as a good
1089 * default and well-behaving controllers can now ignore VTs entirely.
1090 * Note that we reset the VT on ReleaseControl() and if the controller
1091 * exits.
1092 * If logind crashes/restarts, we restore the controller during restart
1093 * or reset the VT in case it crashed/exited, too. */
1094 session_mute_vt(s);
1095
ae5e06bd
DH
1096 return 0;
1097}
1098
1099void session_drop_controller(Session *s) {
1100 assert(s);
1101
1102 if (!s->controller)
1103 return;
1104
6d33772f 1105 session_swap_controller(s, NULL);
ae5e06bd
DH
1106}
1107
fb6becb4
LP
1108static const char* const session_state_table[_SESSION_STATE_MAX] = {
1109 [SESSION_OPENING] = "opening",
0604381b
LP
1110 [SESSION_ONLINE] = "online",
1111 [SESSION_ACTIVE] = "active",
1112 [SESSION_CLOSING] = "closing"
1113};
1114
1115DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
1116
20263082 1117static const char* const session_type_table[_SESSION_TYPE_MAX] = {
3f49d45a 1118 [SESSION_TTY] = "tty",
98a28fef 1119 [SESSION_X11] = "x11",
d9eb81f9
LP
1120 [SESSION_WAYLAND] = "wayland",
1121 [SESSION_UNSPECIFIED] = "unspecified",
20263082
LP
1122};
1123
1124DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
de07ab16 1125
55efac6c
LP
1126static const char* const session_class_table[_SESSION_CLASS_MAX] = {
1127 [SESSION_USER] = "user",
1128 [SESSION_GREETER] = "greeter",
e2acb67b
LP
1129 [SESSION_LOCK_SCREEN] = "lock-screen",
1130 [SESSION_BACKGROUND] = "background"
55efac6c
LP
1131};
1132
1133DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
1134
de07ab16
LP
1135static const char* const kill_who_table[_KILL_WHO_MAX] = {
1136 [KILL_LEADER] = "leader",
1137 [KILL_ALL] = "all"
1138};
1139
1140DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);