1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <errno.h>
4 #include <unistd.h>
5
6 #include "alloc-util.h"
7 #include "bus-common-errors.h"
8 #include "bus-error.h"
9 #include "bus-util.h"
10 #include "cgroup-util.h"
11 #include "clean-ipc.h"
12 #include "env-file.h"
13 #include "escape.h"
14 #include "fd-util.h"
15 #include "fileio.h"
16 #include "format-util.h"
17 #include "fs-util.h"
18 #include "hashmap.h"
19 #include "label.h"
20 #include "limits-util.h"
21 #include "logind-dbus.h"
22 #include "logind-user-dbus.h"
23 #include "logind-user.h"
24 #include "mkdir-label.h"
25 #include "parse-util.h"
26 #include "path-util.h"
27 #include "percent-util.h"
28 #include "rm-rf.h"
29 #include "serialize.h"
30 #include "special.h"
31 #include "stdio-util.h"
32 #include "string-table.h"
33 #include "strv.h"
34 #include "tmpfile-util.h"
35 #include "uid-alloc-range.h"
36 #include "unit-name.h"
37 #include "user-util.h"
38 #include "util.h"
39
user_new(User ** ret,Manager * m,UserRecord * ur)40 int user_new(User **ret,
41 Manager *m,
42 UserRecord *ur) {
43
44 _cleanup_(user_freep) User *u = NULL;
45 char lu[DECIMAL_STR_MAX(uid_t) + 1];
46 int r;
47
48 assert(ret);
49 assert(m);
50 assert(ur);
51
52 if (!ur->user_name)
53 return -EINVAL;
54
55 if (!uid_is_valid(ur->uid))
56 return -EINVAL;
57
58 u = new(User, 1);
59 if (!u)
60 return -ENOMEM;
61
62 *u = (User) {
63 .manager = m,
64 .user_record = user_record_ref(ur),
65 .last_session_timestamp = USEC_INFINITY,
66 };
67
68 if (asprintf(&u->state_file, "/run/systemd/users/" UID_FMT, ur->uid) < 0)
69 return -ENOMEM;
70
71 if (asprintf(&u->runtime_path, "/run/user/" UID_FMT, ur->uid) < 0)
72 return -ENOMEM;
73
74 xsprintf(lu, UID_FMT, ur->uid);
75 r = slice_build_subslice(SPECIAL_USER_SLICE, lu, &u->slice);
76 if (r < 0)
77 return r;
78
79 r = unit_name_build("user", lu, ".service", &u->service);
80 if (r < 0)
81 return r;
82
83 r = unit_name_build("user-runtime-dir", lu, ".service", &u->runtime_dir_service);
84 if (r < 0)
85 return r;
86
87 r = hashmap_put(m->users, UID_TO_PTR(ur->uid), u);
88 if (r < 0)
89 return r;
90
91 r = hashmap_put(m->user_units, u->slice, u);
92 if (r < 0)
93 return r;
94
95 r = hashmap_put(m->user_units, u->service, u);
96 if (r < 0)
97 return r;
98
99 r = hashmap_put(m->user_units, u->runtime_dir_service, u);
100 if (r < 0)
101 return r;
102
103 *ret = TAKE_PTR(u);
104 return 0;
105 }
106
user_free(User * u)107 User *user_free(User *u) {
108 if (!u)
109 return NULL;
110
111 if (u->in_gc_queue)
112 LIST_REMOVE(gc_queue, u->manager->user_gc_queue, u);
113
114 while (u->sessions)
115 session_free(u->sessions);
116
117 if (u->service)
118 hashmap_remove_value(u->manager->user_units, u->service, u);
119
120 if (u->runtime_dir_service)
121 hashmap_remove_value(u->manager->user_units, u->runtime_dir_service, u);
122
123 if (u->slice)
124 hashmap_remove_value(u->manager->user_units, u->slice, u);
125
126 hashmap_remove_value(u->manager->users, UID_TO_PTR(u->user_record->uid), u);
127
128 sd_event_source_unref(u->timer_event_source);
129
130 u->service_job = mfree(u->service_job);
131
132 u->service = mfree(u->service);
133 u->runtime_dir_service = mfree(u->runtime_dir_service);
134 u->slice = mfree(u->slice);
135 u->runtime_path = mfree(u->runtime_path);
136 u->state_file = mfree(u->state_file);
137
138 user_record_unref(u->user_record);
139
140 return mfree(u);
141 }
142
user_save_internal(User * u)143 static int user_save_internal(User *u) {
144 _cleanup_free_ char *temp_path = NULL;
145 _cleanup_fclose_ FILE *f = NULL;
146 int r;
147
148 assert(u);
149 assert(u->state_file);
150
151 r = mkdir_safe_label("/run/systemd/users", 0755, 0, 0, MKDIR_WARN_MODE);
152 if (r < 0)
153 goto fail;
154
155 r = fopen_temporary(u->state_file, &f, &temp_path);
156 if (r < 0)
157 goto fail;
158
159 (void) fchmod(fileno(f), 0644);
160
161 fprintf(f,
162 "# This is private data. Do not parse.\n"
163 "NAME=%s\n"
164 "STATE=%s\n" /* friendly user-facing state */
165 "STOPPING=%s\n", /* low-level state */
166 u->user_record->user_name,
167 user_state_to_string(user_get_state(u)),
168 yes_no(u->stopping));
169
170 /* LEGACY: no-one reads RUNTIME= anymore, drop it at some point */
171 if (u->runtime_path)
172 fprintf(f, "RUNTIME=%s\n", u->runtime_path);
173
174 if (u->service_job)
175 fprintf(f, "SERVICE_JOB=%s\n", u->service_job);
176
177 if (u->display)
178 fprintf(f, "DISPLAY=%s\n", u->display->id);
179
180 if (dual_timestamp_is_set(&u->timestamp))
181 fprintf(f,
182 "REALTIME="USEC_FMT"\n"
183 "MONOTONIC="USEC_FMT"\n",
184 u->timestamp.realtime,
185 u->timestamp.monotonic);
186
187 if (u->last_session_timestamp != USEC_INFINITY)
188 fprintf(f, "LAST_SESSION_TIMESTAMP=" USEC_FMT "\n",
189 u->last_session_timestamp);
190
191 if (u->sessions) {
192 bool first;
193
194 fputs("SESSIONS=", f);
195 first = true;
196 LIST_FOREACH(sessions_by_user, i, u->sessions) {
197 if (first)
198 first = false;
199 else
200 fputc(' ', f);
201
202 fputs(i->id, f);
203 }
204
205 fputs("\nSEATS=", f);
206 first = true;
207 LIST_FOREACH(sessions_by_user, i, u->sessions) {
208 if (!i->seat)
209 continue;
210
211 if (first)
212 first = false;
213 else
214 fputc(' ', f);
215
216 fputs(i->seat->id, f);
217 }
218
219 fputs("\nACTIVE_SESSIONS=", f);
220 first = true;
221 LIST_FOREACH(sessions_by_user, i, u->sessions) {
222 if (!session_is_active(i))
223 continue;
224
225 if (first)
226 first = false;
227 else
228 fputc(' ', f);
229
230 fputs(i->id, f);
231 }
232
233 fputs("\nONLINE_SESSIONS=", f);
234 first = true;
235 LIST_FOREACH(sessions_by_user, i, u->sessions) {
236 if (session_get_state(i) == SESSION_CLOSING)
237 continue;
238
239 if (first)
240 first = false;
241 else
242 fputc(' ', f);
243
244 fputs(i->id, f);
245 }
246
247 fputs("\nACTIVE_SEATS=", f);
248 first = true;
249 LIST_FOREACH(sessions_by_user, i, u->sessions) {
250 if (!session_is_active(i) || !i->seat)
251 continue;
252
253 if (first)
254 first = false;
255 else
256 fputc(' ', f);
257
258 fputs(i->seat->id, f);
259 }
260
261 fputs("\nONLINE_SEATS=", f);
262 first = true;
263 LIST_FOREACH(sessions_by_user, i, u->sessions) {
264 if (session_get_state(i) == SESSION_CLOSING || !i->seat)
265 continue;
266
267 if (first)
268 first = false;
269 else
270 fputc(' ', f);
271
272 fputs(i->seat->id, f);
273 }
274 fputc('\n', f);
275 }
276
277 r = fflush_and_check(f);
278 if (r < 0)
279 goto fail;
280
281 if (rename(temp_path, u->state_file) < 0) {
282 r = -errno;
283 goto fail;
284 }
285
286 return 0;
287
288 fail:
289 (void) unlink(u->state_file);
290
291 if (temp_path)
292 (void) unlink(temp_path);
293
294 return log_error_errno(r, "Failed to save user data %s: %m", u->state_file);
295 }
296
user_save(User * u)297 int user_save(User *u) {
298 assert(u);
299
300 if (!u->started)
301 return 0;
302
303 return user_save_internal(u);
304 }
305
user_load(User * u)306 int user_load(User *u) {
307 _cleanup_free_ char *realtime = NULL, *monotonic = NULL, *stopping = NULL, *last_session_timestamp = NULL;
308 int r;
309
310 assert(u);
311
312 r = parse_env_file(NULL, u->state_file,
313 "SERVICE_JOB", &u->service_job,
314 "STOPPING", &stopping,
315 "REALTIME", &realtime,
316 "MONOTONIC", &monotonic,
317 "LAST_SESSION_TIMESTAMP", &last_session_timestamp);
318 if (r == -ENOENT)
319 return 0;
320 if (r < 0)
321 return log_error_errno(r, "Failed to read %s: %m", u->state_file);
322
323 if (stopping) {
324 r = parse_boolean(stopping);
325 if (r < 0)
326 log_debug_errno(r, "Failed to parse 'STOPPING' boolean: %s", stopping);
327 else
328 u->stopping = r;
329 }
330
331 if (realtime)
332 (void) deserialize_usec(realtime, &u->timestamp.realtime);
333 if (monotonic)
334 (void) deserialize_usec(monotonic, &u->timestamp.monotonic);
335 if (last_session_timestamp)
336 (void) deserialize_usec(last_session_timestamp, &u->last_session_timestamp);
337
338 return 0;
339 }
340
user_start_service(User * u)341 static void user_start_service(User *u) {
342 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
343 int r;
344
345 assert(u);
346
347 /* Start the service containing the "systemd --user" instance (user@.service). Note that we don't explicitly
348 * start the per-user slice or the systemd-runtime-dir@.service instance, as those are pulled in both by
349 * user@.service and the session scopes as dependencies. */
350
351 u->service_job = mfree(u->service_job);
352
353 r = manager_start_unit(u->manager, u->service, &error, &u->service_job);
354 if (r < 0)
355 log_full_errno(sd_bus_error_has_name(&error, BUS_ERROR_UNIT_MASKED) ? LOG_DEBUG : LOG_WARNING, r,
356 "Failed to start user service '%s', ignoring: %s", u->service, bus_error_message(&error, r));
357 }
358
update_slice_callback(sd_bus_message * m,void * userdata,sd_bus_error * ret_error)359 static int update_slice_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
360 _cleanup_(user_record_unrefp) UserRecord *ur = userdata;
361 const sd_bus_error *e;
362 int r;
363
364 assert(m);
365 assert(ur);
366
367 e = sd_bus_message_get_error(m);
368 if (e) {
369 r = sd_bus_error_get_errno(e);
370 log_warning_errno(r,
371 "Failed to update slice of %s, ignoring: %s",
372 ur->user_name,
373 bus_error_message(e, r));
374
375 return 0;
376 }
377
378 log_debug("Successfully set slice parameters of %s.", ur->user_name);
379 return 0;
380 }
381
user_update_slice(User * u)382 static int user_update_slice(User *u) {
383 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
384 int r;
385
386 assert(u);
387
388 if (u->user_record->tasks_max == UINT64_MAX &&
389 u->user_record->memory_high == UINT64_MAX &&
390 u->user_record->memory_max == UINT64_MAX &&
391 u->user_record->cpu_weight == UINT64_MAX &&
392 u->user_record->io_weight == UINT64_MAX)
393 return 0;
394
395 r = sd_bus_message_new_method_call(
396 u->manager->bus,
397 &m,
398 "org.freedesktop.systemd1",
399 "/org/freedesktop/systemd1",
400 "org.freedesktop.systemd1.Manager",
401 "SetUnitProperties");
402 if (r < 0)
403 return bus_log_create_error(r);
404
405 r = sd_bus_message_append(m, "sb", u->slice, true);
406 if (r < 0)
407 return bus_log_create_error(r);
408
409 r = sd_bus_message_open_container(m, 'a', "(sv)");
410 if (r < 0)
411 return bus_log_create_error(r);
412
413 const struct {
414 const char *name;
415 uint64_t value;
416 } settings[] = {
417 { "TasksMax", u->user_record->tasks_max },
418 { "MemoryMax", u->user_record->memory_max },
419 { "MemoryHigh", u->user_record->memory_high },
420 { "CPUWeight", u->user_record->cpu_weight },
421 { "IOWeight", u->user_record->io_weight },
422 };
423
424 for (size_t i = 0; i < ELEMENTSOF(settings); i++)
425 if (settings[i].value != UINT64_MAX) {
426 r = sd_bus_message_append(m, "(sv)", settings[i].name, "t", settings[i].value);
427 if (r < 0)
428 return bus_log_create_error(r);
429 }
430
431 r = sd_bus_message_close_container(m);
432 if (r < 0)
433 return bus_log_create_error(r);
434
435 r = sd_bus_call_async(u->manager->bus, NULL, m, update_slice_callback, u->user_record, 0);
436 if (r < 0)
437 return log_error_errno(r, "Failed to change user slice properties: %m");
438
439 /* Ref the user record pointer, so that the slot keeps it pinned */
440 user_record_ref(u->user_record);
441
442 return 0;
443 }
444
user_start(User * u)445 int user_start(User *u) {
446 assert(u);
447
448 if (u->started && !u->stopping)
449 return 0;
450
451 /* If u->stopping is set, the user is marked for removal and service stop-jobs are queued. We have to clear
452 * that flag before queueing the start-jobs again. If they succeed, the user object can be re-used just fine
453 * (pid1 takes care of job-ordering and proper restart), but if they fail, we want to force another user_stop()
454 * so possibly pending units are stopped. */
455 u->stopping = false;
456
457 if (!u->started)
458 log_debug("Starting services for new user %s.", u->user_record->user_name);
459
460 /* Save the user data so far, because pam_systemd will read the XDG_RUNTIME_DIR out of it while starting up
461 * systemd --user. We need to do user_save_internal() because we have not "officially" started yet. */
462 user_save_internal(u);
463
464 /* Set slice parameters */
465 (void) user_update_slice(u);
466
467 /* Start user@UID.service */
468 user_start_service(u);
469
470 if (!u->started) {
471 if (!dual_timestamp_is_set(&u->timestamp))
472 dual_timestamp_get(&u->timestamp);
473 user_send_signal(u, true);
474 u->started = true;
475 }
476
477 /* Save new user data */
478 user_save(u);
479
480 return 0;
481 }
482
user_stop_service(User * u,bool force)483 static void user_stop_service(User *u, bool force) {
484 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
485 int r;
486
487 assert(u);
488 assert(u->service);
489
490 /* The reverse of user_start_service(). Note that we only stop user@UID.service here, and let StopWhenUnneeded=
491 * deal with the slice and the user-runtime-dir@.service instance. */
492
493 u->service_job = mfree(u->service_job);
494
495 r = manager_stop_unit(u->manager, u->service, force ? "replace" : "fail", &error, &u->service_job);
496 if (r < 0)
497 log_warning_errno(r, "Failed to stop user service '%s', ignoring: %s", u->service, bus_error_message(&error, r));
498 }
499
user_stop(User * u,bool force)500 int user_stop(User *u, bool force) {
501 int r = 0;
502
503 assert(u);
504
505 /* This is called whenever we begin with tearing down a user record. It's called in two cases: explicit API
506 * request to do so via the bus (in which case 'force' is true) and automatically due to GC, if there's no
507 * session left pinning it (in which case 'force' is false). Note that this just initiates tearing down of the
508 * user, the User object will remain in memory until user_finalize() is called, see below. */
509
510 if (!u->started)
511 return 0;
512
513 if (u->stopping) { /* Stop jobs have already been queued */
514 user_save(u);
515 return 0;
516 }
517
518 LIST_FOREACH(sessions_by_user, s, u->sessions) {
519 int k;
520
521 k = session_stop(s, force);
522 if (k < 0)
523 r = k;
524 }
525
526 user_stop_service(u, force);
527
528 u->stopping = true;
529
530 user_save(u);
531
532 return r;
533 }
534
user_finalize(User * u)535 int user_finalize(User *u) {
536 int r = 0, k;
537
538 assert(u);
539
540 /* Called when the user is really ready to be freed, i.e. when all unit stop jobs and suchlike for it are
541 * done. This is called as a result of an earlier user_done() when all jobs are completed. */
542
543 if (u->started)
544 log_debug("User %s logged out.", u->user_record->user_name);
545
546 LIST_FOREACH(sessions_by_user, s, u->sessions) {
547 k = session_finalize(s);
548 if (k < 0)
549 r = k;
550 }
551
552 /* Clean SysV + POSIX IPC objects, but only if this is not a system user. Background: in many setups cronjobs
553 * are run in full PAM and thus logind sessions, even if the code run doesn't belong to actual users but to
554 * system components. Since enable RemoveIPC= globally for all users, we need to be a bit careful with such
555 * cases, as we shouldn't accidentally remove a system service's IPC objects while it is running, just because
556 * a cronjob running as the same user just finished. Hence: exclude system users generally from IPC clean-up,
557 * and do it only for normal users. */
558 if (u->manager->remove_ipc && !uid_is_system(u->user_record->uid)) {
559 k = clean_ipc_by_uid(u->user_record->uid);
560 if (k < 0)
561 r = k;
562 }
563
564 (void) unlink(u->state_file);
565 user_add_to_gc_queue(u);
566
567 if (u->started) {
568 user_send_signal(u, false);
569 u->started = false;
570 }
571
572 return r;
573 }
574
user_get_idle_hint(User * u,dual_timestamp * t)575 int user_get_idle_hint(User *u, dual_timestamp *t) {
576 bool idle_hint = true;
577 dual_timestamp ts = DUAL_TIMESTAMP_NULL;
578
579 assert(u);
580
581 LIST_FOREACH(sessions_by_user, s, u->sessions) {
582 dual_timestamp k;
583 int ih;
584
585 ih = session_get_idle_hint(s, &k);
586 if (ih < 0)
587 return ih;
588
589 if (!ih) {
590 if (!idle_hint) {
591 if (k.monotonic < ts.monotonic)
592 ts = k;
593 } else {
594 idle_hint = false;
595 ts = k;
596 }
597 } else if (idle_hint) {
598
599 if (k.monotonic > ts.monotonic)
600 ts = k;
601 }
602 }
603
604 if (t)
605 *t = ts;
606
607 return idle_hint;
608 }
609
user_check_linger_file(User * u)610 int user_check_linger_file(User *u) {
611 _cleanup_free_ char *cc = NULL;
612 char *p = NULL;
613
614 cc = cescape(u->user_record->user_name);
615 if (!cc)
616 return -ENOMEM;
617
618 p = strjoina("/var/lib/systemd/linger/", cc);
619 if (access(p, F_OK) < 0) {
620 if (errno != ENOENT)
621 return -errno;
622
623 return false;
624 }
625
626 return true;
627 }
628
user_unit_active(User * u)629 static bool user_unit_active(User *u) {
630 int r;
631
632 assert(u->service);
633 assert(u->runtime_dir_service);
634 assert(u->slice);
635
636 FOREACH_STRING(i, u->service, u->runtime_dir_service, u->slice) {
637 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
638
639 r = manager_unit_is_active(u->manager, i, &error);
640 if (r < 0)
641 log_debug_errno(r, "Failed to determine whether unit '%s' is active, ignoring: %s", i, bus_error_message(&error, r));
642 if (r != 0)
643 return true;
644 }
645
646 return false;
647 }
648
user_get_stop_delay(User * u)649 static usec_t user_get_stop_delay(User *u) {
650 assert(u);
651
652 if (u->user_record->stop_delay_usec != UINT64_MAX)
653 return u->user_record->stop_delay_usec;
654
655 if (user_record_removable(u->user_record) > 0)
656 return 0; /* For removable users lower the stop delay to zero */
657
658 return u->manager->user_stop_delay;
659 }
660
user_may_gc(User * u,bool drop_not_started)661 bool user_may_gc(User *u, bool drop_not_started) {
662 int r;
663
664 assert(u);
665
666 if (drop_not_started && !u->started)
667 return true;
668
669 if (u->sessions)
670 return false;
671
672 if (u->last_session_timestamp != USEC_INFINITY) {
673 usec_t user_stop_delay;
674
675 /* All sessions have been closed. Let's see if we shall leave the user record around for a bit */
676
677 user_stop_delay = user_get_stop_delay(u);
678
679 if (user_stop_delay == USEC_INFINITY)
680 return false; /* Leave it around forever! */
681 if (user_stop_delay > 0 &&
682 now(CLOCK_MONOTONIC) < usec_add(u->last_session_timestamp, user_stop_delay))
683 return false; /* Leave it around for a bit longer. */
684 }
685
686 /* Is this a user that shall stay around forever ("linger")? Before we say "no" to GC'ing for lingering users, let's check
687 * if any of the three units that we maintain for this user is still around. If none of them is,
688 * there's no need to keep this user around even if lingering is enabled. */
689 if (user_check_linger_file(u) > 0 && user_unit_active(u))
690 return false;
691
692 /* Check if our job is still pending */
693 if (u->service_job) {
694 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
695
696 r = manager_job_is_active(u->manager, u->service_job, &error);
697 if (r < 0)
698 log_debug_errno(r, "Failed to determine whether job '%s' is pending, ignoring: %s", u->service_job, bus_error_message(&error, r));
699 if (r != 0)
700 return false;
701 }
702
703 /* Note that we don't care if the three units we manage for each user object are up or not, as we are managing
704 * their state rather than tracking it. */
705
706 return true;
707 }
708
user_add_to_gc_queue(User * u)709 void user_add_to_gc_queue(User *u) {
710 assert(u);
711
712 if (u->in_gc_queue)
713 return;
714
715 LIST_PREPEND(gc_queue, u->manager->user_gc_queue, u);
716 u->in_gc_queue = true;
717 }
718
user_get_state(User * u)719 UserState user_get_state(User *u) {
720 assert(u);
721
722 if (u->stopping)
723 return USER_CLOSING;
724
725 if (!u->started || u->service_job)
726 return USER_OPENING;
727
728 if (u->sessions) {
729 bool all_closing = true;
730
731 LIST_FOREACH(sessions_by_user, i, u->sessions) {
732 SessionState state;
733
734 state = session_get_state(i);
735 if (state == SESSION_ACTIVE)
736 return USER_ACTIVE;
737 if (state != SESSION_CLOSING)
738 all_closing = false;
739 }
740
741 return all_closing ? USER_CLOSING : USER_ONLINE;
742 }
743
744 if (user_check_linger_file(u) > 0 && user_unit_active(u))
745 return USER_LINGERING;
746
747 return USER_CLOSING;
748 }
749
user_kill(User * u,int signo)750 int user_kill(User *u, int signo) {
751 assert(u);
752
753 return manager_kill_unit(u->manager, u->slice, KILL_ALL, signo, NULL);
754 }
755
elect_display_filter(Session * s)756 static bool elect_display_filter(Session *s) {
757 /* Return true if the session is a candidate for the user’s ‘primary session’ or ‘display’. */
758 assert(s);
759
760 return IN_SET(s->class, SESSION_USER, SESSION_GREETER) && s->started && !s->stopping;
761 }
762
elect_display_compare(Session * s1,Session * s2)763 static int elect_display_compare(Session *s1, Session *s2) {
764 /* Indexed by SessionType. Lower numbers mean more preferred. */
765 static const int type_ranks[_SESSION_TYPE_MAX] = {
766 [SESSION_UNSPECIFIED] = 0,
767 [SESSION_TTY] = -2,
768 [SESSION_X11] = -3,
769 [SESSION_WAYLAND] = -3,
770 [SESSION_MIR] = -3,
771 [SESSION_WEB] = -1,
772 };
773
774 /* Calculate the partial order relationship between s1 and s2,
775 * returning < 0 if s1 is preferred as the user’s ‘primary session’,
776 * 0 if s1 and s2 are equally preferred or incomparable, or > 0 if s2
777 * is preferred.
778 *
779 * s1 or s2 may be NULL. */
780 if (!s1 && !s2)
781 return 0;
782
783 if ((s1 == NULL) != (s2 == NULL))
784 return (s1 == NULL) - (s2 == NULL);
785
786 if (s1->stopping != s2->stopping)
787 return s1->stopping - s2->stopping;
788
789 if ((s1->class != SESSION_USER) != (s2->class != SESSION_USER))
790 return (s1->class != SESSION_USER) - (s2->class != SESSION_USER);
791
792 if ((s1->type == _SESSION_TYPE_INVALID) != (s2->type == _SESSION_TYPE_INVALID))
793 return (s1->type == _SESSION_TYPE_INVALID) - (s2->type == _SESSION_TYPE_INVALID);
794
795 if (s1->type != s2->type)
796 return type_ranks[s1->type] - type_ranks[s2->type];
797
798 return 0;
799 }
800
user_elect_display(User * u)801 void user_elect_display(User *u) {
802 assert(u);
803
804 /* This elects a primary session for each user, which we call the "display". We try to keep the assignment
805 * stable, but we "upgrade" to better choices. */
806 log_debug("Electing new display for user %s", u->user_record->user_name);
807
808 LIST_FOREACH(sessions_by_user, s, u->sessions) {
809 if (!elect_display_filter(s)) {
810 log_debug("Ignoring session %s", s->id);
811 continue;
812 }
813
814 if (elect_display_compare(s, u->display) < 0) {
815 log_debug("Choosing session %s in preference to %s", s->id, u->display ? u->display->id : "-");
816 u->display = s;
817 }
818 }
819 }
820
user_stop_timeout_callback(sd_event_source * es,uint64_t usec,void * userdata)821 static int user_stop_timeout_callback(sd_event_source *es, uint64_t usec, void *userdata) {
822 User *u = userdata;
823
824 assert(u);
825 user_add_to_gc_queue(u);
826
827 return 0;
828 }
829
user_update_last_session_timer(User * u)830 void user_update_last_session_timer(User *u) {
831 usec_t user_stop_delay;
832 int r;
833
834 assert(u);
835
836 if (u->sessions) {
837 /* There are sessions, turn off the timer */
838 u->last_session_timestamp = USEC_INFINITY;
839 u->timer_event_source = sd_event_source_unref(u->timer_event_source);
840 return;
841 }
842
843 if (u->last_session_timestamp != USEC_INFINITY)
844 return; /* Timer already started */
845
846 u->last_session_timestamp = now(CLOCK_MONOTONIC);
847
848 assert(!u->timer_event_source);
849
850 user_stop_delay = user_get_stop_delay(u);
851 if (!timestamp_is_set(user_stop_delay))
852 return;
853
854 if (sd_event_get_state(u->manager->event) == SD_EVENT_FINISHED) {
855 log_debug("Not allocating user stop timeout, since we are already exiting.");
856 return;
857 }
858
859 r = sd_event_add_time(u->manager->event,
860 &u->timer_event_source,
861 CLOCK_MONOTONIC,
862 usec_add(u->last_session_timestamp, user_stop_delay), 0,
863 user_stop_timeout_callback, u);
864 if (r < 0)
865 log_warning_errno(r, "Failed to enqueue user stop event source, ignoring: %m");
866
867 if (DEBUG_LOGGING)
868 log_debug("Last session of user '%s' logged out, terminating user context in %s.",
869 u->user_record->user_name,
870 FORMAT_TIMESPAN(user_stop_delay, USEC_PER_MSEC));
871 }
872
873 static const char* const user_state_table[_USER_STATE_MAX] = {
874 [USER_OFFLINE] = "offline",
875 [USER_OPENING] = "opening",
876 [USER_LINGERING] = "lingering",
877 [USER_ONLINE] = "online",
878 [USER_ACTIVE] = "active",
879 [USER_CLOSING] = "closing"
880 };
881
882 DEFINE_STRING_TABLE_LOOKUP(user_state, UserState);
883
config_parse_tmpfs_size(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)884 int config_parse_tmpfs_size(
885 const char* unit,
886 const char *filename,
887 unsigned line,
888 const char *section,
889 unsigned section_line,
890 const char *lvalue,
891 int ltype,
892 const char *rvalue,
893 void *data,
894 void *userdata) {
895
896 uint64_t *sz = data;
897 int r;
898
899 assert(filename);
900 assert(lvalue);
901 assert(rvalue);
902 assert(data);
903
904 /* First, try to parse as percentage */
905 r = parse_permyriad(rvalue);
906 if (r > 0)
907 *sz = physical_memory_scale(r, 10000U);
908 else {
909 uint64_t k;
910
911 /* If the passed argument was not a percentage, or out of range, parse as byte size */
912
913 r = parse_size(rvalue, 1024, &k);
914 if (r >= 0 && (k <= 0 || (uint64_t) (size_t) k != k))
915 r = -ERANGE;
916 if (r < 0) {
917 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse size value '%s', ignoring: %m", rvalue);
918 return 0;
919 }
920
921 *sz = PAGE_ALIGN((size_t) k);
922 }
923
924 return 0;
925 }
926
config_parse_compat_user_tasks_max(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)927 int config_parse_compat_user_tasks_max(
928 const char *unit,
929 const char *filename,
930 unsigned line,
931 const char *section,
932 unsigned section_line,
933 const char *lvalue,
934 int ltype,
935 const char *rvalue,
936 void *data,
937 void *userdata) {
938
939 assert(filename);
940 assert(lvalue);
941 assert(rvalue);
942
943 log_syntax(unit, LOG_NOTICE, filename, line, 0,
944 "Support for option %s= has been removed.",
945 lvalue);
946 log_info("Hint: try creating /etc/systemd/system/user-.slice.d/50-limits.conf with:\n"
947 " [Slice]\n"
948 " TasksMax=%s",
949 rvalue);
950 return 0;
951 }
952