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