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