]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/login/logind-user.c
util-lib: split out fd-related operations into fd-util.[ch]
[thirdparty/systemd.git] / src / login / logind-user.c
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
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
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
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <errno.h>
23 #include <string.h>
24 #include <sys/mount.h>
25 #include <unistd.h>
26
27 #include "bus-error.h"
28 #include "bus-util.h"
29 #include "clean-ipc.h"
30 #include "conf-parser.h"
31 #include "escape.h"
32 #include "fd-util.h"
33 #include "fileio.h"
34 #include "formats-util.h"
35 #include "hashmap.h"
36 #include "label.h"
37 #include "logind-user.h"
38 #include "mkdir.h"
39 #include "path-util.h"
40 #include "rm-rf.h"
41 #include "smack-util.h"
42 #include "special.h"
43 #include "unit-name.h"
44 #include "util.h"
45
46 User* user_new(Manager *m, uid_t uid, gid_t gid, const char *name) {
47 User *u;
48
49 assert(m);
50 assert(name);
51
52 u = new0(User, 1);
53 if (!u)
54 return NULL;
55
56 u->name = strdup(name);
57 if (!u->name)
58 goto fail;
59
60 if (asprintf(&u->state_file, "/run/systemd/users/"UID_FMT, uid) < 0)
61 goto fail;
62
63 if (hashmap_put(m->users, UID_TO_PTR(uid), u) < 0)
64 goto fail;
65
66 u->manager = m;
67 u->uid = uid;
68 u->gid = gid;
69
70 return u;
71
72 fail:
73 free(u->state_file);
74 free(u->name);
75 free(u);
76
77 return NULL;
78 }
79
80 void user_free(User *u) {
81 assert(u);
82
83 if (u->in_gc_queue)
84 LIST_REMOVE(gc_queue, u->manager->user_gc_queue, u);
85
86 while (u->sessions)
87 session_free(u->sessions);
88
89 if (u->slice) {
90 hashmap_remove(u->manager->user_units, u->slice);
91 free(u->slice);
92 }
93
94 if (u->service) {
95 hashmap_remove(u->manager->user_units, u->service);
96 free(u->service);
97 }
98
99 free(u->slice_job);
100 free(u->service_job);
101
102 free(u->runtime_path);
103
104 hashmap_remove(u->manager->users, UID_TO_PTR(u->uid));
105
106 free(u->name);
107 free(u->state_file);
108 free(u);
109 }
110
111 static int user_save_internal(User *u) {
112 _cleanup_free_ char *temp_path = NULL;
113 _cleanup_fclose_ FILE *f = NULL;
114 int r;
115
116 assert(u);
117 assert(u->state_file);
118
119 r = mkdir_safe_label("/run/systemd/users", 0755, 0, 0);
120 if (r < 0)
121 goto fail;
122
123 r = fopen_temporary(u->state_file, &f, &temp_path);
124 if (r < 0)
125 goto fail;
126
127 fchmod(fileno(f), 0644);
128
129 fprintf(f,
130 "# This is private data. Do not parse.\n"
131 "NAME=%s\n"
132 "STATE=%s\n",
133 u->name,
134 user_state_to_string(user_get_state(u)));
135
136 if (u->runtime_path)
137 fprintf(f, "RUNTIME=%s\n", u->runtime_path);
138
139 if (u->service)
140 fprintf(f, "SERVICE=%s\n", u->service);
141 if (u->service_job)
142 fprintf(f, "SERVICE_JOB=%s\n", u->service_job);
143
144 if (u->slice)
145 fprintf(f, "SLICE=%s\n", u->slice);
146 if (u->slice_job)
147 fprintf(f, "SLICE_JOB=%s\n", u->slice_job);
148
149 if (u->display)
150 fprintf(f, "DISPLAY=%s\n", u->display->id);
151
152 if (dual_timestamp_is_set(&u->timestamp))
153 fprintf(f,
154 "REALTIME="USEC_FMT"\n"
155 "MONOTONIC="USEC_FMT"\n",
156 u->timestamp.realtime,
157 u->timestamp.monotonic);
158
159 if (u->sessions) {
160 Session *i;
161 bool first;
162
163 fputs("SESSIONS=", f);
164 first = true;
165 LIST_FOREACH(sessions_by_user, i, u->sessions) {
166 if (first)
167 first = false;
168 else
169 fputc(' ', f);
170
171 fputs(i->id, f);
172 }
173
174 fputs("\nSEATS=", f);
175 first = true;
176 LIST_FOREACH(sessions_by_user, i, u->sessions) {
177 if (!i->seat)
178 continue;
179
180 if (first)
181 first = false;
182 else
183 fputc(' ', f);
184
185 fputs(i->seat->id, f);
186 }
187
188 fputs("\nACTIVE_SESSIONS=", f);
189 first = true;
190 LIST_FOREACH(sessions_by_user, i, u->sessions) {
191 if (!session_is_active(i))
192 continue;
193
194 if (first)
195 first = false;
196 else
197 fputc(' ', f);
198
199 fputs(i->id, f);
200 }
201
202 fputs("\nONLINE_SESSIONS=", f);
203 first = true;
204 LIST_FOREACH(sessions_by_user, i, u->sessions) {
205 if (session_get_state(i) == SESSION_CLOSING)
206 continue;
207
208 if (first)
209 first = false;
210 else
211 fputc(' ', f);
212
213 fputs(i->id, f);
214 }
215
216 fputs("\nACTIVE_SEATS=", f);
217 first = true;
218 LIST_FOREACH(sessions_by_user, i, u->sessions) {
219 if (!session_is_active(i) || !i->seat)
220 continue;
221
222 if (first)
223 first = false;
224 else
225 fputc(' ', f);
226
227 fputs(i->seat->id, f);
228 }
229
230 fputs("\nONLINE_SEATS=", f);
231 first = true;
232 LIST_FOREACH(sessions_by_user, i, u->sessions) {
233 if (session_get_state(i) == SESSION_CLOSING || !i->seat)
234 continue;
235
236 if (first)
237 first = false;
238 else
239 fputc(' ', f);
240
241 fputs(i->seat->id, f);
242 }
243 fputc('\n', f);
244 }
245
246 r = fflush_and_check(f);
247 if (r < 0)
248 goto fail;
249
250 if (rename(temp_path, u->state_file) < 0) {
251 r = -errno;
252 goto fail;
253 }
254
255 return 0;
256
257 fail:
258 (void) unlink(u->state_file);
259
260 if (temp_path)
261 (void) unlink(temp_path);
262
263 return log_error_errno(r, "Failed to save user data %s: %m", u->state_file);
264 }
265
266 int user_save(User *u) {
267 assert(u);
268
269 if (!u->started)
270 return 0;
271
272 return user_save_internal (u);
273 }
274
275 int user_load(User *u) {
276 _cleanup_free_ char *display = NULL, *realtime = NULL, *monotonic = NULL;
277 Session *s = NULL;
278 int r;
279
280 assert(u);
281
282 r = parse_env_file(u->state_file, NEWLINE,
283 "RUNTIME", &u->runtime_path,
284 "SERVICE", &u->service,
285 "SERVICE_JOB", &u->service_job,
286 "SLICE", &u->slice,
287 "SLICE_JOB", &u->slice_job,
288 "DISPLAY", &display,
289 "REALTIME", &realtime,
290 "MONOTONIC", &monotonic,
291 NULL);
292 if (r < 0) {
293 if (r == -ENOENT)
294 return 0;
295
296 log_error_errno(r, "Failed to read %s: %m", u->state_file);
297 return r;
298 }
299
300 if (display)
301 s = hashmap_get(u->manager->sessions, display);
302
303 if (s && s->display && display_is_local(s->display))
304 u->display = s;
305
306 if (realtime) {
307 unsigned long long l;
308 if (sscanf(realtime, "%llu", &l) > 0)
309 u->timestamp.realtime = l;
310 }
311
312 if (monotonic) {
313 unsigned long long l;
314 if (sscanf(monotonic, "%llu", &l) > 0)
315 u->timestamp.monotonic = l;
316 }
317
318 return r;
319 }
320
321 static int user_mkdir_runtime_path(User *u) {
322 char *p;
323 int r;
324
325 assert(u);
326
327 r = mkdir_safe_label("/run/user", 0755, 0, 0);
328 if (r < 0)
329 return log_error_errno(r, "Failed to create /run/user: %m");
330
331 if (!u->runtime_path) {
332 if (asprintf(&p, "/run/user/" UID_FMT, u->uid) < 0)
333 return log_oom();
334 } else
335 p = u->runtime_path;
336
337 if (path_is_mount_point(p, 0) <= 0) {
338 _cleanup_free_ char *t = NULL;
339
340 (void) mkdir_label(p, 0700);
341
342 if (mac_smack_use())
343 r = asprintf(&t, "mode=0700,smackfsroot=*,uid=" UID_FMT ",gid=" GID_FMT ",size=%zu", u->uid, u->gid, u->manager->runtime_dir_size);
344 else
345 r = asprintf(&t, "mode=0700,uid=" UID_FMT ",gid=" GID_FMT ",size=%zu", u->uid, u->gid, u->manager->runtime_dir_size);
346 if (r < 0) {
347 r = log_oom();
348 goto fail;
349 }
350
351 r = mount("tmpfs", p, "tmpfs", MS_NODEV|MS_NOSUID, t);
352 if (r < 0) {
353 if (errno != EPERM) {
354 r = log_error_errno(errno, "Failed to mount per-user tmpfs directory %s: %m", p);
355 goto fail;
356 }
357
358 /* Lacking permissions, maybe
359 * CAP_SYS_ADMIN-less container? In this case,
360 * just use a normal directory. */
361
362 r = chmod_and_chown(p, 0700, u->uid, u->gid);
363 if (r < 0) {
364 log_error_errno(r, "Failed to change runtime directory ownership and mode: %m");
365 goto fail;
366 }
367 }
368
369 r = label_fix(p, false, false);
370 if (r < 0)
371 log_warning_errno(r, "Failed to fix label of '%s', ignoring: %m", p);
372 }
373
374 u->runtime_path = p;
375 return 0;
376
377 fail:
378 if (p) {
379 /* Try to clean up, but ignore errors */
380 (void) rmdir(p);
381 free(p);
382 }
383
384 u->runtime_path = NULL;
385 return r;
386 }
387
388 static int user_start_slice(User *u) {
389 char *job;
390 int r;
391
392 assert(u);
393
394 if (!u->slice) {
395 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
396 char lu[DECIMAL_STR_MAX(uid_t) + 1], *slice;
397 sprintf(lu, UID_FMT, u->uid);
398
399 r = slice_build_subslice(SPECIAL_USER_SLICE, lu, &slice);
400 if (r < 0)
401 return r;
402
403 r = manager_start_unit(u->manager, slice, &error, &job);
404 if (r < 0) {
405 log_error("Failed to start user slice: %s", bus_error_message(&error, r));
406 free(slice);
407 } else {
408 u->slice = slice;
409
410 free(u->slice_job);
411 u->slice_job = job;
412 }
413 }
414
415 if (u->slice)
416 hashmap_put(u->manager->user_units, u->slice, u);
417
418 return 0;
419 }
420
421 static int user_start_service(User *u) {
422 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
423 char *job;
424 int r;
425
426 assert(u);
427
428 if (!u->service) {
429 char lu[DECIMAL_STR_MAX(uid_t) + 1], *service;
430 sprintf(lu, UID_FMT, u->uid);
431
432 r = unit_name_build("user", lu, ".service", &service);
433 if (r < 0)
434 return log_error_errno(r, "Failed to build service name: %m");
435
436 r = manager_start_unit(u->manager, service, &error, &job);
437 if (r < 0) {
438 log_error("Failed to start user service: %s", bus_error_message(&error, r));
439 free(service);
440 } else {
441 u->service = service;
442
443 free(u->service_job);
444 u->service_job = job;
445 }
446 }
447
448 if (u->service)
449 hashmap_put(u->manager->user_units, u->service, u);
450
451 return 0;
452 }
453
454 int user_start(User *u) {
455 int r;
456
457 assert(u);
458
459 if (u->started)
460 return 0;
461
462 log_debug("New user %s logged in.", u->name);
463
464 /* Make XDG_RUNTIME_DIR */
465 r = user_mkdir_runtime_path(u);
466 if (r < 0)
467 return r;
468
469 /* Create cgroup */
470 r = user_start_slice(u);
471 if (r < 0)
472 return r;
473
474 /* Save the user data so far, because pam_systemd will read the
475 * XDG_RUNTIME_DIR out of it while starting up systemd --user.
476 * We need to do user_save_internal() because we have not
477 * "officially" started yet. */
478 user_save_internal(u);
479
480 /* Spawn user systemd */
481 r = user_start_service(u);
482 if (r < 0)
483 return r;
484
485 if (!dual_timestamp_is_set(&u->timestamp))
486 dual_timestamp_get(&u->timestamp);
487
488 u->started = true;
489
490 /* Save new user data */
491 user_save(u);
492
493 user_send_signal(u, true);
494
495 return 0;
496 }
497
498 static int user_stop_slice(User *u) {
499 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
500 char *job;
501 int r;
502
503 assert(u);
504
505 if (!u->slice)
506 return 0;
507
508 r = manager_stop_unit(u->manager, u->slice, &error, &job);
509 if (r < 0) {
510 log_error("Failed to stop user slice: %s", bus_error_message(&error, r));
511 return r;
512 }
513
514 free(u->slice_job);
515 u->slice_job = job;
516
517 return r;
518 }
519
520 static int user_stop_service(User *u) {
521 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
522 char *job;
523 int r;
524
525 assert(u);
526
527 if (!u->service)
528 return 0;
529
530 r = manager_stop_unit(u->manager, u->service, &error, &job);
531 if (r < 0) {
532 log_error("Failed to stop user service: %s", bus_error_message(&error, r));
533 return r;
534 }
535
536 free(u->service_job);
537 u->service_job = job;
538
539 return r;
540 }
541
542 static int user_remove_runtime_path(User *u) {
543 int r;
544
545 assert(u);
546
547 if (!u->runtime_path)
548 return 0;
549
550 r = rm_rf(u->runtime_path, 0);
551 if (r < 0)
552 log_error_errno(r, "Failed to remove runtime directory %s: %m", u->runtime_path);
553
554 /* Ignore cases where the directory isn't mounted, as that's
555 * quite possible, if we lacked the permissions to mount
556 * something */
557 r = umount2(u->runtime_path, MNT_DETACH);
558 if (r < 0 && errno != EINVAL && errno != ENOENT)
559 log_error_errno(errno, "Failed to unmount user runtime directory %s: %m", u->runtime_path);
560
561 r = rm_rf(u->runtime_path, REMOVE_ROOT);
562 if (r < 0)
563 log_error_errno(r, "Failed to remove runtime directory %s: %m", u->runtime_path);
564
565 u->runtime_path = mfree(u->runtime_path);
566
567 return r;
568 }
569
570 int user_stop(User *u, bool force) {
571 Session *s;
572 int r = 0, k;
573 assert(u);
574
575 /* Stop jobs have already been queued */
576 if (u->stopping) {
577 user_save(u);
578 return r;
579 }
580
581 LIST_FOREACH(sessions_by_user, s, u->sessions) {
582 k = session_stop(s, force);
583 if (k < 0)
584 r = k;
585 }
586
587 /* Kill systemd */
588 k = user_stop_service(u);
589 if (k < 0)
590 r = k;
591
592 /* Kill cgroup */
593 k = user_stop_slice(u);
594 if (k < 0)
595 r = k;
596
597 u->stopping = true;
598
599 user_save(u);
600
601 return r;
602 }
603
604 int user_finalize(User *u) {
605 Session *s;
606 int r = 0, k;
607
608 assert(u);
609
610 if (u->started)
611 log_debug("User %s logged out.", u->name);
612
613 LIST_FOREACH(sessions_by_user, s, u->sessions) {
614 k = session_finalize(s);
615 if (k < 0)
616 r = k;
617 }
618
619 /* Kill XDG_RUNTIME_DIR */
620 k = user_remove_runtime_path(u);
621 if (k < 0)
622 r = k;
623
624 /* Clean SysV + POSIX IPC objects */
625 if (u->manager->remove_ipc) {
626 k = clean_ipc(u->uid);
627 if (k < 0)
628 r = k;
629 }
630
631 unlink(u->state_file);
632 user_add_to_gc_queue(u);
633
634 if (u->started) {
635 user_send_signal(u, false);
636 u->started = false;
637 }
638
639 return r;
640 }
641
642 int user_get_idle_hint(User *u, dual_timestamp *t) {
643 Session *s;
644 bool idle_hint = true;
645 dual_timestamp ts = DUAL_TIMESTAMP_NULL;
646
647 assert(u);
648
649 LIST_FOREACH(sessions_by_user, s, u->sessions) {
650 dual_timestamp k;
651 int ih;
652
653 ih = session_get_idle_hint(s, &k);
654 if (ih < 0)
655 return ih;
656
657 if (!ih) {
658 if (!idle_hint) {
659 if (k.monotonic < ts.monotonic)
660 ts = k;
661 } else {
662 idle_hint = false;
663 ts = k;
664 }
665 } else if (idle_hint) {
666
667 if (k.monotonic > ts.monotonic)
668 ts = k;
669 }
670 }
671
672 if (t)
673 *t = ts;
674
675 return idle_hint;
676 }
677
678 int user_check_linger_file(User *u) {
679 _cleanup_free_ char *cc = NULL;
680 char *p = NULL;
681
682 cc = cescape(u->name);
683 if (!cc)
684 return -ENOMEM;
685
686 p = strjoina("/var/lib/systemd/linger/", cc);
687
688 return access(p, F_OK) >= 0;
689 }
690
691 bool user_check_gc(User *u, bool drop_not_started) {
692 assert(u);
693
694 if (drop_not_started && !u->started)
695 return false;
696
697 if (u->sessions)
698 return true;
699
700 if (user_check_linger_file(u) > 0)
701 return true;
702
703 if (u->slice_job && manager_job_is_active(u->manager, u->slice_job))
704 return true;
705
706 if (u->service_job && manager_job_is_active(u->manager, u->service_job))
707 return true;
708
709 return false;
710 }
711
712 void user_add_to_gc_queue(User *u) {
713 assert(u);
714
715 if (u->in_gc_queue)
716 return;
717
718 LIST_PREPEND(gc_queue, u->manager->user_gc_queue, u);
719 u->in_gc_queue = true;
720 }
721
722 UserState user_get_state(User *u) {
723 Session *i;
724
725 assert(u);
726
727 if (u->stopping)
728 return USER_CLOSING;
729
730 if (!u->started || u->slice_job || u->service_job)
731 return USER_OPENING;
732
733 if (u->sessions) {
734 bool all_closing = true;
735
736 LIST_FOREACH(sessions_by_user, i, u->sessions) {
737 SessionState state;
738
739 state = session_get_state(i);
740 if (state == SESSION_ACTIVE)
741 return USER_ACTIVE;
742 if (state != SESSION_CLOSING)
743 all_closing = false;
744 }
745
746 return all_closing ? USER_CLOSING : USER_ONLINE;
747 }
748
749 if (user_check_linger_file(u) > 0)
750 return USER_LINGERING;
751
752 return USER_CLOSING;
753 }
754
755 int user_kill(User *u, int signo) {
756 assert(u);
757
758 if (!u->slice)
759 return -ESRCH;
760
761 return manager_kill_unit(u->manager, u->slice, KILL_ALL, signo, NULL);
762 }
763
764 static bool elect_display_filter(Session *s) {
765 /* Return true if the session is a candidate for the user’s ‘primary
766 * session’ or ‘display’. */
767 assert(s);
768
769 return (s->class == SESSION_USER && !s->stopping);
770 }
771
772 static int elect_display_compare(Session *s1, Session *s2) {
773 /* Indexed by SessionType. Lower numbers mean more preferred. */
774 const int type_ranks[_SESSION_TYPE_MAX] = {
775 [SESSION_UNSPECIFIED] = 0,
776 [SESSION_TTY] = -2,
777 [SESSION_X11] = -3,
778 [SESSION_WAYLAND] = -3,
779 [SESSION_MIR] = -3,
780 [SESSION_WEB] = -1,
781 };
782
783 /* Calculate the partial order relationship between s1 and s2,
784 * returning < 0 if s1 is preferred as the user’s ‘primary session’,
785 * 0 if s1 and s2 are equally preferred or incomparable, or > 0 if s2
786 * is preferred.
787 *
788 * s1 or s2 may be NULL. */
789 if (!s1 && !s2)
790 return 0;
791
792 if ((s1 == NULL) != (s2 == NULL))
793 return (s1 == NULL) - (s2 == NULL);
794
795 if (s1->stopping != s2->stopping)
796 return s1->stopping - s2->stopping;
797
798 if ((s1->class != SESSION_USER) != (s2->class != SESSION_USER))
799 return (s1->class != SESSION_USER) - (s2->class != SESSION_USER);
800
801 if ((s1->type == _SESSION_TYPE_INVALID) != (s2->type == _SESSION_TYPE_INVALID))
802 return (s1->type == _SESSION_TYPE_INVALID) - (s2->type == _SESSION_TYPE_INVALID);
803
804 if (s1->type != s2->type)
805 return type_ranks[s1->type] - type_ranks[s2->type];
806
807 return 0;
808 }
809
810 void user_elect_display(User *u) {
811 Session *s;
812
813 assert(u);
814
815 /* This elects a primary session for each user, which we call
816 * the "display". We try to keep the assignment stable, but we
817 * "upgrade" to better choices. */
818 log_debug("Electing new display for user %s", u->name);
819
820 LIST_FOREACH(sessions_by_user, s, u->sessions) {
821 if (!elect_display_filter(s)) {
822 log_debug("Ignoring session %s", s->id);
823 continue;
824 }
825
826 if (elect_display_compare(s, u->display) < 0) {
827 log_debug("Choosing session %s in preference to %s", s->id, u->display ? u->display->id : "-");
828 u->display = s;
829 }
830 }
831 }
832
833 static const char* const user_state_table[_USER_STATE_MAX] = {
834 [USER_OFFLINE] = "offline",
835 [USER_OPENING] = "opening",
836 [USER_LINGERING] = "lingering",
837 [USER_ONLINE] = "online",
838 [USER_ACTIVE] = "active",
839 [USER_CLOSING] = "closing"
840 };
841
842 DEFINE_STRING_TABLE_LOOKUP(user_state, UserState);
843
844 int config_parse_tmpfs_size(
845 const char* unit,
846 const char *filename,
847 unsigned line,
848 const char *section,
849 unsigned section_line,
850 const char *lvalue,
851 int ltype,
852 const char *rvalue,
853 void *data,
854 void *userdata) {
855
856 size_t *sz = data;
857 const char *e;
858 int r;
859
860 assert(filename);
861 assert(lvalue);
862 assert(rvalue);
863 assert(data);
864
865 e = endswith(rvalue, "%");
866 if (e) {
867 unsigned long ul;
868 char *f;
869
870 errno = 0;
871 ul = strtoul(rvalue, &f, 10);
872 if (errno != 0 || f != e) {
873 log_syntax(unit, LOG_ERR, filename, line, errno, "Failed to parse percentage value, ignoring: %s", rvalue);
874 return 0;
875 }
876
877 if (ul <= 0 || ul >= 100) {
878 log_syntax(unit, LOG_ERR, filename, line, 0, "Percentage value out of range, ignoring: %s", rvalue);
879 return 0;
880 }
881
882 *sz = PAGE_ALIGN((size_t) ((physical_memory() * (uint64_t) ul) / (uint64_t) 100));
883 } else {
884 uint64_t k;
885
886 r = parse_size(rvalue, 1024, &k);
887 if (r < 0 || (uint64_t) (size_t) k != k) {
888 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
889 return 0;
890 }
891
892 *sz = PAGE_ALIGN((size_t) k);
893 }
894
895 return 0;
896 }