Line data Source code
1 : /* SPDX-License-Identifier: LGPL-2.1+ */
2 :
3 : #include <errno.h>
4 : #include <fcntl.h>
5 : #include <linux/kd.h>
6 : #include <linux/vt.h>
7 : #include <signal.h>
8 : #include <string.h>
9 : #include <sys/ioctl.h>
10 : #include <sys/stat.h>
11 : #include <unistd.h>
12 :
13 : #include "sd-messages.h"
14 :
15 : #include "alloc-util.h"
16 : #include "audit-util.h"
17 : #include "bus-error.h"
18 : #include "bus-util.h"
19 : #include "env-file.h"
20 : #include "escape.h"
21 : #include "fd-util.h"
22 : #include "fileio.h"
23 : #include "format-util.h"
24 : #include "io-util.h"
25 : #include "logind-dbus.h"
26 : #include "logind-seat-dbus.h"
27 : #include "logind-session-dbus.h"
28 : #include "logind-session.h"
29 : #include "logind-user-dbus.h"
30 : #include "mkdir.h"
31 : #include "parse-util.h"
32 : #include "path-util.h"
33 : #include "process-util.h"
34 : #include "serialize.h"
35 : #include "string-table.h"
36 : #include "strv.h"
37 : #include "terminal-util.h"
38 : #include "tmpfile-util.h"
39 : #include "user-util.h"
40 : #include "util.h"
41 :
42 : #define RELEASE_USEC (20*USEC_PER_SEC)
43 :
44 : static void session_remove_fifo(Session *s);
45 : static void session_restore_vt(Session *s);
46 :
47 0 : int session_new(Session **ret, Manager *m, const char *id) {
48 0 : _cleanup_(session_freep) Session *s = NULL;
49 : int r;
50 :
51 0 : assert(ret);
52 0 : assert(m);
53 0 : assert(id);
54 :
55 0 : if (!session_id_valid(id))
56 0 : return -EINVAL;
57 :
58 0 : s = new(Session, 1);
59 0 : if (!s)
60 0 : return -ENOMEM;
61 :
62 0 : *s = (Session) {
63 : .manager = m,
64 : .fifo_fd = -1,
65 : .vtfd = -1,
66 : .audit_id = AUDIT_SESSION_INVALID,
67 : .tty_validity = _TTY_VALIDITY_INVALID,
68 : };
69 :
70 0 : s->state_file = path_join("/run/systemd/sessions", id);
71 0 : if (!s->state_file)
72 0 : return -ENOMEM;
73 :
74 0 : s->id = basename(s->state_file);
75 :
76 0 : s->devices = hashmap_new(&devt_hash_ops);
77 0 : if (!s->devices)
78 0 : return -ENOMEM;
79 :
80 0 : r = hashmap_put(m->sessions, s->id, s);
81 0 : if (r < 0)
82 0 : return r;
83 :
84 0 : *ret = TAKE_PTR(s);
85 0 : return 0;
86 : }
87 :
88 0 : Session* session_free(Session *s) {
89 : SessionDevice *sd;
90 :
91 0 : if (!s)
92 0 : return NULL;
93 :
94 0 : if (s->in_gc_queue)
95 0 : LIST_REMOVE(gc_queue, s->manager->session_gc_queue, s);
96 :
97 0 : s->timer_event_source = sd_event_source_unref(s->timer_event_source);
98 :
99 0 : session_drop_controller(s);
100 :
101 0 : while ((sd = hashmap_first(s->devices)))
102 0 : session_device_free(sd);
103 :
104 0 : hashmap_free(s->devices);
105 :
106 0 : if (s->user) {
107 0 : LIST_REMOVE(sessions_by_user, s->user->sessions, s);
108 :
109 0 : if (s->user->display == s)
110 0 : s->user->display = NULL;
111 :
112 0 : user_update_last_session_timer(s->user);
113 : }
114 :
115 0 : if (s->seat) {
116 0 : if (s->seat->active == s)
117 0 : s->seat->active = NULL;
118 0 : if (s->seat->pending_switch == s)
119 0 : s->seat->pending_switch = NULL;
120 :
121 0 : seat_evict_position(s->seat, s);
122 0 : LIST_REMOVE(sessions_by_seat, s->seat->sessions, s);
123 : }
124 :
125 0 : if (s->scope) {
126 0 : hashmap_remove(s->manager->session_units, s->scope);
127 0 : free(s->scope);
128 : }
129 :
130 0 : if (pid_is_valid(s->leader))
131 0 : (void) hashmap_remove_value(s->manager->sessions_by_leader, PID_TO_PTR(s->leader), s);
132 :
133 0 : free(s->scope_job);
134 :
135 0 : sd_bus_message_unref(s->create_message);
136 :
137 0 : free(s->tty);
138 0 : free(s->display);
139 0 : free(s->remote_host);
140 0 : free(s->remote_user);
141 0 : free(s->service);
142 0 : free(s->desktop);
143 :
144 0 : hashmap_remove(s->manager->sessions, s->id);
145 :
146 0 : sd_event_source_unref(s->fifo_event_source);
147 0 : safe_close(s->fifo_fd);
148 :
149 : /* Note that we remove neither the state file nor the fifo path here, since we want both to survive
150 : * daemon restarts */
151 0 : free(s->state_file);
152 0 : free(s->fifo_path);
153 :
154 0 : return mfree(s);
155 : }
156 :
157 0 : void session_set_user(Session *s, User *u) {
158 0 : assert(s);
159 0 : assert(!s->user);
160 :
161 0 : s->user = u;
162 0 : LIST_PREPEND(sessions_by_user, u->sessions, s);
163 :
164 0 : user_update_last_session_timer(u);
165 0 : }
166 :
167 0 : int session_set_leader(Session *s, pid_t pid) {
168 : int r;
169 :
170 0 : assert(s);
171 :
172 0 : if (!pid_is_valid(pid))
173 0 : return -EINVAL;
174 :
175 0 : if (s->leader == pid)
176 0 : return 0;
177 :
178 0 : r = hashmap_put(s->manager->sessions_by_leader, PID_TO_PTR(pid), s);
179 0 : if (r < 0)
180 0 : return r;
181 :
182 0 : if (pid_is_valid(s->leader))
183 0 : (void) hashmap_remove_value(s->manager->sessions_by_leader, PID_TO_PTR(s->leader), s);
184 :
185 0 : s->leader = pid;
186 0 : (void) audit_session_from_pid(pid, &s->audit_id);
187 :
188 0 : return 1;
189 : }
190 :
191 0 : static void session_save_devices(Session *s, FILE *f) {
192 : SessionDevice *sd;
193 : Iterator i;
194 :
195 0 : if (!hashmap_isempty(s->devices)) {
196 0 : fprintf(f, "DEVICES=");
197 0 : HASHMAP_FOREACH(sd, s->devices, i)
198 0 : fprintf(f, "%u:%u ", major(sd->dev), minor(sd->dev));
199 0 : fprintf(f, "\n");
200 : }
201 0 : }
202 :
203 0 : int session_save(Session *s) {
204 0 : _cleanup_free_ char *temp_path = NULL;
205 0 : _cleanup_fclose_ FILE *f = NULL;
206 0 : int r = 0;
207 :
208 0 : assert(s);
209 :
210 0 : if (!s->user)
211 0 : return -ESTALE;
212 :
213 0 : if (!s->started)
214 0 : return 0;
215 :
216 0 : r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0, MKDIR_WARN_MODE);
217 0 : if (r < 0)
218 0 : goto fail;
219 :
220 0 : r = fopen_temporary(s->state_file, &f, &temp_path);
221 0 : if (r < 0)
222 0 : goto fail;
223 :
224 0 : (void) fchmod(fileno(f), 0644);
225 :
226 0 : fprintf(f,
227 : "# This is private data. Do not parse.\n"
228 : "UID="UID_FMT"\n"
229 : "USER=%s\n"
230 : "ACTIVE=%i\n"
231 : "IS_DISPLAY=%i\n"
232 : "STATE=%s\n"
233 : "REMOTE=%i\n",
234 0 : s->user->uid,
235 0 : s->user->name,
236 0 : session_is_active(s),
237 0 : s->user->display == s,
238 : session_state_to_string(session_get_state(s)),
239 0 : s->remote);
240 :
241 0 : if (s->type >= 0)
242 0 : fprintf(f, "TYPE=%s\n", session_type_to_string(s->type));
243 :
244 0 : if (s->class >= 0)
245 0 : fprintf(f, "CLASS=%s\n", session_class_to_string(s->class));
246 :
247 0 : if (s->scope)
248 0 : fprintf(f, "SCOPE=%s\n", s->scope);
249 0 : if (s->scope_job)
250 0 : fprintf(f, "SCOPE_JOB=%s\n", s->scope_job);
251 :
252 0 : if (s->fifo_path)
253 0 : fprintf(f, "FIFO=%s\n", s->fifo_path);
254 :
255 0 : if (s->seat)
256 0 : fprintf(f, "SEAT=%s\n", s->seat->id);
257 :
258 0 : if (s->tty)
259 0 : fprintf(f, "TTY=%s\n", s->tty);
260 :
261 0 : if (s->tty_validity >= 0)
262 0 : fprintf(f, "TTY_VALIDITY=%s\n", tty_validity_to_string(s->tty_validity));
263 :
264 0 : if (s->display)
265 0 : fprintf(f, "DISPLAY=%s\n", s->display);
266 :
267 0 : if (s->remote_host) {
268 0 : _cleanup_free_ char *escaped;
269 :
270 0 : escaped = cescape(s->remote_host);
271 0 : if (!escaped) {
272 0 : r = -ENOMEM;
273 0 : goto fail;
274 : }
275 :
276 0 : fprintf(f, "REMOTE_HOST=%s\n", escaped);
277 : }
278 :
279 0 : if (s->remote_user) {
280 0 : _cleanup_free_ char *escaped;
281 :
282 0 : escaped = cescape(s->remote_user);
283 0 : if (!escaped) {
284 0 : r = -ENOMEM;
285 0 : goto fail;
286 : }
287 :
288 0 : fprintf(f, "REMOTE_USER=%s\n", escaped);
289 : }
290 :
291 0 : if (s->service) {
292 0 : _cleanup_free_ char *escaped;
293 :
294 0 : escaped = cescape(s->service);
295 0 : if (!escaped) {
296 0 : r = -ENOMEM;
297 0 : goto fail;
298 : }
299 :
300 0 : fprintf(f, "SERVICE=%s\n", escaped);
301 : }
302 :
303 0 : if (s->desktop) {
304 0 : _cleanup_free_ char *escaped;
305 :
306 0 : escaped = cescape(s->desktop);
307 0 : if (!escaped) {
308 0 : r = -ENOMEM;
309 0 : goto fail;
310 : }
311 :
312 0 : fprintf(f, "DESKTOP=%s\n", escaped);
313 : }
314 :
315 0 : if (s->seat && seat_has_vts(s->seat))
316 0 : fprintf(f, "VTNR=%u\n", s->vtnr);
317 :
318 0 : if (!s->vtnr)
319 0 : fprintf(f, "POSITION=%u\n", s->position);
320 :
321 0 : if (pid_is_valid(s->leader))
322 0 : fprintf(f, "LEADER="PID_FMT"\n", s->leader);
323 :
324 0 : if (audit_session_is_valid(s->audit_id))
325 0 : fprintf(f, "AUDIT=%"PRIu32"\n", s->audit_id);
326 :
327 0 : if (dual_timestamp_is_set(&s->timestamp))
328 0 : fprintf(f,
329 : "REALTIME="USEC_FMT"\n"
330 : "MONOTONIC="USEC_FMT"\n",
331 : s->timestamp.realtime,
332 : s->timestamp.monotonic);
333 :
334 0 : if (s->controller) {
335 0 : fprintf(f, "CONTROLLER=%s\n", s->controller);
336 0 : session_save_devices(s, f);
337 : }
338 :
339 0 : r = fflush_and_check(f);
340 0 : if (r < 0)
341 0 : goto fail;
342 :
343 0 : if (rename(temp_path, s->state_file) < 0) {
344 0 : r = -errno;
345 0 : goto fail;
346 : }
347 :
348 0 : return 0;
349 :
350 0 : fail:
351 0 : (void) unlink(s->state_file);
352 :
353 0 : if (temp_path)
354 0 : (void) unlink(temp_path);
355 :
356 0 : return log_error_errno(r, "Failed to save session data %s: %m", s->state_file);
357 : }
358 :
359 0 : static int session_load_devices(Session *s, const char *devices) {
360 : const char *p;
361 0 : int r = 0;
362 :
363 0 : assert(s);
364 :
365 0 : for (p = devices;;) {
366 0 : _cleanup_free_ char *word = NULL;
367 : SessionDevice *sd;
368 : dev_t dev;
369 : int k;
370 :
371 0 : k = extract_first_word(&p, &word, NULL, 0);
372 0 : if (k == 0)
373 0 : break;
374 0 : if (k < 0) {
375 0 : r = k;
376 0 : break;
377 : }
378 :
379 0 : k = parse_dev(word, &dev);
380 0 : if (k < 0) {
381 0 : r = k;
382 0 : continue;
383 : }
384 :
385 : /* The file descriptors for loaded devices will be reattached later. */
386 0 : k = session_device_new(s, dev, false, &sd);
387 0 : if (k < 0)
388 0 : r = k;
389 : }
390 :
391 0 : if (r < 0)
392 0 : log_error_errno(r, "Loading session devices for session %s failed: %m", s->id);
393 :
394 0 : return r;
395 : }
396 :
397 0 : int session_load(Session *s) {
398 0 : _cleanup_free_ char *remote = NULL,
399 0 : *seat = NULL,
400 0 : *tty_validity = NULL,
401 0 : *vtnr = NULL,
402 0 : *state = NULL,
403 0 : *position = NULL,
404 0 : *leader = NULL,
405 0 : *type = NULL,
406 0 : *class = NULL,
407 0 : *uid = NULL,
408 0 : *realtime = NULL,
409 0 : *monotonic = NULL,
410 0 : *controller = NULL,
411 0 : *active = NULL,
412 0 : *devices = NULL,
413 0 : *is_display = NULL;
414 :
415 : int k, r;
416 :
417 0 : assert(s);
418 :
419 0 : r = parse_env_file(NULL, s->state_file,
420 : "REMOTE", &remote,
421 : "SCOPE", &s->scope,
422 : "SCOPE_JOB", &s->scope_job,
423 : "FIFO", &s->fifo_path,
424 : "SEAT", &seat,
425 : "TTY", &s->tty,
426 : "TTY_VALIDITY", &tty_validity,
427 : "DISPLAY", &s->display,
428 : "REMOTE_HOST", &s->remote_host,
429 : "REMOTE_USER", &s->remote_user,
430 : "SERVICE", &s->service,
431 : "DESKTOP", &s->desktop,
432 : "VTNR", &vtnr,
433 : "STATE", &state,
434 : "POSITION", &position,
435 : "LEADER", &leader,
436 : "TYPE", &type,
437 : "CLASS", &class,
438 : "UID", &uid,
439 : "REALTIME", &realtime,
440 : "MONOTONIC", &monotonic,
441 : "CONTROLLER", &controller,
442 : "ACTIVE", &active,
443 : "DEVICES", &devices,
444 : "IS_DISPLAY", &is_display);
445 :
446 0 : if (r < 0)
447 0 : return log_error_errno(r, "Failed to read %s: %m", s->state_file);
448 :
449 0 : if (!s->user) {
450 : uid_t u;
451 : User *user;
452 :
453 0 : if (!uid)
454 0 : return log_error_errno(SYNTHETIC_ERRNO(ENOENT),
455 : "UID not specified for session %s",
456 : s->id);
457 :
458 0 : r = parse_uid(uid, &u);
459 0 : if (r < 0) {
460 0 : log_error("Failed to parse UID value %s for session %s.", uid, s->id);
461 0 : return r;
462 : }
463 :
464 0 : user = hashmap_get(s->manager->users, UID_TO_PTR(u));
465 0 : if (!user)
466 0 : return log_error_errno(SYNTHETIC_ERRNO(ENOENT),
467 : "User of session %s not known.",
468 : s->id);
469 :
470 0 : session_set_user(s, user);
471 : }
472 :
473 0 : if (remote) {
474 0 : k = parse_boolean(remote);
475 0 : if (k >= 0)
476 0 : s->remote = k;
477 : }
478 :
479 0 : if (vtnr)
480 0 : safe_atou(vtnr, &s->vtnr);
481 :
482 0 : if (seat && !s->seat) {
483 : Seat *o;
484 :
485 0 : o = hashmap_get(s->manager->seats, seat);
486 0 : if (o)
487 0 : r = seat_attach_session(o, s);
488 0 : if (!o || r < 0)
489 0 : log_error("Cannot attach session %s to seat %s", s->id, seat);
490 : }
491 :
492 0 : if (!s->seat || !seat_has_vts(s->seat))
493 0 : s->vtnr = 0;
494 :
495 0 : if (position && s->seat) {
496 : unsigned npos;
497 :
498 0 : safe_atou(position, &npos);
499 0 : seat_claim_position(s->seat, s, npos);
500 : }
501 :
502 0 : if (tty_validity) {
503 : TTYValidity v;
504 :
505 0 : v = tty_validity_from_string(tty_validity);
506 0 : if (v < 0)
507 0 : log_debug("Failed to parse TTY validity: %s", tty_validity);
508 : else
509 0 : s->tty_validity = v;
510 : }
511 :
512 0 : if (leader) {
513 : pid_t pid;
514 :
515 0 : r = parse_pid(leader, &pid);
516 0 : if (r < 0)
517 0 : log_debug_errno(r, "Failed to parse leader PID of session: %s", leader);
518 : else {
519 0 : r = session_set_leader(s, pid);
520 0 : if (r < 0)
521 0 : log_warning_errno(r, "Failed to set session leader PID, ignoring: %m");
522 : }
523 : }
524 :
525 0 : if (type) {
526 : SessionType t;
527 :
528 0 : t = session_type_from_string(type);
529 0 : if (t >= 0)
530 0 : s->type = t;
531 : }
532 :
533 0 : if (class) {
534 : SessionClass c;
535 :
536 0 : c = session_class_from_string(class);
537 0 : if (c >= 0)
538 0 : s->class = c;
539 : }
540 :
541 0 : if (state && streq(state, "closing"))
542 0 : s->stopping = true;
543 :
544 0 : if (s->fifo_path) {
545 : int fd;
546 :
547 : /* If we open an unopened pipe for reading we will not
548 : get an EOF. to trigger an EOF we hence open it for
549 : writing, but close it right away which then will
550 : trigger the EOF. This will happen immediately if no
551 : other process has the FIFO open for writing, i. e.
552 : when the session died before logind (re)started. */
553 :
554 0 : fd = session_create_fifo(s);
555 0 : safe_close(fd);
556 : }
557 :
558 0 : if (realtime)
559 0 : (void) deserialize_usec(realtime, &s->timestamp.realtime);
560 0 : if (monotonic)
561 0 : (void) deserialize_usec(monotonic, &s->timestamp.monotonic);
562 :
563 0 : if (active) {
564 0 : k = parse_boolean(active);
565 0 : if (k >= 0)
566 0 : s->was_active = k;
567 : }
568 :
569 0 : if (is_display) {
570 : /* Note that when enumerating users are loaded before sessions, hence the display session to use is
571 : * something we have to store along with the session and not the user, as in that case we couldn't
572 : * apply it at the time we load the user. */
573 :
574 0 : k = parse_boolean(is_display);
575 0 : if (k < 0)
576 0 : log_warning_errno(k, "Failed to parse IS_DISPLAY session property: %m");
577 0 : else if (k > 0)
578 0 : s->user->display = s;
579 : }
580 :
581 0 : if (controller) {
582 0 : if (bus_name_has_owner(s->manager->bus, controller, NULL) > 0) {
583 0 : session_set_controller(s, controller, false, false);
584 0 : session_load_devices(s, devices);
585 : } else
586 0 : session_restore_vt(s);
587 : }
588 :
589 0 : return r;
590 : }
591 :
592 0 : int session_activate(Session *s) {
593 : unsigned num_pending;
594 :
595 0 : assert(s);
596 0 : assert(s->user);
597 :
598 0 : if (!s->seat)
599 0 : return -EOPNOTSUPP;
600 :
601 0 : if (s->seat->active == s)
602 0 : return 0;
603 :
604 : /* on seats with VTs, we let VTs manage session-switching */
605 0 : if (seat_has_vts(s->seat)) {
606 0 : if (s->vtnr == 0)
607 0 : return -EOPNOTSUPP;
608 :
609 0 : return chvt(s->vtnr);
610 : }
611 :
612 : /* On seats without VTs, we implement session-switching in logind. We
613 : * try to pause all session-devices and wait until the session
614 : * controller acknowledged them. Once all devices are asleep, we simply
615 : * switch the active session and be done.
616 : * We save the session we want to switch to in seat->pending_switch and
617 : * seat_complete_switch() will perform the final switch. */
618 :
619 0 : s->seat->pending_switch = s;
620 :
621 : /* if no devices are running, immediately perform the session switch */
622 0 : num_pending = session_device_try_pause_all(s);
623 0 : if (!num_pending)
624 0 : seat_complete_switch(s->seat);
625 :
626 0 : return 0;
627 : }
628 :
629 0 : static int session_start_scope(Session *s, sd_bus_message *properties, sd_bus_error *error) {
630 : int r;
631 :
632 0 : assert(s);
633 0 : assert(s->user);
634 :
635 0 : if (!s->scope) {
636 0 : _cleanup_free_ char *scope = NULL;
637 : const char *description;
638 :
639 0 : s->scope_job = mfree(s->scope_job);
640 :
641 0 : scope = strjoin("session-", s->id, ".scope");
642 0 : if (!scope)
643 0 : return log_oom();
644 :
645 0 : description = strjoina("Session ", s->id, " of user ", s->user->name);
646 :
647 0 : r = manager_start_scope(
648 : s->manager,
649 : scope,
650 : s->leader,
651 0 : s->user->slice,
652 : description,
653 : /* These two have StopWhenUnneeded= set, hence add a dep towards them */
654 0 : STRV_MAKE(s->user->runtime_dir_service,
655 : s->user->service),
656 : /* And order us after some more */
657 0 : STRV_MAKE("systemd-logind.service",
658 : "systemd-user-sessions.service",
659 : s->user->runtime_dir_service,
660 : s->user->service),
661 0 : s->user->home,
662 : properties,
663 : error,
664 : &s->scope_job);
665 0 : if (r < 0)
666 0 : return log_error_errno(r, "Failed to start session scope %s: %s",
667 : scope, bus_error_message(error, r));
668 :
669 0 : s->scope = TAKE_PTR(scope);
670 : }
671 :
672 0 : (void) hashmap_put(s->manager->session_units, s->scope, s);
673 :
674 0 : return 0;
675 : }
676 :
677 0 : int session_start(Session *s, sd_bus_message *properties, sd_bus_error *error) {
678 : int r;
679 :
680 0 : assert(s);
681 :
682 0 : if (!s->user)
683 0 : return -ESTALE;
684 :
685 0 : if (s->stopping)
686 0 : return -EINVAL;
687 :
688 0 : if (s->started)
689 0 : return 0;
690 :
691 0 : r = user_start(s->user);
692 0 : if (r < 0)
693 0 : return r;
694 :
695 0 : r = session_start_scope(s, properties, error);
696 0 : if (r < 0)
697 0 : return r;
698 :
699 0 : log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
700 : "MESSAGE_ID=" SD_MESSAGE_SESSION_START_STR,
701 : "SESSION_ID=%s", s->id,
702 : "USER_ID=%s", s->user->name,
703 : "LEADER="PID_FMT, s->leader,
704 : LOG_MESSAGE("New session %s of user %s.", s->id, s->user->name));
705 :
706 0 : if (!dual_timestamp_is_set(&s->timestamp))
707 0 : dual_timestamp_get(&s->timestamp);
708 :
709 0 : if (s->seat)
710 0 : seat_read_active_vt(s->seat);
711 :
712 0 : s->started = true;
713 :
714 0 : user_elect_display(s->user);
715 :
716 : /* Save data */
717 0 : session_save(s);
718 0 : user_save(s->user);
719 0 : if (s->seat)
720 0 : seat_save(s->seat);
721 :
722 : /* Send signals */
723 0 : session_send_signal(s, true);
724 0 : user_send_changed(s->user, "Display", NULL);
725 0 : if (s->seat) {
726 0 : if (s->seat->active == s)
727 0 : seat_send_changed(s->seat, "ActiveSession", NULL);
728 : }
729 :
730 0 : return 0;
731 : }
732 :
733 0 : static int session_stop_scope(Session *s, bool force) {
734 0 : _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
735 : int r;
736 :
737 0 : assert(s);
738 :
739 0 : if (!s->scope)
740 0 : return 0;
741 :
742 : /* Let's always abandon the scope first. This tells systemd that we are not interested anymore, and everything
743 : * that is left in the scope is "left-over". Informing systemd about this has the benefit that it will log
744 : * when killing any processes left after this point. */
745 0 : r = manager_abandon_scope(s->manager, s->scope, &error);
746 0 : if (r < 0) {
747 0 : log_warning_errno(r, "Failed to abandon session scope, ignoring: %s", bus_error_message(&error, r));
748 0 : sd_bus_error_free(&error);
749 : }
750 :
751 0 : s->scope_job = mfree(s->scope_job);
752 :
753 : /* Optionally, let's kill everything that's left now. */
754 0 : if (force || manager_shall_kill(s->manager, s->user->name)) {
755 :
756 0 : r = manager_stop_unit(s->manager, s->scope, &error, &s->scope_job);
757 0 : if (r < 0) {
758 0 : if (force)
759 0 : return log_error_errno(r, "Failed to stop session scope: %s", bus_error_message(&error, r));
760 :
761 0 : log_warning_errno(r, "Failed to stop session scope, ignoring: %s", bus_error_message(&error, r));
762 : }
763 : } else {
764 :
765 : /* With no killing, this session is allowed to persist in "closing" state indefinitely.
766 : * Therefore session stop and session removal may be two distinct events.
767 : * Session stop is quite significant on its own, let's log it. */
768 0 : log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
769 : "SESSION_ID=%s", s->id,
770 : "USER_ID=%s", s->user->name,
771 : "LEADER="PID_FMT, s->leader,
772 : LOG_MESSAGE("Session %s logged out. Waiting for processes to exit.", s->id));
773 : }
774 :
775 0 : return 0;
776 : }
777 :
778 0 : int session_stop(Session *s, bool force) {
779 : int r;
780 :
781 0 : assert(s);
782 :
783 : /* This is called whenever we begin with tearing down a session record. It's called in four cases: explicit API
784 : * request via the bus (either directly for the session object or for the seat or user object this session
785 : * belongs to; 'force' is true), or due to automatic GC (i.e. scope vanished; 'force' is false), or because the
786 : * session FIFO saw an EOF ('force' is false), or because the release timer hit ('force' is false). */
787 :
788 0 : if (!s->user)
789 0 : return -ESTALE;
790 0 : if (!s->started)
791 0 : return 0;
792 0 : if (s->stopping)
793 0 : return 0;
794 :
795 0 : s->timer_event_source = sd_event_source_unref(s->timer_event_source);
796 :
797 0 : if (s->seat)
798 0 : seat_evict_position(s->seat, s);
799 :
800 : /* We are going down, don't care about FIFOs anymore */
801 0 : session_remove_fifo(s);
802 :
803 : /* Kill cgroup */
804 0 : r = session_stop_scope(s, force);
805 :
806 0 : s->stopping = true;
807 :
808 0 : user_elect_display(s->user);
809 :
810 0 : session_save(s);
811 0 : user_save(s->user);
812 :
813 0 : return r;
814 : }
815 :
816 0 : int session_finalize(Session *s) {
817 : SessionDevice *sd;
818 :
819 0 : assert(s);
820 :
821 0 : if (!s->user)
822 0 : return -ESTALE;
823 :
824 0 : if (s->started)
825 0 : log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
826 : "MESSAGE_ID=" SD_MESSAGE_SESSION_STOP_STR,
827 : "SESSION_ID=%s", s->id,
828 : "USER_ID=%s", s->user->name,
829 : "LEADER="PID_FMT, s->leader,
830 : LOG_MESSAGE("Removed session %s.", s->id));
831 :
832 0 : s->timer_event_source = sd_event_source_unref(s->timer_event_source);
833 :
834 0 : if (s->seat)
835 0 : seat_evict_position(s->seat, s);
836 :
837 : /* Kill session devices */
838 0 : while ((sd = hashmap_first(s->devices)))
839 0 : session_device_free(sd);
840 :
841 0 : (void) unlink(s->state_file);
842 0 : session_add_to_gc_queue(s);
843 0 : user_add_to_gc_queue(s->user);
844 :
845 0 : if (s->started) {
846 0 : session_send_signal(s, false);
847 0 : s->started = false;
848 : }
849 :
850 0 : if (s->seat) {
851 0 : if (s->seat->active == s)
852 0 : seat_set_active(s->seat, NULL);
853 :
854 0 : seat_save(s->seat);
855 : }
856 :
857 0 : user_save(s->user);
858 0 : user_send_changed(s->user, "Display", NULL);
859 :
860 0 : return 0;
861 : }
862 :
863 0 : static int release_timeout_callback(sd_event_source *es, uint64_t usec, void *userdata) {
864 0 : Session *s = userdata;
865 :
866 0 : assert(es);
867 0 : assert(s);
868 :
869 0 : session_stop(s, false);
870 0 : return 0;
871 : }
872 :
873 0 : int session_release(Session *s) {
874 0 : assert(s);
875 :
876 0 : if (!s->started || s->stopping)
877 0 : return 0;
878 :
879 0 : if (s->timer_event_source)
880 0 : return 0;
881 :
882 0 : return sd_event_add_time(s->manager->event,
883 : &s->timer_event_source,
884 : CLOCK_MONOTONIC,
885 : usec_add(now(CLOCK_MONOTONIC), RELEASE_USEC), 0,
886 : release_timeout_callback, s);
887 : }
888 :
889 0 : bool session_is_active(Session *s) {
890 0 : assert(s);
891 :
892 0 : if (!s->seat)
893 0 : return true;
894 :
895 0 : return s->seat->active == s;
896 : }
897 :
898 0 : static int get_tty_atime(const char *tty, usec_t *atime) {
899 0 : _cleanup_free_ char *p = NULL;
900 : struct stat st;
901 :
902 0 : assert(tty);
903 0 : assert(atime);
904 :
905 0 : if (!path_is_absolute(tty)) {
906 0 : p = path_join("/dev", tty);
907 0 : if (!p)
908 0 : return -ENOMEM;
909 :
910 0 : tty = p;
911 0 : } else if (!path_startswith(tty, "/dev/"))
912 0 : return -ENOENT;
913 :
914 0 : if (lstat(tty, &st) < 0)
915 0 : return -errno;
916 :
917 0 : *atime = timespec_load(&st.st_atim);
918 0 : return 0;
919 : }
920 :
921 0 : static int get_process_ctty_atime(pid_t pid, usec_t *atime) {
922 0 : _cleanup_free_ char *p = NULL;
923 : int r;
924 :
925 0 : assert(pid > 0);
926 0 : assert(atime);
927 :
928 0 : r = get_ctty(pid, NULL, &p);
929 0 : if (r < 0)
930 0 : return r;
931 :
932 0 : return get_tty_atime(p, atime);
933 : }
934 :
935 0 : int session_get_idle_hint(Session *s, dual_timestamp *t) {
936 0 : usec_t atime = 0, n;
937 : int r;
938 :
939 0 : assert(s);
940 :
941 : /* Explicit idle hint is set */
942 0 : if (s->idle_hint) {
943 0 : if (t)
944 0 : *t = s->idle_hint_timestamp;
945 :
946 0 : return s->idle_hint;
947 : }
948 :
949 : /* Graphical sessions should really implement a real
950 : * idle hint logic */
951 0 : if (SESSION_TYPE_IS_GRAPHICAL(s->type))
952 0 : goto dont_know;
953 :
954 : /* For sessions with an explicitly configured tty, let's check
955 : * its atime */
956 0 : if (s->tty) {
957 0 : r = get_tty_atime(s->tty, &atime);
958 0 : if (r >= 0)
959 0 : goto found_atime;
960 : }
961 :
962 : /* For sessions with a leader but no explicitly configured
963 : * tty, let's check the controlling tty of the leader */
964 0 : if (pid_is_valid(s->leader)) {
965 0 : r = get_process_ctty_atime(s->leader, &atime);
966 0 : if (r >= 0)
967 0 : goto found_atime;
968 : }
969 :
970 0 : dont_know:
971 0 : if (t)
972 0 : *t = s->idle_hint_timestamp;
973 :
974 0 : return 0;
975 :
976 0 : found_atime:
977 0 : if (t)
978 0 : dual_timestamp_from_realtime(t, atime);
979 :
980 0 : n = now(CLOCK_REALTIME);
981 :
982 0 : if (s->manager->idle_action_usec <= 0)
983 0 : return 0;
984 :
985 0 : return atime + s->manager->idle_action_usec <= n;
986 : }
987 :
988 0 : void session_set_idle_hint(Session *s, bool b) {
989 0 : assert(s);
990 :
991 0 : if (s->idle_hint == b)
992 0 : return;
993 :
994 0 : s->idle_hint = b;
995 0 : dual_timestamp_get(&s->idle_hint_timestamp);
996 :
997 0 : session_send_changed(s, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
998 :
999 0 : if (s->seat)
1000 0 : seat_send_changed(s->seat, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
1001 :
1002 0 : user_send_changed(s->user, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
1003 0 : manager_send_changed(s->manager, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
1004 : }
1005 :
1006 0 : int session_get_locked_hint(Session *s) {
1007 0 : assert(s);
1008 :
1009 0 : return s->locked_hint;
1010 : }
1011 :
1012 0 : void session_set_locked_hint(Session *s, bool b) {
1013 0 : assert(s);
1014 :
1015 0 : if (s->locked_hint == b)
1016 0 : return;
1017 :
1018 0 : s->locked_hint = b;
1019 :
1020 0 : session_send_changed(s, "LockedHint", NULL);
1021 : }
1022 :
1023 0 : static int session_dispatch_fifo(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
1024 0 : Session *s = userdata;
1025 :
1026 0 : assert(s);
1027 0 : assert(s->fifo_fd == fd);
1028 :
1029 : /* EOF on the FIFO means the session died abnormally. */
1030 :
1031 0 : session_remove_fifo(s);
1032 0 : session_stop(s, false);
1033 :
1034 0 : return 1;
1035 : }
1036 :
1037 0 : int session_create_fifo(Session *s) {
1038 : int r;
1039 :
1040 0 : assert(s);
1041 :
1042 : /* Create FIFO */
1043 0 : if (!s->fifo_path) {
1044 0 : r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0, MKDIR_WARN_MODE);
1045 0 : if (r < 0)
1046 0 : return r;
1047 :
1048 0 : s->fifo_path = strjoin("/run/systemd/sessions/", s->id, ".ref");
1049 0 : if (!s->fifo_path)
1050 0 : return -ENOMEM;
1051 :
1052 0 : if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
1053 0 : return -errno;
1054 : }
1055 :
1056 : /* Open reading side */
1057 0 : if (s->fifo_fd < 0) {
1058 0 : s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
1059 0 : if (s->fifo_fd < 0)
1060 0 : return -errno;
1061 : }
1062 :
1063 0 : if (!s->fifo_event_source) {
1064 0 : r = sd_event_add_io(s->manager->event, &s->fifo_event_source, s->fifo_fd, 0, session_dispatch_fifo, s);
1065 0 : if (r < 0)
1066 0 : return r;
1067 :
1068 : /* Let's make sure we noticed dead sessions before we process new bus requests (which might create new
1069 : * sessions). */
1070 0 : r = sd_event_source_set_priority(s->fifo_event_source, SD_EVENT_PRIORITY_NORMAL-10);
1071 0 : if (r < 0)
1072 0 : return r;
1073 : }
1074 :
1075 : /* Open writing side */
1076 0 : r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NONBLOCK);
1077 0 : if (r < 0)
1078 0 : return -errno;
1079 :
1080 0 : return r;
1081 : }
1082 :
1083 0 : static void session_remove_fifo(Session *s) {
1084 0 : assert(s);
1085 :
1086 0 : s->fifo_event_source = sd_event_source_unref(s->fifo_event_source);
1087 0 : s->fifo_fd = safe_close(s->fifo_fd);
1088 :
1089 0 : if (s->fifo_path) {
1090 0 : (void) unlink(s->fifo_path);
1091 0 : s->fifo_path = mfree(s->fifo_path);
1092 : }
1093 0 : }
1094 :
1095 0 : bool session_may_gc(Session *s, bool drop_not_started) {
1096 : int r;
1097 :
1098 0 : assert(s);
1099 :
1100 0 : if (drop_not_started && !s->started)
1101 0 : return true;
1102 :
1103 0 : if (!s->user)
1104 0 : return true;
1105 :
1106 0 : if (s->fifo_fd >= 0) {
1107 0 : if (pipe_eof(s->fifo_fd) <= 0)
1108 0 : return false;
1109 : }
1110 :
1111 0 : if (s->scope_job) {
1112 0 : _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1113 :
1114 0 : r = manager_job_is_active(s->manager, s->scope_job, &error);
1115 0 : if (r < 0)
1116 0 : log_debug_errno(r, "Failed to determine whether job '%s' is pending, ignoring: %s", s->scope_job, bus_error_message(&error, r));
1117 0 : if (r != 0)
1118 0 : return false;
1119 : }
1120 :
1121 0 : if (s->scope) {
1122 0 : _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1123 :
1124 0 : r = manager_unit_is_active(s->manager, s->scope, &error);
1125 0 : if (r < 0)
1126 0 : log_debug_errno(r, "Failed to determine whether unit '%s' is active, ignoring: %s", s->scope, bus_error_message(&error, r));
1127 0 : if (r != 0)
1128 0 : return false;
1129 : }
1130 :
1131 0 : return true;
1132 : }
1133 :
1134 0 : void session_add_to_gc_queue(Session *s) {
1135 0 : assert(s);
1136 :
1137 0 : if (s->in_gc_queue)
1138 0 : return;
1139 :
1140 0 : LIST_PREPEND(gc_queue, s->manager->session_gc_queue, s);
1141 0 : s->in_gc_queue = true;
1142 : }
1143 :
1144 0 : SessionState session_get_state(Session *s) {
1145 0 : assert(s);
1146 :
1147 : /* always check closing first */
1148 0 : if (s->stopping || s->timer_event_source)
1149 0 : return SESSION_CLOSING;
1150 :
1151 0 : if (s->scope_job || s->fifo_fd < 0)
1152 0 : return SESSION_OPENING;
1153 :
1154 0 : if (session_is_active(s))
1155 0 : return SESSION_ACTIVE;
1156 :
1157 0 : return SESSION_ONLINE;
1158 : }
1159 :
1160 0 : int session_kill(Session *s, KillWho who, int signo) {
1161 0 : assert(s);
1162 :
1163 0 : if (!s->scope)
1164 0 : return -ESRCH;
1165 :
1166 0 : return manager_kill_unit(s->manager, s->scope, who, signo, NULL);
1167 : }
1168 :
1169 0 : static int session_open_vt(Session *s) {
1170 : char path[sizeof("/dev/tty") + DECIMAL_STR_MAX(s->vtnr)];
1171 :
1172 0 : if (s->vtnr < 1)
1173 0 : return -ENODEV;
1174 :
1175 0 : if (s->vtfd >= 0)
1176 0 : return s->vtfd;
1177 :
1178 0 : sprintf(path, "/dev/tty%u", s->vtnr);
1179 0 : s->vtfd = open_terminal(path, O_RDWR | O_CLOEXEC | O_NONBLOCK | O_NOCTTY);
1180 0 : if (s->vtfd < 0)
1181 0 : return log_error_errno(s->vtfd, "cannot open VT %s of session %s: %m", path, s->id);
1182 :
1183 0 : return s->vtfd;
1184 : }
1185 :
1186 0 : int session_prepare_vt(Session *s) {
1187 : int vt, r;
1188 0 : struct vt_mode mode = {};
1189 :
1190 0 : if (s->vtnr < 1)
1191 0 : return 0;
1192 :
1193 0 : vt = session_open_vt(s);
1194 0 : if (vt < 0)
1195 0 : return vt;
1196 :
1197 0 : r = fchown(vt, s->user->uid, -1);
1198 0 : if (r < 0) {
1199 0 : r = log_error_errno(errno,
1200 : "Cannot change owner of /dev/tty%u: %m",
1201 : s->vtnr);
1202 0 : goto error;
1203 : }
1204 :
1205 0 : r = ioctl(vt, KDSKBMODE, K_OFF);
1206 0 : if (r < 0) {
1207 0 : r = log_error_errno(errno,
1208 : "Cannot set K_OFF on /dev/tty%u: %m",
1209 : s->vtnr);
1210 0 : goto error;
1211 : }
1212 :
1213 0 : r = ioctl(vt, KDSETMODE, KD_GRAPHICS);
1214 0 : if (r < 0) {
1215 0 : r = log_error_errno(errno,
1216 : "Cannot set KD_GRAPHICS on /dev/tty%u: %m",
1217 : s->vtnr);
1218 0 : goto error;
1219 : }
1220 :
1221 : /* Oh, thanks to the VT layer, VT_AUTO does not work with KD_GRAPHICS.
1222 : * So we need a dummy handler here which just acknowledges *all* VT
1223 : * switch requests. */
1224 0 : mode.mode = VT_PROCESS;
1225 0 : mode.relsig = SIGRTMIN;
1226 0 : mode.acqsig = SIGRTMIN + 1;
1227 0 : r = ioctl(vt, VT_SETMODE, &mode);
1228 0 : if (r < 0) {
1229 0 : r = log_error_errno(errno,
1230 : "Cannot set VT_PROCESS on /dev/tty%u: %m",
1231 : s->vtnr);
1232 0 : goto error;
1233 : }
1234 :
1235 0 : return 0;
1236 :
1237 0 : error:
1238 0 : session_restore_vt(s);
1239 0 : return r;
1240 : }
1241 :
1242 0 : static void session_restore_vt(Session *s) {
1243 : int r, vt, old_fd;
1244 :
1245 : /* We need to get a fresh handle to the virtual terminal,
1246 : * since the old file-descriptor is potentially in a hung-up
1247 : * state after the controlling process exited; we do a
1248 : * little dance to avoid having the terminal be available
1249 : * for reuse before we've cleaned it up.
1250 : */
1251 0 : old_fd = TAKE_FD(s->vtfd);
1252 :
1253 0 : vt = session_open_vt(s);
1254 0 : safe_close(old_fd);
1255 :
1256 0 : if (vt < 0)
1257 0 : return;
1258 :
1259 0 : r = vt_restore(vt);
1260 0 : if (r < 0)
1261 0 : log_warning_errno(r, "Failed to restore VT, ignoring: %m");
1262 :
1263 0 : s->vtfd = safe_close(s->vtfd);
1264 : }
1265 :
1266 0 : void session_leave_vt(Session *s) {
1267 : int r;
1268 :
1269 0 : assert(s);
1270 :
1271 : /* This is called whenever we get a VT-switch signal from the kernel.
1272 : * We acknowledge all of them unconditionally. Note that session are
1273 : * free to overwrite those handlers and we only register them for
1274 : * sessions with controllers. Legacy sessions are not affected.
1275 : * However, if we switch from a non-legacy to a legacy session, we must
1276 : * make sure to pause all device before acknowledging the switch. We
1277 : * process the real switch only after we are notified via sysfs, so the
1278 : * legacy session might have already started using the devices. If we
1279 : * don't pause the devices before the switch, we might confuse the
1280 : * session we switch to. */
1281 :
1282 0 : if (s->vtfd < 0)
1283 0 : return;
1284 :
1285 0 : session_device_pause_all(s);
1286 0 : r = vt_release(s->vtfd, false);
1287 0 : if (r < 0)
1288 0 : log_debug_errno(r, "Cannot release VT of session %s: %m", s->id);
1289 : }
1290 :
1291 0 : bool session_is_controller(Session *s, const char *sender) {
1292 0 : assert(s);
1293 :
1294 0 : return streq_ptr(s->controller, sender);
1295 : }
1296 :
1297 0 : static void session_release_controller(Session *s, bool notify) {
1298 0 : _cleanup_free_ char *name = NULL;
1299 : SessionDevice *sd;
1300 :
1301 0 : if (!s->controller)
1302 0 : return;
1303 :
1304 0 : name = s->controller;
1305 :
1306 : /* By resetting the controller before releasing the devices, we won't
1307 : * send notification signals. This avoids sending useless notifications
1308 : * if the controller is released on disconnects. */
1309 0 : if (!notify)
1310 0 : s->controller = NULL;
1311 :
1312 0 : while ((sd = hashmap_first(s->devices)))
1313 0 : session_device_free(sd);
1314 :
1315 0 : s->controller = NULL;
1316 0 : s->track = sd_bus_track_unref(s->track);
1317 : }
1318 :
1319 0 : static int on_bus_track(sd_bus_track *track, void *userdata) {
1320 0 : Session *s = userdata;
1321 :
1322 0 : assert(track);
1323 0 : assert(s);
1324 :
1325 0 : session_drop_controller(s);
1326 :
1327 0 : return 0;
1328 : }
1329 :
1330 0 : int session_set_controller(Session *s, const char *sender, bool force, bool prepare) {
1331 0 : _cleanup_free_ char *name = NULL;
1332 : int r;
1333 :
1334 0 : assert(s);
1335 0 : assert(sender);
1336 :
1337 0 : if (session_is_controller(s, sender))
1338 0 : return 0;
1339 0 : if (s->controller && !force)
1340 0 : return -EBUSY;
1341 :
1342 0 : name = strdup(sender);
1343 0 : if (!name)
1344 0 : return -ENOMEM;
1345 :
1346 0 : s->track = sd_bus_track_unref(s->track);
1347 0 : r = sd_bus_track_new(s->manager->bus, &s->track, on_bus_track, s);
1348 0 : if (r < 0)
1349 0 : return r;
1350 :
1351 0 : r = sd_bus_track_add_name(s->track, name);
1352 0 : if (r < 0)
1353 0 : return r;
1354 :
1355 : /* When setting a session controller, we forcibly mute the VT and set
1356 : * it into graphics-mode. Applications can override that by changing
1357 : * VT state after calling TakeControl(). However, this serves as a good
1358 : * default and well-behaving controllers can now ignore VTs entirely.
1359 : * Note that we reset the VT on ReleaseControl() and if the controller
1360 : * exits.
1361 : * If logind crashes/restarts, we restore the controller during restart
1362 : * (without preparing the VT since the controller has probably overridden
1363 : * VT state by now) or reset the VT in case it crashed/exited, too. */
1364 0 : if (prepare) {
1365 0 : r = session_prepare_vt(s);
1366 0 : if (r < 0) {
1367 0 : s->track = sd_bus_track_unref(s->track);
1368 0 : return r;
1369 : }
1370 : }
1371 :
1372 0 : session_release_controller(s, true);
1373 0 : s->controller = TAKE_PTR(name);
1374 0 : session_save(s);
1375 :
1376 0 : return 0;
1377 : }
1378 :
1379 0 : void session_drop_controller(Session *s) {
1380 0 : assert(s);
1381 :
1382 0 : if (!s->controller)
1383 0 : return;
1384 :
1385 0 : s->track = sd_bus_track_unref(s->track);
1386 0 : session_release_controller(s, false);
1387 0 : session_save(s);
1388 0 : session_restore_vt(s);
1389 : }
1390 :
1391 : static const char* const session_state_table[_SESSION_STATE_MAX] = {
1392 : [SESSION_OPENING] = "opening",
1393 : [SESSION_ONLINE] = "online",
1394 : [SESSION_ACTIVE] = "active",
1395 : [SESSION_CLOSING] = "closing"
1396 : };
1397 :
1398 12 : DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
1399 :
1400 : static const char* const session_type_table[_SESSION_TYPE_MAX] = {
1401 : [SESSION_UNSPECIFIED] = "unspecified",
1402 : [SESSION_TTY] = "tty",
1403 : [SESSION_X11] = "x11",
1404 : [SESSION_WAYLAND] = "wayland",
1405 : [SESSION_MIR] = "mir",
1406 : [SESSION_WEB] = "web",
1407 : };
1408 :
1409 16 : DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
1410 :
1411 : static const char* const session_class_table[_SESSION_CLASS_MAX] = {
1412 : [SESSION_USER] = "user",
1413 : [SESSION_GREETER] = "greeter",
1414 : [SESSION_LOCK_SCREEN] = "lock-screen",
1415 : [SESSION_BACKGROUND] = "background"
1416 : };
1417 :
1418 12 : DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
1419 :
1420 : static const char* const kill_who_table[_KILL_WHO_MAX] = {
1421 : [KILL_LEADER] = "leader",
1422 : [KILL_ALL] = "all"
1423 : };
1424 :
1425 8 : DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);
1426 :
1427 : static const char* const tty_validity_table[_TTY_VALIDITY_MAX] = {
1428 : [TTY_FROM_PAM] = "from-pam",
1429 : [TTY_FROM_UTMP] = "from-utmp",
1430 : [TTY_UTMP_INCONSISTENT] = "utmp-inconsistent",
1431 : };
1432 :
1433 0 : DEFINE_STRING_TABLE_LOOKUP(tty_validity, TTYValidity);
|