chiark / gitweb /
core: fix a potential mem leak
[elogind.git] / src / core / load-fragment.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2010 Lennart Poettering
7   Copyright 2012 Holger Hans Peter Freyther
8
9   systemd is free software; you can redistribute it and/or modify it
10   under the terms of the GNU Lesser General Public License as published by
11   the Free Software Foundation; either version 2.1 of the License, or
12   (at your option) any later version.
13
14   systemd is distributed in the hope that it will be useful, but
15   WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17   Lesser General Public License for more details.
18
19   You should have received a copy of the GNU Lesser General Public License
20   along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 ***/
22
23 #include <linux/oom.h>
24 #include <assert.h>
25 #include <errno.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <fcntl.h>
29 #include <sched.h>
30 #include <sys/prctl.h>
31 #include <sys/mount.h>
32 #include <linux/fs.h>
33 #include <sys/stat.h>
34 #include <sys/time.h>
35 #include <sys/resource.h>
36 #include <sys/types.h>
37 #include <grp.h>
38
39 #ifdef HAVE_SECCOMP
40 #include <seccomp.h>
41 #endif
42
43 #include "sd-messages.h"
44 #include "unit.h"
45 #include "strv.h"
46 #include "conf-parser.h"
47 #include "load-fragment.h"
48 #include "log.h"
49 #include "ioprio.h"
50 #include "securebits.h"
51 #include "missing.h"
52 #include "unit-name.h"
53 #include "unit-printf.h"
54 #include "utf8.h"
55 #include "path-util.h"
56 #include "env-util.h"
57 #include "cgroup.h"
58 #include "bus-util.h"
59 #include "bus-error.h"
60 #include "errno-list.h"
61 #include "af-list.h"
62
63 #ifdef HAVE_SECCOMP
64 #include "seccomp-util.h"
65 #endif
66
67 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
68 int config_parse_warn_compat(
69                 const char *unit,
70                 const char *filename,
71                 unsigned line,
72                 const char *section,
73                 unsigned section_line,
74                 const char *lvalue,
75                 int ltype,
76                 const char *rvalue,
77                 void *data,
78                 void *userdata) {
79
80         log_syntax(unit, LOG_DEBUG, filename, line, EINVAL,
81                    "Support for option %s= has been disabled at compile time and is ignored",
82                    lvalue);
83         return 0;
84 }
85 #endif
86
87 int config_parse_unit_deps(const char *unit,
88                            const char *filename,
89                            unsigned line,
90                            const char *section,
91                            unsigned section_line,
92                            const char *lvalue,
93                            int ltype,
94                            const char *rvalue,
95                            void *data,
96                            void *userdata) {
97
98         UnitDependency d = ltype;
99         Unit *u = userdata;
100         const char *word, *state;
101         size_t l;
102
103         assert(filename);
104         assert(lvalue);
105         assert(rvalue);
106
107         FOREACH_WORD_QUOTED(word, l, rvalue, state) {
108                 _cleanup_free_ char *t = NULL, *k = NULL;
109                 int r;
110
111                 t = strndup(word, l);
112                 if (!t)
113                         return log_oom();
114
115                 r = unit_name_printf(u, t, &k);
116                 if (r < 0) {
117                         log_syntax(unit, LOG_ERR, filename, line, -r,
118                                    "Failed to resolve specifiers, ignoring: %s", strerror(-r));
119                         continue;
120                 }
121
122                 r = unit_add_dependency_by_name(u, d, k, NULL, true);
123                 if (r < 0)
124                         log_syntax(unit, LOG_ERR, filename, line, -r,
125                                    "Failed to add dependency on %s, ignoring: %s", k, strerror(-r));
126         }
127         if (!isempty(state))
128                 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid syntax, ignoring.");
129
130         return 0;
131 }
132
133 int config_parse_unit_string_printf(const char *unit,
134                                     const char *filename,
135                                     unsigned line,
136                                     const char *section,
137                                     unsigned section_line,
138                                     const char *lvalue,
139                                     int ltype,
140                                     const char *rvalue,
141                                     void *data,
142                                     void *userdata) {
143
144         Unit *u = userdata;
145         _cleanup_free_ char *k = NULL;
146         int r;
147
148         assert(filename);
149         assert(lvalue);
150         assert(rvalue);
151         assert(u);
152
153         r = unit_full_printf(u, rvalue, &k);
154         if (r < 0)
155                 log_syntax(unit, LOG_ERR, filename, line, -r,
156                            "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
157
158         return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype,
159                                    k ? k : rvalue, data, userdata);
160 }
161
162 int config_parse_unit_strv_printf(const char *unit,
163                                   const char *filename,
164                                   unsigned line,
165                                   const char *section,
166                                   unsigned section_line,
167                                   const char *lvalue,
168                                   int ltype,
169                                   const char *rvalue,
170                                   void *data,
171                                   void *userdata) {
172
173         Unit *u = userdata;
174         _cleanup_free_ char *k = NULL;
175         int r;
176
177         assert(filename);
178         assert(lvalue);
179         assert(rvalue);
180         assert(u);
181
182         r = unit_full_printf(u, rvalue, &k);
183         if (r < 0)
184                 log_syntax(unit, LOG_ERR, filename, line, -r,
185                            "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
186
187         return config_parse_strv(unit, filename, line, section, section_line, lvalue, ltype,
188                                  k ? k : rvalue, data, userdata);
189 }
190
191 int config_parse_unit_path_printf(const char *unit,
192                                   const char *filename,
193                                   unsigned line,
194                                   const char *section,
195                                   unsigned section_line,
196                                   const char *lvalue,
197                                   int ltype,
198                                   const char *rvalue,
199                                   void *data,
200                                   void *userdata) {
201
202         _cleanup_free_ char *k = NULL;
203         Unit *u = userdata;
204         int r;
205
206         assert(filename);
207         assert(lvalue);
208         assert(rvalue);
209         assert(u);
210
211         r = unit_full_printf(u, rvalue, &k);
212         if (r < 0) {
213                 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
214                 return 0;
215         }
216
217         return config_parse_path(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
218 }
219
220 int config_parse_unit_path_strv_printf(
221                 const char *unit,
222                 const char *filename,
223                 unsigned line,
224                 const char *section,
225                 unsigned section_line,
226                 const char *lvalue,
227                 int ltype,
228                 const char *rvalue,
229                 void *data,
230                 void *userdata) {
231
232         char ***x = data;
233         const char *word, *state;
234         Unit *u = userdata;
235         size_t l;
236         int r;
237
238         assert(filename);
239         assert(lvalue);
240         assert(rvalue);
241         assert(u);
242
243         FOREACH_WORD_QUOTED(word, l, rvalue, state) {
244                 _cleanup_free_ char *k = NULL;
245                 char t[l+1];
246
247                 memcpy(t, word, l);
248                 t[l] = 0;
249
250                 r = unit_full_printf(u, t, &k);
251                 if (r < 0) {
252                         log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve unit specifiers on %s, ignoring: %s", t, strerror(-r));
253                         return 0;
254                 }
255
256                 if (!utf8_is_valid(k)) {
257                         log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
258                         return 0;
259                 }
260
261                 if (!path_is_absolute(k)) {
262                         log_syntax(unit, LOG_ERR, filename, line, -r, "Symlink path %s is not absolute, ignoring: %s", k, strerror(-r));
263                         return 0;
264                 }
265
266                 path_kill_slashes(k);
267
268                 r = strv_push(x, k);
269                 if (r < 0)
270                         return log_oom();
271
272                 k = NULL;
273         }
274         if (!isempty(state))
275                 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid syntax, ignoring.");
276
277         return 0;
278 }
279
280 int config_parse_socket_listen(const char *unit,
281                                const char *filename,
282                                unsigned line,
283                                const char *section,
284                                unsigned section_line,
285                                const char *lvalue,
286                                int ltype,
287                                const char *rvalue,
288                                void *data,
289                                void *userdata) {
290
291         SocketPort *p, *tail;
292         Socket *s;
293         int r;
294
295         assert(filename);
296         assert(lvalue);
297         assert(rvalue);
298         assert(data);
299
300         s = SOCKET(data);
301
302         if (isempty(rvalue)) {
303                 /* An empty assignment removes all ports */
304                 socket_free_ports(s);
305                 return 0;
306         }
307
308         p = new0(SocketPort, 1);
309         if (!p)
310                 return log_oom();
311
312         if (ltype != SOCKET_SOCKET) {
313
314                 p->type = ltype;
315                 r = unit_full_printf(UNIT(s), rvalue, &p->path);
316                 if (r < 0) {
317                         p->path = strdup(rvalue);
318                         if (!p->path) {
319                                 free(p);
320                                 return log_oom();
321                         } else
322                                 log_syntax(unit, LOG_ERR, filename, line, -r,
323                                            "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
324                 }
325
326                 path_kill_slashes(p->path);
327
328         } else if (streq(lvalue, "ListenNetlink")) {
329                 _cleanup_free_ char  *k = NULL;
330
331                 p->type = SOCKET_SOCKET;
332                 r = unit_full_printf(UNIT(s), rvalue, &k);
333                 if (r < 0)
334                         log_syntax(unit, LOG_ERR, filename, line, -r,
335                                    "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
336
337                 r = socket_address_parse_netlink(&p->address, k ? k : rvalue);
338                 if (r < 0) {
339                         log_syntax(unit, LOG_ERR, filename, line, -r,
340                                    "Failed to parse address value, ignoring: %s", rvalue);
341                         free(p);
342                         return 0;
343                 }
344
345         } else {
346                 _cleanup_free_ char *k = NULL;
347
348                 p->type = SOCKET_SOCKET;
349                 r = unit_full_printf(UNIT(s), rvalue, &k);
350                 if (r < 0)
351                         log_syntax(unit, LOG_ERR, filename, line, -r,
352                                    "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
353
354                 r = socket_address_parse(&p->address, k ? k : rvalue);
355                 if (r < 0) {
356                         log_syntax(unit, LOG_ERR, filename, line, -r,
357                                    "Failed to parse address value, ignoring: %s", rvalue);
358                         free(p);
359                         return 0;
360                 }
361
362                 if (streq(lvalue, "ListenStream"))
363                         p->address.type = SOCK_STREAM;
364                 else if (streq(lvalue, "ListenDatagram"))
365                         p->address.type = SOCK_DGRAM;
366                 else {
367                         assert(streq(lvalue, "ListenSequentialPacket"));
368                         p->address.type = SOCK_SEQPACKET;
369                 }
370
371                 if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
372                         log_syntax(unit, LOG_ERR, filename, line, ENOTSUP,
373                                    "Address family not supported, ignoring: %s", rvalue);
374                         free(p);
375                         return 0;
376                 }
377         }
378
379         p->fd = -1;
380         p->socket = s;
381
382         if (s->ports) {
383                 LIST_FIND_TAIL(port, s->ports, tail);
384                 LIST_INSERT_AFTER(port, s->ports, tail, p);
385         } else
386                 LIST_PREPEND(port, s->ports, p);
387
388         return 0;
389 }
390
391 int config_parse_socket_bind(const char *unit,
392                              const char *filename,
393                              unsigned line,
394                              const char *section,
395                              unsigned section_line,
396                              const char *lvalue,
397                              int ltype,
398                              const char *rvalue,
399                              void *data,
400                              void *userdata) {
401
402         Socket *s;
403         SocketAddressBindIPv6Only b;
404
405         assert(filename);
406         assert(lvalue);
407         assert(rvalue);
408         assert(data);
409
410         s = SOCKET(data);
411
412         b = socket_address_bind_ipv6_only_from_string(rvalue);
413         if (b < 0) {
414                 int r;
415
416                 r = parse_boolean(rvalue);
417                 if (r < 0) {
418                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
419                                    "Failed to parse bind IPv6 only value, ignoring: %s", rvalue);
420                         return 0;
421                 }
422
423                 s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
424         } else
425                 s->bind_ipv6_only = b;
426
427         return 0;
428 }
429
430 int config_parse_exec_nice(const char *unit,
431                            const char *filename,
432                            unsigned line,
433                            const char *section,
434                            unsigned section_line,
435                            const char *lvalue,
436                            int ltype,
437                            const char *rvalue,
438                            void *data,
439                            void *userdata) {
440
441         ExecContext *c = data;
442         int priority, r;
443
444         assert(filename);
445         assert(lvalue);
446         assert(rvalue);
447         assert(data);
448
449         r = safe_atoi(rvalue, &priority);
450         if (r < 0) {
451                 log_syntax(unit, LOG_ERR, filename, line, -r,
452                            "Failed to parse nice priority, ignoring: %s. ", rvalue);
453                 return 0;
454         }
455
456         if (priority < PRIO_MIN || priority >= PRIO_MAX) {
457                 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
458                            "Nice priority out of range, ignoring: %s", rvalue);
459                 return 0;
460         }
461
462         c->nice = priority;
463         c->nice_set = true;
464
465         return 0;
466 }
467
468 int config_parse_exec_oom_score_adjust(const char* unit,
469                                        const char *filename,
470                                        unsigned line,
471                                        const char *section,
472                                        unsigned section_line,
473                                        const char *lvalue,
474                                        int ltype,
475                                        const char *rvalue,
476                                        void *data,
477                                        void *userdata) {
478
479         ExecContext *c = data;
480         int oa, r;
481
482         assert(filename);
483         assert(lvalue);
484         assert(rvalue);
485         assert(data);
486
487         r = safe_atoi(rvalue, &oa);
488         if (r < 0) {
489                 log_syntax(unit, LOG_ERR, filename, line, -r,
490                            "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
491                 return 0;
492         }
493
494         if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
495                 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
496                            "OOM score adjust value out of range, ignoring: %s", rvalue);
497                 return 0;
498         }
499
500         c->oom_score_adjust = oa;
501         c->oom_score_adjust_set = true;
502
503         return 0;
504 }
505
506 int config_parse_exec(const char *unit,
507                       const char *filename,
508                       unsigned line,
509                       const char *section,
510                       unsigned section_line,
511                       const char *lvalue,
512                       int ltype,
513                       const char *rvalue,
514                       void *data,
515                       void *userdata) {
516
517         ExecCommand **e = data, *nce;
518         char *path, **n;
519         unsigned k;
520         int r;
521
522         assert(filename);
523         assert(lvalue);
524         assert(rvalue);
525         assert(e);
526
527         e += ltype;
528
529         if (isempty(rvalue)) {
530                 /* An empty assignment resets the list */
531                 exec_command_free_list(*e);
532                 *e = NULL;
533                 return 0;
534         }
535
536         /* We accept an absolute path as first argument, or
537          * alternatively an absolute prefixed with @ to allow
538          * overriding of argv[0]. */
539         for (;;) {
540                 int i;
541                 const char *word, *state;
542                 size_t l;
543                 bool honour_argv0 = false, ignore = false;
544
545                 path = NULL;
546                 nce = NULL;
547                 n = NULL;
548
549                 rvalue += strspn(rvalue, WHITESPACE);
550
551                 if (rvalue[0] == 0)
552                         break;
553
554                 for (i = 0; i < 2; i++) {
555                         if (rvalue[0] == '-' && !ignore) {
556                                 ignore = true;
557                                 rvalue ++;
558                         }
559
560                         if (rvalue[0] == '@' && !honour_argv0) {
561                                 honour_argv0 = true;
562                                 rvalue ++;
563                         }
564                 }
565
566                 if (*rvalue != '/') {
567                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
568                                    "Executable path is not absolute, ignoring: %s", rvalue);
569                         return 0;
570                 }
571
572                 k = 0;
573                 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
574                         if (strneq(word, ";", MAX(l, 1U)))
575                                 goto found;
576
577                         k++;
578                 }
579                 if (!isempty(state)) {
580                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
581                                    "Trailing garbage, ignoring.");
582                         return 0;
583                 }
584
585         found:
586                 n = new(char*, k + !honour_argv0);
587                 if (!n)
588                         return log_oom();
589
590                 k = 0;
591                 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
592                         if (strneq(word, ";", MAX(l, 1U)))
593                                 break;
594                         else if (strneq(word, "\\;", MAX(l, 1U)))
595                                 word ++;
596
597                         if (honour_argv0 && word == rvalue) {
598                                 assert(!path);
599
600                                 path = strndup(word, l);
601                                 if (!path) {
602                                         r = log_oom();
603                                         goto fail;
604                                 }
605
606                                 if (!utf8_is_valid(path)) {
607                                         log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
608                                         r = 0;
609                                         goto fail;
610                                 }
611
612                         } else {
613                                 char *c;
614
615                                 c = n[k++] = cunescape_length(word, l);
616                                 if (!c) {
617                                         r = log_oom();
618                                         goto fail;
619                                 }
620
621                                 if (!utf8_is_valid(c)) {
622                                         log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
623                                         r = 0;
624                                         goto fail;
625                                 }
626                         }
627                 }
628
629                 n[k] = NULL;
630
631                 if (!n[0]) {
632                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
633                                    "Invalid command line, ignoring: %s", rvalue);
634                         r = 0;
635                         goto fail;
636                 }
637
638                 if (!path) {
639                         path = strdup(n[0]);
640                         if (!path) {
641                                 r = log_oom();
642                                 goto fail;
643                         }
644                 }
645
646                 assert(path_is_absolute(path));
647
648                 nce = new0(ExecCommand, 1);
649                 if (!nce) {
650                         r = log_oom();
651                         goto fail;
652                 }
653
654                 nce->argv = n;
655                 nce->path = path;
656                 nce->ignore = ignore;
657
658                 path_kill_slashes(nce->path);
659
660                 exec_command_append_list(e, nce);
661
662                 rvalue = state;
663         }
664
665         return 0;
666
667 fail:
668         n[k] = NULL;
669         strv_free(n);
670         free(path);
671         free(nce);
672
673         return r;
674 }
675
676 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
677 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
678
679 int config_parse_socket_bindtodevice(const char* unit,
680                                      const char *filename,
681                                      unsigned line,
682                                      const char *section,
683                                      unsigned section_line,
684                                      const char *lvalue,
685                                      int ltype,
686                                      const char *rvalue,
687                                      void *data,
688                                      void *userdata) {
689
690         Socket *s = data;
691         char *n;
692
693         assert(filename);
694         assert(lvalue);
695         assert(rvalue);
696         assert(data);
697
698         if (rvalue[0] && !streq(rvalue, "*")) {
699                 n = strdup(rvalue);
700                 if (!n)
701                         return log_oom();
702         } else
703                 n = NULL;
704
705         free(s->bind_to_device);
706         s->bind_to_device = n;
707
708         return 0;
709 }
710
711 DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
712 DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
713
714 int config_parse_exec_io_class(const char *unit,
715                                const char *filename,
716                                unsigned line,
717                                const char *section,
718                                unsigned section_line,
719                                const char *lvalue,
720                                int ltype,
721                                const char *rvalue,
722                                void *data,
723                                void *userdata) {
724
725         ExecContext *c = data;
726         int x;
727
728         assert(filename);
729         assert(lvalue);
730         assert(rvalue);
731         assert(data);
732
733         x = ioprio_class_from_string(rvalue);
734         if (x < 0) {
735                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
736                            "Failed to parse IO scheduling class, ignoring: %s", rvalue);
737                 return 0;
738         }
739
740         c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
741         c->ioprio_set = true;
742
743         return 0;
744 }
745
746 int config_parse_exec_io_priority(const char *unit,
747                                   const char *filename,
748                                   unsigned line,
749                                   const char *section,
750                                   unsigned section_line,
751                                   const char *lvalue,
752                                   int ltype,
753                                   const char *rvalue,
754                                   void *data,
755                                   void *userdata) {
756
757         ExecContext *c = data;
758         int i, r;
759
760         assert(filename);
761         assert(lvalue);
762         assert(rvalue);
763         assert(data);
764
765         r = safe_atoi(rvalue, &i);
766         if (r < 0 || i < 0 || i >= IOPRIO_BE_NR) {
767                 log_syntax(unit, LOG_ERR, filename, line, -r,
768                            "Failed to parse IO priority, ignoring: %s", rvalue);
769                 return 0;
770         }
771
772         c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
773         c->ioprio_set = true;
774
775         return 0;
776 }
777
778 int config_parse_exec_cpu_sched_policy(const char *unit,
779                                        const char *filename,
780                                        unsigned line,
781                                        const char *section,
782                                        unsigned section_line,
783                                        const char *lvalue,
784                                        int ltype,
785                                        const char *rvalue,
786                                        void *data,
787                                        void *userdata) {
788
789
790         ExecContext *c = data;
791         int x;
792
793         assert(filename);
794         assert(lvalue);
795         assert(rvalue);
796         assert(data);
797
798         x = sched_policy_from_string(rvalue);
799         if (x < 0) {
800                 log_syntax(unit, LOG_ERR, filename, line, -x,
801                            "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
802                 return 0;
803         }
804
805         c->cpu_sched_policy = x;
806         /* Moving to or from real-time policy? We need to adjust the priority */
807         c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x));
808         c->cpu_sched_set = true;
809
810         return 0;
811 }
812
813 int config_parse_exec_cpu_sched_prio(const char *unit,
814                                      const char *filename,
815                                      unsigned line,
816                                      const char *section,
817                                      unsigned section_line,
818                                      const char *lvalue,
819                                      int ltype,
820                                      const char *rvalue,
821                                      void *data,
822                                      void *userdata) {
823
824         ExecContext *c = data;
825         int i, min, max, r;
826
827         assert(filename);
828         assert(lvalue);
829         assert(rvalue);
830         assert(data);
831
832         r = safe_atoi(rvalue, &i);
833         if (r < 0) {
834                 log_syntax(unit, LOG_ERR, filename, line, -r,
835                            "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
836                 return 0;
837         }
838
839         /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
840         min = sched_get_priority_min(c->cpu_sched_policy);
841         max = sched_get_priority_max(c->cpu_sched_policy);
842
843         if (i < min || i > max) {
844                 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
845                            "CPU scheduling priority is out of range, ignoring: %s", rvalue);
846                 return 0;
847         }
848
849         c->cpu_sched_priority = i;
850         c->cpu_sched_set = true;
851
852         return 0;
853 }
854
855 int config_parse_exec_cpu_affinity(const char *unit,
856                                    const char *filename,
857                                    unsigned line,
858                                    const char *section,
859                                    unsigned section_line,
860                                    const char *lvalue,
861                                    int ltype,
862                                    const char *rvalue,
863                                    void *data,
864                                    void *userdata) {
865
866         ExecContext *c = data;
867         const char *word, *state;
868         size_t l;
869
870         assert(filename);
871         assert(lvalue);
872         assert(rvalue);
873         assert(data);
874
875         if (isempty(rvalue)) {
876                 /* An empty assignment resets the CPU list */
877                 if (c->cpuset)
878                         CPU_FREE(c->cpuset);
879                 c->cpuset = NULL;
880                 return 0;
881         }
882
883         FOREACH_WORD_QUOTED(word, l, rvalue, state) {
884                 _cleanup_free_ char *t = NULL;
885                 int r;
886                 unsigned cpu;
887
888                 t = strndup(word, l);
889                 if (!t)
890                         return log_oom();
891
892                 r = safe_atou(t, &cpu);
893
894                 if (!c->cpuset) {
895                         c->cpuset = cpu_set_malloc(&c->cpuset_ncpus);
896                         if (!c->cpuset)
897                                 return log_oom();
898                 }
899
900                 if (r < 0 || cpu >= c->cpuset_ncpus) {
901                         log_syntax(unit, LOG_ERR, filename, line, ERANGE,
902                                    "Failed to parse CPU affinity '%s', ignoring: %s", t, rvalue);
903                         return 0;
904                 }
905
906                 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
907         }
908         if (!isempty(state))
909                 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
910                            "Trailing garbage, ignoring.");
911
912         return 0;
913 }
914
915 int config_parse_exec_capabilities(const char *unit,
916                                    const char *filename,
917                                    unsigned line,
918                                    const char *section,
919                                    unsigned section_line,
920                                    const char *lvalue,
921                                    int ltype,
922                                    const char *rvalue,
923                                    void *data,
924                                    void *userdata) {
925
926         ExecContext *c = data;
927         cap_t cap;
928
929         assert(filename);
930         assert(lvalue);
931         assert(rvalue);
932         assert(data);
933
934         cap = cap_from_text(rvalue);
935         if (!cap) {
936                 log_syntax(unit, LOG_ERR, filename, line, errno,
937                            "Failed to parse capabilities, ignoring: %s", rvalue);
938                 return 0;
939         }
940
941         if (c->capabilities)
942                 cap_free(c->capabilities);
943         c->capabilities = cap;
944
945         return 0;
946 }
947
948 int config_parse_exec_secure_bits(const char *unit,
949                                   const char *filename,
950                                   unsigned line,
951                                   const char *section,
952                                   unsigned section_line,
953                                   const char *lvalue,
954                                   int ltype,
955                                   const char *rvalue,
956                                   void *data,
957                                   void *userdata) {
958
959         ExecContext *c = data;
960         size_t l;
961         const char *word, *state;
962
963         assert(filename);
964         assert(lvalue);
965         assert(rvalue);
966         assert(data);
967
968         if (isempty(rvalue)) {
969                 /* An empty assignment resets the field */
970                 c->secure_bits = 0;
971                 return 0;
972         }
973
974         FOREACH_WORD_QUOTED(word, l, rvalue, state) {
975                 if (first_word(word, "keep-caps"))
976                         c->secure_bits |= 1<<SECURE_KEEP_CAPS;
977                 else if (first_word(word, "keep-caps-locked"))
978                         c->secure_bits |= 1<<SECURE_KEEP_CAPS_LOCKED;
979                 else if (first_word(word, "no-setuid-fixup"))
980                         c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP;
981                 else if (first_word(word, "no-setuid-fixup-locked"))
982                         c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP_LOCKED;
983                 else if (first_word(word, "noroot"))
984                         c->secure_bits |= 1<<SECURE_NOROOT;
985                 else if (first_word(word, "noroot-locked"))
986                         c->secure_bits |= 1<<SECURE_NOROOT_LOCKED;
987                 else {
988                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
989                                    "Failed to parse secure bits, ignoring: %s", rvalue);
990                         return 0;
991                 }
992         }
993         if (!isempty(state))
994                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
995                            "Invalid syntax, garbage at the end, ignoring.");
996
997         return 0;
998 }
999
1000 int config_parse_bounding_set(const char *unit,
1001                               const char *filename,
1002                               unsigned line,
1003                               const char *section,
1004                               unsigned section_line,
1005                               const char *lvalue,
1006                               int ltype,
1007                               const char *rvalue,
1008                               void *data,
1009                               void *userdata) {
1010
1011         uint64_t *capability_bounding_set_drop = data;
1012         const char *word, *state;
1013         size_t l;
1014         bool invert = false;
1015         uint64_t sum = 0;
1016
1017         assert(filename);
1018         assert(lvalue);
1019         assert(rvalue);
1020         assert(data);
1021
1022         if (rvalue[0] == '~') {
1023                 invert = true;
1024                 rvalue++;
1025         }
1026
1027         /* Note that we store this inverted internally, since the
1028          * kernel wants it like this. But we actually expose it
1029          * non-inverted everywhere to have a fully normalized
1030          * interface. */
1031
1032         FOREACH_WORD_QUOTED(word, l, rvalue, state) {
1033                 _cleanup_free_ char *t = NULL;
1034                 int r;
1035                 cap_value_t cap;
1036
1037                 t = strndup(word, l);
1038                 if (!t)
1039                         return log_oom();
1040
1041                 r = cap_from_name(t, &cap);
1042                 if (r < 0) {
1043                         log_syntax(unit, LOG_ERR, filename, line, errno,
1044                                    "Failed to parse capability in bounding set, ignoring: %s", t);
1045                         continue;
1046                 }
1047
1048                 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
1049         }
1050         if (!isempty(state))
1051                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1052                            "Trailing garbage, ignoring.");
1053
1054         if (invert)
1055                 *capability_bounding_set_drop |= sum;
1056         else
1057                 *capability_bounding_set_drop |= ~sum;
1058
1059         return 0;
1060 }
1061
1062 int config_parse_limit(const char *unit,
1063                        const char *filename,
1064                        unsigned line,
1065                        const char *section,
1066                        unsigned section_line,
1067                        const char *lvalue,
1068                        int ltype,
1069                        const char *rvalue,
1070                        void *data,
1071                        void *userdata) {
1072
1073         struct rlimit **rl = data;
1074         unsigned long long u;
1075
1076         assert(filename);
1077         assert(lvalue);
1078         assert(rvalue);
1079         assert(data);
1080
1081         rl += ltype;
1082
1083         if (streq(rvalue, "infinity"))
1084                 u = (unsigned long long) RLIM_INFINITY;
1085         else {
1086                 int r;
1087
1088                 r = safe_atollu(rvalue, &u);
1089                 if (r < 0) {
1090                         log_syntax(unit, LOG_ERR, filename, line, -r,
1091                                    "Failed to parse resource value, ignoring: %s", rvalue);
1092                         return 0;
1093                 }
1094         }
1095
1096         if (!*rl) {
1097                 *rl = new(struct rlimit, 1);
1098                 if (!*rl)
1099                         return log_oom();
1100         }
1101
1102         (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
1103         return 0;
1104 }
1105
1106 #ifdef HAVE_SYSV_COMPAT
1107 int config_parse_sysv_priority(const char *unit,
1108                                const char *filename,
1109                                unsigned line,
1110                                const char *section,
1111                                unsigned section_line,
1112                                const char *lvalue,
1113                                int ltype,
1114                                const char *rvalue,
1115                                void *data,
1116                                void *userdata) {
1117
1118         int *priority = data;
1119         int i, r;
1120
1121         assert(filename);
1122         assert(lvalue);
1123         assert(rvalue);
1124         assert(data);
1125
1126         r = safe_atoi(rvalue, &i);
1127         if (r < 0 || i < 0) {
1128                 log_syntax(unit, LOG_ERR, filename, line, -r,
1129                            "Failed to parse SysV start priority, ignoring: %s", rvalue);
1130                 return 0;
1131         }
1132
1133         *priority = (int) i;
1134         return 0;
1135 }
1136 #endif
1137
1138 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
1139
1140 int config_parse_kill_signal(const char *unit,
1141                              const char *filename,
1142                              unsigned line,
1143                              const char *section,
1144                              unsigned section_line,
1145                              const char *lvalue,
1146                              int ltype,
1147                              const char *rvalue,
1148                              void *data,
1149                              void *userdata) {
1150
1151         int *sig = data;
1152         int r;
1153
1154         assert(filename);
1155         assert(lvalue);
1156         assert(rvalue);
1157         assert(sig);
1158
1159         r = signal_from_string_try_harder(rvalue);
1160         if (r <= 0) {
1161                 log_syntax(unit, LOG_ERR, filename, line, -r,
1162                            "Failed to parse kill signal, ignoring: %s", rvalue);
1163                 return 0;
1164         }
1165
1166         *sig = r;
1167         return 0;
1168 }
1169
1170 int config_parse_exec_mount_flags(const char *unit,
1171                                   const char *filename,
1172                                   unsigned line,
1173                                   const char *section,
1174                                   unsigned section_line,
1175                                   const char *lvalue,
1176                                   int ltype,
1177                                   const char *rvalue,
1178                                   void *data,
1179                                   void *userdata) {
1180
1181         ExecContext *c = data;
1182         const char *word, *state;
1183         size_t l;
1184         unsigned long flags = 0;
1185
1186         assert(filename);
1187         assert(lvalue);
1188         assert(rvalue);
1189         assert(data);
1190
1191         FOREACH_WORD_SEPARATOR(word, l, rvalue, ", ", state) {
1192                 _cleanup_free_ char *t;
1193
1194                 t = strndup(word, l);
1195                 if (!t)
1196                         return log_oom();
1197
1198                 if (streq(t, "shared"))
1199                         flags = MS_SHARED;
1200                 else if (streq(t, "slave"))
1201                         flags = MS_SLAVE;
1202                 else if (streq(word, "private"))
1203                         flags = MS_PRIVATE;
1204                 else {
1205                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1206                                    "Failed to parse mount flag %s, ignoring: %s", t, rvalue);
1207                         return 0;
1208                 }
1209         }
1210         if (!isempty(state))
1211                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1212                            "Trailing garbage, ignoring.");
1213
1214         c->mount_flags = flags;
1215         return 0;
1216 }
1217
1218 int config_parse_exec_selinux_context(
1219                 const char *unit,
1220                 const char *filename,
1221                 unsigned line,
1222                 const char *section,
1223                 unsigned section_line,
1224                 const char *lvalue,
1225                 int ltype,
1226                 const char *rvalue,
1227                 void *data,
1228                 void *userdata) {
1229
1230         ExecContext *c = data;
1231         Unit *u = userdata;
1232         bool ignore;
1233         char *k;
1234         int r;
1235
1236         assert(filename);
1237         assert(lvalue);
1238         assert(rvalue);
1239         assert(data);
1240
1241         if (isempty(rvalue)) {
1242                 free(c->selinux_context);
1243                 c->selinux_context = NULL;
1244                 c->selinux_context_ignore = false;
1245                 return 0;
1246         }
1247
1248         if (rvalue[0] == '-') {
1249                 ignore = true;
1250                 rvalue++;
1251         } else
1252                 ignore = false;
1253
1254         r = unit_name_printf(u, rvalue, &k);
1255         if (r < 0) {
1256                 log_syntax(unit, LOG_ERR, filename, line, -r,
1257                            "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1258                 return 0;
1259         }
1260
1261         free(c->selinux_context);
1262         c->selinux_context = k;
1263         c->selinux_context_ignore = ignore;
1264
1265         return 0;
1266 }
1267
1268 int config_parse_exec_apparmor_profile(
1269                 const char *unit,
1270                 const char *filename,
1271                 unsigned line,
1272                 const char *section,
1273                 unsigned section_line,
1274                 const char *lvalue,
1275                 int ltype,
1276                 const char *rvalue,
1277                 void *data,
1278                 void *userdata) {
1279
1280         ExecContext *c = data;
1281         Unit *u = userdata;
1282         bool ignore;
1283         char *k;
1284         int r;
1285
1286         assert(filename);
1287         assert(lvalue);
1288         assert(rvalue);
1289         assert(data);
1290
1291         if (isempty(rvalue)) {
1292                 free(c->apparmor_profile);
1293                 c->apparmor_profile = NULL;
1294                 c->apparmor_profile_ignore = false;
1295                 return 0;
1296         }
1297
1298         if (rvalue[0] == '-') {
1299                 ignore = true;
1300                 rvalue++;
1301         } else
1302                 ignore = false;
1303
1304         r = unit_name_printf(u, rvalue, &k);
1305         if (r < 0) {
1306                 log_syntax(unit, LOG_ERR, filename, line, -r,
1307                            "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1308                 return 0;
1309         }
1310
1311         free(c->apparmor_profile);
1312         c->apparmor_profile = k;
1313         c->apparmor_profile_ignore = ignore;
1314
1315         return 0;
1316 }
1317
1318 int config_parse_timer(const char *unit,
1319                        const char *filename,
1320                        unsigned line,
1321                        const char *section,
1322                        unsigned section_line,
1323                        const char *lvalue,
1324                        int ltype,
1325                        const char *rvalue,
1326                        void *data,
1327                        void *userdata) {
1328
1329         Timer *t = data;
1330         usec_t u = 0;
1331         TimerValue *v;
1332         TimerBase b;
1333         CalendarSpec *c = NULL;
1334
1335         assert(filename);
1336         assert(lvalue);
1337         assert(rvalue);
1338         assert(data);
1339
1340         if (isempty(rvalue)) {
1341                 /* Empty assignment resets list */
1342                 timer_free_values(t);
1343                 return 0;
1344         }
1345
1346         b = timer_base_from_string(lvalue);
1347         if (b < 0) {
1348                 log_syntax(unit, LOG_ERR, filename, line, -b,
1349                            "Failed to parse timer base, ignoring: %s", lvalue);
1350                 return 0;
1351         }
1352
1353         if (b == TIMER_CALENDAR) {
1354                 if (calendar_spec_from_string(rvalue, &c) < 0) {
1355                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1356                                    "Failed to parse calendar specification, ignoring: %s",
1357                                    rvalue);
1358                         return 0;
1359                 }
1360         } else {
1361                 if (parse_sec(rvalue, &u) < 0) {
1362                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1363                                    "Failed to parse timer value, ignoring: %s",
1364                                    rvalue);
1365                         return 0;
1366                 }
1367         }
1368
1369         v = new0(TimerValue, 1);
1370         if (!v) {
1371                 if (c)
1372                         free(c);
1373                 return log_oom();
1374         }
1375
1376         v->base = b;
1377         v->value = u;
1378         v->calendar_spec = c;
1379
1380         LIST_PREPEND(value, t->values, v);
1381
1382         return 0;
1383 }
1384
1385 int config_parse_trigger_unit(
1386                 const char *unit,
1387                 const char *filename,
1388                 unsigned line,
1389                 const char *section,
1390                 unsigned section_line,
1391                 const char *lvalue,
1392                 int ltype,
1393                 const char *rvalue,
1394                 void *data,
1395                 void *userdata) {
1396
1397         _cleanup_free_ char *p = NULL;
1398         Unit *u = data;
1399         UnitType type;
1400         int r;
1401
1402         assert(filename);
1403         assert(lvalue);
1404         assert(rvalue);
1405         assert(data);
1406
1407         if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
1408                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1409                            "Multiple units to trigger specified, ignoring: %s", rvalue);
1410                 return 0;
1411         }
1412
1413         r = unit_name_printf(u, rvalue, &p);
1414         if (r < 0)
1415                 log_syntax(unit, LOG_ERR, filename, line, -r,
1416                            "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1417
1418         type = unit_name_to_type(p ?: rvalue);
1419         if (type < 0) {
1420                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1421                            "Unit type not valid, ignoring: %s", rvalue);
1422                 return 0;
1423         }
1424
1425         if (type == u->type) {
1426                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1427                            "Trigger cannot be of same type, ignoring: %s", rvalue);
1428                 return 0;
1429         }
1430
1431         r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p ?: rvalue, NULL, true);
1432         if (r < 0) {
1433                 log_syntax(unit, LOG_ERR, filename, line, -r,
1434                            "Failed to add trigger on %s, ignoring: %s", p ?: rvalue, strerror(-r));
1435                 return 0;
1436         }
1437
1438         return 0;
1439 }
1440
1441 int config_parse_path_spec(const char *unit,
1442                            const char *filename,
1443                            unsigned line,
1444                            const char *section,
1445                            unsigned section_line,
1446                            const char *lvalue,
1447                            int ltype,
1448                            const char *rvalue,
1449                            void *data,
1450                            void *userdata) {
1451
1452         Path *p = data;
1453         PathSpec *s;
1454         PathType b;
1455         _cleanup_free_ char *k = NULL;
1456         int r;
1457
1458         assert(filename);
1459         assert(lvalue);
1460         assert(rvalue);
1461         assert(data);
1462
1463         if (isempty(rvalue)) {
1464                 /* Empty assignment clears list */
1465                 path_free_specs(p);
1466                 return 0;
1467         }
1468
1469         b = path_type_from_string(lvalue);
1470         if (b < 0) {
1471                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1472                            "Failed to parse path type, ignoring: %s", lvalue);
1473                 return 0;
1474         }
1475
1476         r = unit_full_printf(UNIT(p), rvalue, &k);
1477         if (r < 0) {
1478                 k = strdup(rvalue);
1479                 if (!k)
1480                         return log_oom();
1481                 else
1482                         log_syntax(unit, LOG_ERR, filename, line, -r,
1483                                    "Failed to resolve unit specifiers on %s. Ignoring.",
1484                                    rvalue);
1485         }
1486
1487         if (!path_is_absolute(k)) {
1488                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1489                            "Path is not absolute, ignoring: %s", k);
1490                 return 0;
1491         }
1492
1493         s = new0(PathSpec, 1);
1494         if (!s)
1495                 return log_oom();
1496
1497         s->unit = UNIT(p);
1498         s->path = path_kill_slashes(k);
1499         k = NULL;
1500         s->type = b;
1501         s->inotify_fd = -1;
1502
1503         LIST_PREPEND(spec, p->specs, s);
1504
1505         return 0;
1506 }
1507
1508 int config_parse_socket_service(const char *unit,
1509                                 const char *filename,
1510                                 unsigned line,
1511                                 const char *section,
1512                                 unsigned section_line,
1513                                 const char *lvalue,
1514                                 int ltype,
1515                                 const char *rvalue,
1516                                 void *data,
1517                                 void *userdata) {
1518
1519         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1520         Socket *s = data;
1521         int r;
1522         Unit *x;
1523         _cleanup_free_ char *p = NULL;
1524
1525         assert(filename);
1526         assert(lvalue);
1527         assert(rvalue);
1528         assert(data);
1529
1530         r = unit_name_printf(UNIT(s), rvalue, &p);
1531         if (r < 0) {
1532                 log_syntax(unit, LOG_ERR, filename, line, -r,
1533                            "Failed to resolve specifiers, ignoring: %s", rvalue);
1534                 return 0;
1535         }
1536
1537         if (!endswith(p, ".service")) {
1538                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1539                            "Unit must be of type service, ignoring: %s", rvalue);
1540                 return 0;
1541         }
1542
1543         r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
1544         if (r < 0) {
1545                 log_syntax(unit, LOG_ERR, filename, line, -r,
1546                            "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1547                 return 0;
1548         }
1549
1550         unit_ref_set(&s->service, x);
1551
1552         return 0;
1553 }
1554
1555 int config_parse_service_sockets(const char *unit,
1556                                  const char *filename,
1557                                  unsigned line,
1558                                  const char *section,
1559                                  unsigned section_line,
1560                                  const char *lvalue,
1561                                  int ltype,
1562                                  const char *rvalue,
1563                                  void *data,
1564                                  void *userdata) {
1565
1566         Service *s = data;
1567         int r;
1568         const char *word, *state;
1569         size_t l;
1570
1571         assert(filename);
1572         assert(lvalue);
1573         assert(rvalue);
1574         assert(data);
1575
1576         FOREACH_WORD_QUOTED(word, l, rvalue, state) {
1577                 _cleanup_free_ char *t = NULL, *k = NULL;
1578
1579                 t = strndup(word, l);
1580                 if (!t)
1581                         return log_oom();
1582
1583                 r = unit_name_printf(UNIT(s), t, &k);
1584                 if (r < 0)
1585                         log_syntax(unit, LOG_ERR, filename, line, -r,
1586                                    "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1587
1588                 if (!endswith(k ?: t, ".socket")) {
1589                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1590                                    "Unit must be of type socket, ignoring: %s", k ?: t);
1591                         continue;
1592                 }
1593
1594                 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k ?: t, NULL, true);
1595                 if (r < 0)
1596                         log_syntax(unit, LOG_ERR, filename, line, -r,
1597                                    "Failed to add dependency on %s, ignoring: %s",
1598                                    k ?: t, strerror(-r));
1599
1600                 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k ?: t, NULL, true);
1601                 if (r < 0)
1602                         return r;
1603         }
1604         if (!isempty(state))
1605                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1606                            "Trailing garbage, ignoring.");
1607
1608         return 0;
1609 }
1610
1611 int config_parse_service_timeout(const char *unit,
1612                                  const char *filename,
1613                                  unsigned line,
1614                                  const char *section,
1615                                  unsigned section_line,
1616                                  const char *lvalue,
1617                                  int ltype,
1618                                  const char *rvalue,
1619                                  void *data,
1620                                  void *userdata) {
1621
1622         Service *s = userdata;
1623         int r;
1624
1625         assert(filename);
1626         assert(lvalue);
1627         assert(rvalue);
1628         assert(s);
1629
1630         r = config_parse_sec(unit, filename, line, section, section_line, lvalue, ltype,
1631                              rvalue, data, userdata);
1632         if (r < 0)
1633                 return r;
1634
1635         if (streq(lvalue, "TimeoutSec")) {
1636                 s->start_timeout_defined = true;
1637                 s->timeout_stop_usec = s->timeout_start_usec;
1638         } else if (streq(lvalue, "TimeoutStartSec"))
1639                 s->start_timeout_defined = true;
1640
1641         return 0;
1642 }
1643
1644 int config_parse_busname_service(
1645                 const char *unit,
1646                 const char *filename,
1647                 unsigned line,
1648                 const char *section,
1649                 unsigned section_line,
1650                 const char *lvalue,
1651                 int ltype,
1652                 const char *rvalue,
1653                 void *data,
1654                 void *userdata) {
1655
1656         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1657         BusName *n = data;
1658         int r;
1659         Unit *x;
1660         _cleanup_free_ char *p = NULL;
1661
1662         assert(filename);
1663         assert(lvalue);
1664         assert(rvalue);
1665         assert(data);
1666
1667         r = unit_name_printf(UNIT(n), rvalue, &p);
1668         if (r < 0) {
1669                 log_syntax(unit, LOG_ERR, filename, line, -r,
1670                            "Failed to resolve specifiers, ignoring: %s", rvalue);
1671                 return 0;
1672         }
1673
1674         if (!endswith(p, ".service")) {
1675                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1676                            "Unit must be of type service, ignoring: %s", rvalue);
1677                 return 0;
1678         }
1679
1680         r = manager_load_unit(UNIT(n)->manager, p, NULL, &error, &x);
1681         if (r < 0) {
1682                 log_syntax(unit, LOG_ERR, filename, line, -r,
1683                            "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1684                 return 0;
1685         }
1686
1687         unit_ref_set(&n->service, x);
1688
1689         return 0;
1690 }
1691
1692 DEFINE_CONFIG_PARSE_ENUM(config_parse_bus_policy_world, bus_policy_access, BusPolicyAccess, "Failed to parse bus name policy access");
1693
1694 int config_parse_bus_policy(
1695                 const char *unit,
1696                 const char *filename,
1697                 unsigned line,
1698                 const char *section,
1699                 unsigned section_line,
1700                 const char *lvalue,
1701                 int ltype,
1702                 const char *rvalue,
1703                 void *data,
1704                 void *userdata) {
1705
1706         _cleanup_free_ BusNamePolicy *p = NULL;
1707         _cleanup_free_ char *id_str = NULL;
1708         BusName *busname = data;
1709         char *access_str;
1710
1711         assert(filename);
1712         assert(lvalue);
1713         assert(rvalue);
1714         assert(data);
1715
1716         p = new0(BusNamePolicy, 1);
1717         if (!p)
1718                 return log_oom();
1719
1720         if (streq(lvalue, "AllowUser"))
1721                 p->type = BUSNAME_POLICY_TYPE_USER;
1722         else if (streq(lvalue, "AllowGroup"))
1723                 p->type = BUSNAME_POLICY_TYPE_GROUP;
1724         else
1725                 assert_not_reached("Unknown lvalue");
1726
1727         id_str = strdup(rvalue);
1728         if (!id_str)
1729                 return log_oom();
1730
1731         access_str = strpbrk(id_str, WHITESPACE);
1732         if (!access_str) {
1733                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1734                            "Invalid busname policy value '%s'", rvalue);
1735                 return 0;
1736         }
1737
1738         *access_str = '\0';
1739         access_str++;
1740         access_str += strspn(access_str, WHITESPACE);
1741
1742         p->access = bus_policy_access_from_string(access_str);
1743         if (p->access < 0) {
1744                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1745                            "Invalid busname policy access type '%s'", access_str);
1746                 return 0;
1747         }
1748
1749         p->name = id_str;
1750         id_str = NULL;
1751
1752         LIST_PREPEND(policy, busname->policy, p);
1753         p = NULL;
1754
1755         return 0;
1756 }
1757
1758 int config_parse_bus_endpoint_policy(
1759                 const char *unit,
1760                 const char *filename,
1761                 unsigned line,
1762                 const char *section,
1763                 unsigned section_line,
1764                 const char *lvalue,
1765                 int ltype,
1766                 const char *rvalue,
1767                 void *data,
1768                 void *userdata) {
1769
1770         _cleanup_free_ char *name = NULL;
1771         BusPolicyAccess access;
1772         ExecContext *c = data;
1773         char *access_str;
1774         int r;
1775
1776         assert(filename);
1777         assert(lvalue);
1778         assert(rvalue);
1779         assert(data);
1780
1781         name = strdup(rvalue);
1782         if (!name)
1783                 return log_oom();
1784
1785         access_str = strpbrk(name, WHITESPACE);
1786         if (!access_str) {
1787                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1788                            "Invalid endpoint policy value '%s'", rvalue);
1789                 return 0;
1790         }
1791
1792         *access_str = '\0';
1793         access_str++;
1794         access_str += strspn(access_str, WHITESPACE);
1795
1796         access = bus_policy_access_from_string(access_str);
1797         if (access <= _BUS_POLICY_ACCESS_INVALID ||
1798             access >= _BUS_POLICY_ACCESS_MAX) {
1799                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1800                            "Invalid endpoint policy access type '%s'", access_str);
1801                 return 0;
1802         }
1803
1804         if (!c->bus_endpoint) {
1805                 r = bus_endpoint_new(&c->bus_endpoint);
1806
1807                 if (r < 0)
1808                         return r;
1809         }
1810
1811         return bus_endpoint_add_policy(c->bus_endpoint, name, access);
1812 }
1813
1814 int config_parse_unit_env_file(const char *unit,
1815                                const char *filename,
1816                                unsigned line,
1817                                const char *section,
1818                                unsigned section_line,
1819                                const char *lvalue,
1820                                int ltype,
1821                                const char *rvalue,
1822                                void *data,
1823                                void *userdata) {
1824
1825         char ***env = data;
1826         Unit *u = userdata;
1827         _cleanup_free_ char *n = NULL;
1828         const char *s;
1829         int r;
1830
1831         assert(filename);
1832         assert(lvalue);
1833         assert(rvalue);
1834         assert(data);
1835
1836         if (isempty(rvalue)) {
1837                 /* Empty assignment frees the list */
1838                 strv_free(*env);
1839                 *env = NULL;
1840                 return 0;
1841         }
1842
1843         r = unit_full_printf(u, rvalue, &n);
1844         if (r < 0)
1845                 log_syntax(unit, LOG_ERR, filename, line, -r,
1846                            "Failed to resolve specifiers, ignoring: %s", rvalue);
1847
1848         s = n ?: rvalue;
1849         if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1850                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1851                            "Path '%s' is not absolute, ignoring.", s);
1852                 return 0;
1853         }
1854
1855         r = strv_extend(env, s);
1856         if (r < 0)
1857                 return log_oom();
1858
1859         return 0;
1860 }
1861
1862 int config_parse_environ(const char *unit,
1863                          const char *filename,
1864                          unsigned line,
1865                          const char *section,
1866                          unsigned section_line,
1867                          const char *lvalue,
1868                          int ltype,
1869                          const char *rvalue,
1870                          void *data,
1871                          void *userdata) {
1872
1873         Unit *u = userdata;
1874         char*** env = data;
1875         const char *word, *state;
1876         size_t l;
1877         _cleanup_free_ char *k = NULL;
1878         int r;
1879
1880         assert(filename);
1881         assert(lvalue);
1882         assert(rvalue);
1883         assert(data);
1884
1885         if (isempty(rvalue)) {
1886                 /* Empty assignment resets the list */
1887                 strv_free(*env);
1888                 *env = NULL;
1889                 return 0;
1890         }
1891
1892         if (u) {
1893                 r = unit_full_printf(u, rvalue, &k);
1894                 if (r < 0)
1895                         log_syntax(unit, LOG_ERR, filename, line, -r,
1896                                    "Failed to resolve specifiers, ignoring: %s", rvalue);
1897         }
1898
1899         if (!k)
1900                 k = strdup(rvalue);
1901         if (!k)
1902                 return log_oom();
1903
1904         FOREACH_WORD_QUOTED(word, l, k, state) {
1905                 _cleanup_free_ char *n;
1906                 char **x;
1907
1908                 n = cunescape_length(word, l);
1909                 if (!n)
1910                         return log_oom();
1911
1912                 if (!env_assignment_is_valid(n)) {
1913                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1914                                    "Invalid environment assignment, ignoring: %s", rvalue);
1915                         continue;
1916                 }
1917
1918                 x = strv_env_set(*env, n);
1919                 if (!x)
1920                         return log_oom();
1921
1922                 strv_free(*env);
1923                 *env = x;
1924         }
1925         if (!isempty(state))
1926                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1927                            "Trailing garbage, ignoring.");
1928
1929         return 0;
1930 }
1931
1932 int config_parse_ip_tos(const char *unit,
1933                         const char *filename,
1934                         unsigned line,
1935                         const char *section,
1936                         unsigned section_line,
1937                         const char *lvalue,
1938                         int ltype,
1939                         const char *rvalue,
1940                         void *data,
1941                         void *userdata) {
1942
1943         int *ip_tos = data, x;
1944
1945         assert(filename);
1946         assert(lvalue);
1947         assert(rvalue);
1948         assert(data);
1949
1950         x = ip_tos_from_string(rvalue);
1951         if (x < 0) {
1952                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1953                            "Failed to parse IP TOS value, ignoring: %s", rvalue);
1954                 return 0;
1955         }
1956
1957         *ip_tos = x;
1958         return 0;
1959 }
1960
1961 int config_parse_unit_condition_path(const char *unit,
1962                                      const char *filename,
1963                                      unsigned line,
1964                                      const char *section,
1965                                      unsigned section_line,
1966                                      const char *lvalue,
1967                                      int ltype,
1968                                      const char *rvalue,
1969                                      void *data,
1970                                      void *userdata) {
1971
1972         ConditionType cond = ltype;
1973         Unit *u = data;
1974         bool trigger, negate;
1975         Condition *c;
1976         _cleanup_free_ char *p = NULL;
1977         int r;
1978
1979         assert(filename);
1980         assert(lvalue);
1981         assert(rvalue);
1982         assert(data);
1983
1984         if (isempty(rvalue)) {
1985                 /* Empty assignment resets the list */
1986                 condition_free_list(u->conditions);
1987                 u->conditions = NULL;
1988                 return 0;
1989         }
1990
1991         trigger = rvalue[0] == '|';
1992         if (trigger)
1993                 rvalue++;
1994
1995         negate = rvalue[0] == '!';
1996         if (negate)
1997                 rvalue++;
1998
1999         r = unit_full_printf(u, rvalue, &p);
2000         if (r < 0)
2001                 log_syntax(unit, LOG_ERR, filename, line, -r,
2002                            "Failed to resolve specifiers, ignoring: %s", rvalue);
2003         if (!p) {
2004                 p = strdup(rvalue);
2005                 if (!p)
2006                         return log_oom();
2007         }
2008
2009         if (!path_is_absolute(p)) {
2010                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2011                            "Path in condition not absolute, ignoring: %s", p);
2012                 return 0;
2013         }
2014
2015         c = condition_new(cond, p, trigger, negate);
2016         if (!c)
2017                 return log_oom();
2018
2019         LIST_PREPEND(conditions, u->conditions, c);
2020         return 0;
2021 }
2022
2023 int config_parse_unit_condition_string(const char *unit,
2024                                        const char *filename,
2025                                        unsigned line,
2026                                        const char *section,
2027                                        unsigned section_line,
2028                                        const char *lvalue,
2029                                        int ltype,
2030                                        const char *rvalue,
2031                                        void *data,
2032                                        void *userdata) {
2033
2034         ConditionType cond = ltype;
2035         Unit *u = data;
2036         bool trigger, negate;
2037         Condition *c;
2038         _cleanup_free_ char *s = NULL;
2039         int r;
2040
2041         assert(filename);
2042         assert(lvalue);
2043         assert(rvalue);
2044         assert(data);
2045
2046         if (isempty(rvalue)) {
2047                 /* Empty assignment resets the list */
2048                 condition_free_list(u->conditions);
2049                 u->conditions = NULL;
2050                 return 0;
2051         }
2052
2053         trigger = rvalue[0] == '|';
2054         if (trigger)
2055                 rvalue++;
2056
2057         negate = rvalue[0] == '!';
2058         if (negate)
2059                 rvalue++;
2060
2061         r = unit_full_printf(u, rvalue, &s);
2062         if (r < 0)
2063                 log_syntax(unit, LOG_ERR, filename, line, -r,
2064                            "Failed to resolve specifiers, ignoring: %s", rvalue);
2065         if (!s) {
2066                 s = strdup(rvalue);
2067                 if (!s)
2068                         return log_oom();
2069         }
2070
2071         c = condition_new(cond, s, trigger, negate);
2072         if (!c)
2073                 return log_oom();
2074
2075         LIST_PREPEND(conditions, u->conditions, c);
2076         return 0;
2077 }
2078
2079 int config_parse_unit_condition_null(const char *unit,
2080                                      const char *filename,
2081                                      unsigned line,
2082                                      const char *section,
2083                                      unsigned section_line,
2084                                      const char *lvalue,
2085                                      int ltype,
2086                                      const char *rvalue,
2087                                      void *data,
2088                                      void *userdata) {
2089
2090         Unit *u = data;
2091         Condition *c;
2092         bool trigger, negate;
2093         int b;
2094
2095         assert(filename);
2096         assert(lvalue);
2097         assert(rvalue);
2098         assert(data);
2099
2100         if (isempty(rvalue)) {
2101                 /* Empty assignment resets the list */
2102                 condition_free_list(u->conditions);
2103                 u->conditions = NULL;
2104                 return 0;
2105         }
2106
2107         trigger = rvalue[0] == '|';
2108         if (trigger)
2109                 rvalue++;
2110
2111         negate = rvalue[0] == '!';
2112         if (negate)
2113                 rvalue++;
2114
2115         b = parse_boolean(rvalue);
2116         if (b < 0) {
2117                 log_syntax(unit, LOG_ERR, filename, line, -b,
2118                            "Failed to parse boolean value in condition, ignoring: %s",
2119                            rvalue);
2120                 return 0;
2121         }
2122
2123         if (!b)
2124                 negate = !negate;
2125
2126         c = condition_new(CONDITION_NULL, NULL, trigger, negate);
2127         if (!c)
2128                 return log_oom();
2129
2130         LIST_PREPEND(conditions, u->conditions, c);
2131         return 0;
2132 }
2133
2134 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
2135 DEFINE_CONFIG_PARSE_ENUM(config_parse_failure_action, failure_action, FailureAction, "Failed to parse failure action specifier");
2136
2137 int config_parse_unit_requires_mounts_for(
2138                 const char *unit,
2139                 const char *filename,
2140                 unsigned line,
2141                 const char *section,
2142                 unsigned section_line,
2143                 const char *lvalue,
2144                 int ltype,
2145                 const char *rvalue,
2146                 void *data,
2147                 void *userdata) {
2148
2149         Unit *u = userdata;
2150         const char *word, *state;
2151         size_t l;
2152
2153         assert(filename);
2154         assert(lvalue);
2155         assert(rvalue);
2156         assert(data);
2157
2158         FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2159                 int r;
2160                 _cleanup_free_ char *n;
2161
2162                 n = strndup(word, l);
2163                 if (!n)
2164                         return log_oom();
2165
2166                 if (!utf8_is_valid(n)) {
2167                         log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
2168                         continue;
2169                 }
2170
2171                 r = unit_require_mounts_for(u, n);
2172                 if (r < 0) {
2173                         log_syntax(unit, LOG_ERR, filename, line, -r,
2174                                    "Failed to add required mount for, ignoring: %s", rvalue);
2175                         continue;
2176                 }
2177         }
2178         if (!isempty(state))
2179                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2180                            "Trailing garbage, ignoring.");
2181
2182         return 0;
2183 }
2184
2185 int config_parse_documentation(const char *unit,
2186                                const char *filename,
2187                                unsigned line,
2188                                const char *section,
2189                                unsigned section_line,
2190                                const char *lvalue,
2191                                int ltype,
2192                                const char *rvalue,
2193                                void *data,
2194                                void *userdata) {
2195
2196         Unit *u = userdata;
2197         int r;
2198         char **a, **b;
2199
2200         assert(filename);
2201         assert(lvalue);
2202         assert(rvalue);
2203         assert(u);
2204
2205         if (isempty(rvalue)) {
2206                 /* Empty assignment resets the list */
2207                 strv_free(u->documentation);
2208                 u->documentation = NULL;
2209                 return 0;
2210         }
2211
2212         r = config_parse_unit_strv_printf(unit, filename, line, section, section_line, lvalue, ltype,
2213                                           rvalue, data, userdata);
2214         if (r < 0)
2215                 return r;
2216
2217         for (a = b = u->documentation; a && *a; a++) {
2218
2219                 if (is_valid_documentation_url(*a))
2220                         *(b++) = *a;
2221                 else {
2222                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2223                                    "Invalid URL, ignoring: %s", *a);
2224                         free(*a);
2225                 }
2226         }
2227         if (b)
2228                 *b = NULL;
2229
2230         return r;
2231 }
2232
2233 #ifdef HAVE_SECCOMP
2234 int config_parse_syscall_filter(
2235                 const char *unit,
2236                 const char *filename,
2237                 unsigned line,
2238                 const char *section,
2239                 unsigned section_line,
2240                 const char *lvalue,
2241                 int ltype,
2242                 const char *rvalue,
2243                 void *data,
2244                 void *userdata) {
2245
2246         static const char default_syscalls[] =
2247                 "execve\0"
2248                 "exit\0"
2249                 "exit_group\0"
2250                 "rt_sigreturn\0"
2251                 "sigreturn\0";
2252
2253         ExecContext *c = data;
2254         Unit *u = userdata;
2255         bool invert = false;
2256         const char *word, *state;
2257         size_t l;
2258         int r;
2259
2260         assert(filename);
2261         assert(lvalue);
2262         assert(rvalue);
2263         assert(u);
2264
2265         if (isempty(rvalue)) {
2266                 /* Empty assignment resets the list */
2267                 set_free(c->syscall_filter);
2268                 c->syscall_filter = NULL;
2269                 c->syscall_whitelist = false;
2270                 return 0;
2271         }
2272
2273         if (rvalue[0] == '~') {
2274                 invert = true;
2275                 rvalue++;
2276         }
2277
2278         if (!c->syscall_filter) {
2279                 c->syscall_filter = set_new(trivial_hash_func, trivial_compare_func);
2280                 if (!c->syscall_filter)
2281                         return log_oom();
2282
2283                 if (invert)
2284                         /* Allow everything but the ones listed */
2285                         c->syscall_whitelist = false;
2286                 else {
2287                         const char *i;
2288
2289                         /* Allow nothing but the ones listed */
2290                         c->syscall_whitelist = true;
2291
2292                         /* Accept default syscalls if we are on a whitelist */
2293                         NULSTR_FOREACH(i, default_syscalls)  {
2294                                 int id;
2295
2296                                 id = seccomp_syscall_resolve_name(i);
2297                                 if (id < 0)
2298                                         continue;
2299
2300                                 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2301                                 if (r == -EEXIST)
2302                                         continue;
2303                                 if (r < 0)
2304                                         return log_oom();
2305                         }
2306                 }
2307         }
2308
2309         FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2310                 _cleanup_free_ char *t = NULL;
2311                 int id;
2312
2313                 t = strndup(word, l);
2314                 if (!t)
2315                         return log_oom();
2316
2317                 id = seccomp_syscall_resolve_name(t);
2318                 if (id < 0)  {
2319                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2320                                    "Failed to parse system call, ignoring: %s", t);
2321                         continue;
2322                 }
2323
2324                 /* If we previously wanted to forbid a syscall and now
2325                  * we want to allow it, then remove it from the list
2326                  */
2327                 if (!invert == c->syscall_whitelist)  {
2328                         r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2329                         if (r == -EEXIST)
2330                                 continue;
2331                         if (r < 0)
2332                                 return log_oom();
2333                 } else
2334                         set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
2335         }
2336         if (!isempty(state))
2337                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2338                            "Trailing garbage, ignoring.");
2339
2340         /* Turn on NNP, but only if it wasn't configured explicitly
2341          * before, and only if we are in user mode. */
2342         if (!c->no_new_privileges_set && u->manager->running_as == SYSTEMD_USER)
2343                 c->no_new_privileges = true;
2344
2345         return 0;
2346 }
2347
2348 int config_parse_syscall_archs(
2349                 const char *unit,
2350                 const char *filename,
2351                 unsigned line,
2352                 const char *section,
2353                 unsigned section_line,
2354                 const char *lvalue,
2355                 int ltype,
2356                 const char *rvalue,
2357                 void *data,
2358                 void *userdata) {
2359
2360         Set **archs = data;
2361         const char *word, *state;
2362         size_t l;
2363         int r;
2364
2365         if (isempty(rvalue)) {
2366                 set_free(*archs);
2367                 *archs = NULL;
2368                 return 0;
2369         }
2370
2371         r = set_ensure_allocated(archs, trivial_hash_func, trivial_compare_func);
2372         if (r < 0)
2373                 return log_oom();
2374
2375         FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2376                 _cleanup_free_ char *t = NULL;
2377                 uint32_t a;
2378
2379                 t = strndup(word, l);
2380                 if (!t)
2381                         return log_oom();
2382
2383                 r = seccomp_arch_from_string(t, &a);
2384                 if (r < 0) {
2385                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2386                                    "Failed to parse system call architecture, ignoring: %s", t);
2387                         continue;
2388                 }
2389
2390                 r = set_put(*archs, UINT32_TO_PTR(a + 1));
2391                 if (r == -EEXIST)
2392                         continue;
2393                 if (r < 0)
2394                         return log_oom();
2395         }
2396         if (!isempty(state))
2397                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2398                            "Trailing garbage, ignoring.");
2399
2400         return 0;
2401 }
2402
2403 int config_parse_syscall_errno(
2404                 const char *unit,
2405                 const char *filename,
2406                 unsigned line,
2407                 const char *section,
2408                 unsigned section_line,
2409                 const char *lvalue,
2410                 int ltype,
2411                 const char *rvalue,
2412                 void *data,
2413                 void *userdata) {
2414
2415         ExecContext *c = data;
2416         int e;
2417
2418         assert(filename);
2419         assert(lvalue);
2420         assert(rvalue);
2421
2422         if (isempty(rvalue)) {
2423                 /* Empty assignment resets to KILL */
2424                 c->syscall_errno = 0;
2425                 return 0;
2426         }
2427
2428         e = errno_from_name(rvalue);
2429         if (e < 0) {
2430                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2431                            "Failed to parse error number, ignoring: %s", rvalue);
2432                 return 0;
2433         }
2434
2435         c->syscall_errno = e;
2436         return 0;
2437 }
2438
2439 int config_parse_address_families(
2440                 const char *unit,
2441                 const char *filename,
2442                 unsigned line,
2443                 const char *section,
2444                 unsigned section_line,
2445                 const char *lvalue,
2446                 int ltype,
2447                 const char *rvalue,
2448                 void *data,
2449                 void *userdata) {
2450
2451         ExecContext *c = data;
2452         Unit *u = userdata;
2453         bool invert = false;
2454         const char *word, *state;
2455         size_t l;
2456         int r;
2457
2458         assert(filename);
2459         assert(lvalue);
2460         assert(rvalue);
2461         assert(u);
2462
2463         if (isempty(rvalue)) {
2464                 /* Empty assignment resets the list */
2465                 set_free(c->address_families);
2466                 c->address_families = NULL;
2467                 c->address_families_whitelist = false;
2468                 return 0;
2469         }
2470
2471         if (rvalue[0] == '~') {
2472                 invert = true;
2473                 rvalue++;
2474         }
2475
2476         if (!c->address_families) {
2477                 c->address_families = set_new(trivial_hash_func, trivial_compare_func);
2478                 if (!c->address_families)
2479                         return log_oom();
2480
2481                 c->address_families_whitelist = !invert;
2482         }
2483
2484         FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2485                 _cleanup_free_ char *t = NULL;
2486                 int af;
2487
2488                 t = strndup(word, l);
2489                 if (!t)
2490                         return log_oom();
2491
2492                 af = af_from_name(t);
2493                 if (af <= 0)  {
2494                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2495                                    "Failed to parse address family, ignoring: %s", t);
2496                         continue;
2497                 }
2498
2499                 /* If we previously wanted to forbid an address family and now
2500                  * we want to allow it, then remove it from the list
2501                  */
2502                 if (!invert == c->address_families_whitelist)  {
2503                         r = set_put(c->address_families, INT_TO_PTR(af));
2504                         if (r == -EEXIST)
2505                                 continue;
2506                         if (r < 0)
2507                                 return log_oom();
2508                 } else
2509                         set_remove(c->address_families, INT_TO_PTR(af));
2510         }
2511         if (!isempty(state))
2512                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2513                            "Trailing garbage, ignoring.");
2514
2515         return 0;
2516 }
2517 #endif
2518
2519 int config_parse_unit_slice(
2520                 const char *unit,
2521                 const char *filename,
2522                 unsigned line,
2523                 const char *section,
2524                 unsigned section_line,
2525                 const char *lvalue,
2526                 int ltype,
2527                 const char *rvalue,
2528                 void *data,
2529                 void *userdata) {
2530
2531         _cleanup_free_ char *k = NULL;
2532         Unit *u = userdata, *slice;
2533         int r;
2534
2535         assert(filename);
2536         assert(lvalue);
2537         assert(rvalue);
2538         assert(u);
2539
2540         r = unit_name_printf(u, rvalue, &k);
2541         if (r < 0)
2542                 log_syntax(unit, LOG_ERR, filename, line, -r,
2543                            "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
2544         if (!k) {
2545                 k = strdup(rvalue);
2546                 if (!k)
2547                         return log_oom();
2548         }
2549
2550         r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
2551         if (r < 0) {
2552                 log_syntax(unit, LOG_ERR, filename, line, -r,
2553                            "Failed to load slice unit %s. Ignoring.", k);
2554                 return 0;
2555         }
2556
2557         if (slice->type != UNIT_SLICE) {
2558                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2559                            "Slice unit %s is not a slice. Ignoring.", k);
2560                 return 0;
2561         }
2562
2563         unit_ref_set(&u->slice, slice);
2564         return 0;
2565 }
2566
2567 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
2568
2569 int config_parse_cpu_shares(
2570                 const char *unit,
2571                 const char *filename,
2572                 unsigned line,
2573                 const char *section,
2574                 unsigned section_line,
2575                 const char *lvalue,
2576                 int ltype,
2577                 const char *rvalue,
2578                 void *data,
2579                 void *userdata) {
2580
2581         unsigned long *shares = data, lu;
2582         int r;
2583
2584         assert(filename);
2585         assert(lvalue);
2586         assert(rvalue);
2587
2588         if (isempty(rvalue)) {
2589                 *shares = (unsigned long) -1;
2590                 return 0;
2591         }
2592
2593         r = safe_atolu(rvalue, &lu);
2594         if (r < 0 || lu <= 0) {
2595                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2596                            "CPU shares '%s' invalid. Ignoring.", rvalue);
2597                 return 0;
2598         }
2599
2600         *shares = lu;
2601         return 0;
2602 }
2603
2604 int config_parse_cpu_quota(
2605                 const char *unit,
2606                 const char *filename,
2607                 unsigned line,
2608                 const char *section,
2609                 unsigned section_line,
2610                 const char *lvalue,
2611                 int ltype,
2612                 const char *rvalue,
2613                 void *data,
2614                 void *userdata) {
2615
2616         CGroupContext *c = data;
2617         double percent;
2618
2619         assert(filename);
2620         assert(lvalue);
2621         assert(rvalue);
2622
2623         if (isempty(rvalue)) {
2624                 c->cpu_quota_per_sec_usec = USEC_INFINITY;
2625                 return 0;
2626         }
2627
2628         if (!endswith(rvalue, "%")) {
2629
2630                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2631                            "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue);
2632                 return 0;
2633         }
2634
2635         if (sscanf(rvalue, "%lf%%", &percent) != 1 || percent <= 0) {
2636                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2637                            "CPU quota '%s' invalid. Ignoring.", rvalue);
2638                 return 0;
2639         }
2640
2641         c->cpu_quota_per_sec_usec = (usec_t) (percent * USEC_PER_SEC / 100);
2642
2643         return 0;
2644 }
2645
2646 int config_parse_memory_limit(
2647                 const char *unit,
2648                 const char *filename,
2649                 unsigned line,
2650                 const char *section,
2651                 unsigned section_line,
2652                 const char *lvalue,
2653                 int ltype,
2654                 const char *rvalue,
2655                 void *data,
2656                 void *userdata) {
2657
2658         CGroupContext *c = data;
2659         off_t bytes;
2660         int r;
2661
2662         if (isempty(rvalue)) {
2663                 c->memory_limit = (uint64_t) -1;
2664                 return 0;
2665         }
2666
2667         assert_cc(sizeof(uint64_t) == sizeof(off_t));
2668
2669         r = parse_size(rvalue, 1024, &bytes);
2670         if (r < 0) {
2671                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2672                            "Memory limit '%s' invalid. Ignoring.", rvalue);
2673                 return 0;
2674         }
2675
2676         c->memory_limit = (uint64_t) bytes;
2677         return 0;
2678 }
2679
2680 int config_parse_device_allow(
2681                 const char *unit,
2682                 const char *filename,
2683                 unsigned line,
2684                 const char *section,
2685                 unsigned section_line,
2686                 const char *lvalue,
2687                 int ltype,
2688                 const char *rvalue,
2689                 void *data,
2690                 void *userdata) {
2691
2692         _cleanup_free_ char *path = NULL;
2693         CGroupContext *c = data;
2694         CGroupDeviceAllow *a;
2695         const char *m;
2696         size_t n;
2697
2698         if (isempty(rvalue)) {
2699                 while (c->device_allow)
2700                         cgroup_context_free_device_allow(c, c->device_allow);
2701
2702                 return 0;
2703         }
2704
2705         n = strcspn(rvalue, WHITESPACE);
2706         path = strndup(rvalue, n);
2707         if (!path)
2708                 return log_oom();
2709
2710         if (!startswith(path, "/dev/") &&
2711             !startswith(path, "block-") &&
2712             !startswith(path, "char-")) {
2713                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2714                            "Invalid device node path '%s'. Ignoring.", path);
2715                 return 0;
2716         }
2717
2718         m = rvalue + n + strspn(rvalue + n, WHITESPACE);
2719         if (isempty(m))
2720                 m = "rwm";
2721
2722         if (!in_charset(m, "rwm")) {
2723                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2724                            "Invalid device rights '%s'. Ignoring.", m);
2725                 return 0;
2726         }
2727
2728         a = new0(CGroupDeviceAllow, 1);
2729         if (!a)
2730                 return log_oom();
2731
2732         a->path = path;
2733         path = NULL;
2734         a->r = !!strchr(m, 'r');
2735         a->w = !!strchr(m, 'w');
2736         a->m = !!strchr(m, 'm');
2737
2738         LIST_PREPEND(device_allow, c->device_allow, a);
2739         return 0;
2740 }
2741
2742 int config_parse_blockio_weight(
2743                 const char *unit,
2744                 const char *filename,
2745                 unsigned line,
2746                 const char *section,
2747                 unsigned section_line,
2748                 const char *lvalue,
2749                 int ltype,
2750                 const char *rvalue,
2751                 void *data,
2752                 void *userdata) {
2753
2754         unsigned long *weight = data, lu;
2755         int r;
2756
2757         assert(filename);
2758         assert(lvalue);
2759         assert(rvalue);
2760
2761         if (isempty(rvalue)) {
2762                 *weight = (unsigned long) -1;
2763                 return 0;
2764         }
2765
2766         r = safe_atolu(rvalue, &lu);
2767         if (r < 0 || lu < 10 || lu > 1000) {
2768                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2769                            "Block IO weight '%s' invalid. Ignoring.", rvalue);
2770                 return 0;
2771         }
2772
2773         *weight = lu;
2774         return 0;
2775 }
2776
2777 int config_parse_blockio_device_weight(
2778                 const char *unit,
2779                 const char *filename,
2780                 unsigned line,
2781                 const char *section,
2782                 unsigned section_line,
2783                 const char *lvalue,
2784                 int ltype,
2785                 const char *rvalue,
2786                 void *data,
2787                 void *userdata) {
2788
2789         _cleanup_free_ char *path = NULL;
2790         CGroupBlockIODeviceWeight *w;
2791         CGroupContext *c = data;
2792         unsigned long lu;
2793         const char *weight;
2794         size_t n;
2795         int r;
2796
2797         assert(filename);
2798         assert(lvalue);
2799         assert(rvalue);
2800
2801         if (isempty(rvalue)) {
2802                 while (c->blockio_device_weights)
2803                         cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
2804
2805                 return 0;
2806         }
2807
2808         n = strcspn(rvalue, WHITESPACE);
2809         weight = rvalue + n;
2810         if (!*weight) {
2811                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2812                            "Expected block device and device weight. Ignoring.");
2813                 return 0;
2814         }
2815
2816         path = strndup(rvalue, n);
2817         if (!path)
2818                 return log_oom();
2819
2820         if (!path_startswith(path, "/dev")) {
2821                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2822                            "Invalid device node path '%s'. Ignoring.", path);
2823                 return 0;
2824         }
2825
2826         weight += strspn(weight, WHITESPACE);
2827         r = safe_atolu(weight, &lu);
2828         if (r < 0 || lu < 10 || lu > 1000) {
2829                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2830                            "Block IO weight '%s' invalid. Ignoring.", rvalue);
2831                 return 0;
2832         }
2833
2834         w = new0(CGroupBlockIODeviceWeight, 1);
2835         if (!w)
2836                 return log_oom();
2837
2838         w->path = path;
2839         path = NULL;
2840
2841         w->weight = lu;
2842
2843         LIST_PREPEND(device_weights, c->blockio_device_weights, w);
2844         return 0;
2845 }
2846
2847 int config_parse_blockio_bandwidth(
2848                 const char *unit,
2849                 const char *filename,
2850                 unsigned line,
2851                 const char *section,
2852                 unsigned section_line,
2853                 const char *lvalue,
2854                 int ltype,
2855                 const char *rvalue,
2856                 void *data,
2857                 void *userdata) {
2858
2859         _cleanup_free_ char *path = NULL;
2860         CGroupBlockIODeviceBandwidth *b;
2861         CGroupContext *c = data;
2862         const char *bandwidth;
2863         off_t bytes;
2864         bool read;
2865         size_t n;
2866         int r;
2867
2868         assert(filename);
2869         assert(lvalue);
2870         assert(rvalue);
2871
2872         read = streq("BlockIOReadBandwidth", lvalue);
2873
2874         if (isempty(rvalue)) {
2875                 CGroupBlockIODeviceBandwidth *next;
2876
2877                 LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
2878                         if (b->read == read)
2879                                 cgroup_context_free_blockio_device_bandwidth(c, b);
2880
2881                 return 0;
2882         }
2883
2884         n = strcspn(rvalue, WHITESPACE);
2885         bandwidth = rvalue + n;
2886         bandwidth += strspn(bandwidth, WHITESPACE);
2887
2888         if (!*bandwidth) {
2889                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2890                            "Expected space separated pair of device node and bandwidth. Ignoring.");
2891                 return 0;
2892         }
2893
2894         path = strndup(rvalue, n);
2895         if (!path)
2896                 return log_oom();
2897
2898         if (!path_startswith(path, "/dev")) {
2899                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2900                            "Invalid device node path '%s'. Ignoring.", path);
2901                 return 0;
2902         }
2903
2904         r = parse_size(bandwidth, 1000, &bytes);
2905         if (r < 0 || bytes <= 0) {
2906                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2907                            "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
2908                 return 0;
2909         }
2910
2911         b = new0(CGroupBlockIODeviceBandwidth, 1);
2912         if (!b)
2913                 return log_oom();
2914
2915         b->path = path;
2916         path = NULL;
2917         b->bandwidth = (uint64_t) bytes;
2918         b->read = read;
2919
2920         LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
2921
2922         return 0;
2923 }
2924
2925 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
2926
2927 int config_parse_job_mode_isolate(
2928                 const char *unit,
2929                 const char *filename,
2930                 unsigned line,
2931                 const char *section,
2932                 unsigned section_line,
2933                 const char *lvalue,
2934                 int ltype,
2935                 const char *rvalue,
2936                 void *data,
2937                 void *userdata) {
2938
2939         JobMode *m = data;
2940         int r;
2941
2942         assert(filename);
2943         assert(lvalue);
2944         assert(rvalue);
2945
2946         r = parse_boolean(rvalue);
2947         if (r < 0) {
2948                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2949                            "Failed to parse boolean, ignoring: %s", rvalue);
2950                 return 0;
2951         }
2952
2953         *m = r ? JOB_ISOLATE : JOB_REPLACE;
2954         return 0;
2955 }
2956
2957 int config_parse_personality(
2958                 const char *unit,
2959                 const char *filename,
2960                 unsigned line,
2961                 const char *section,
2962                 unsigned section_line,
2963                 const char *lvalue,
2964                 int ltype,
2965                 const char *rvalue,
2966                 void *data,
2967                 void *userdata) {
2968
2969         unsigned long *personality = data, p;
2970
2971         assert(filename);
2972         assert(lvalue);
2973         assert(rvalue);
2974         assert(personality);
2975
2976         p = personality_from_string(rvalue);
2977         if (p == 0xffffffffUL) {
2978                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2979                            "Failed to parse personality, ignoring: %s", rvalue);
2980                 return 0;
2981         }
2982
2983         *personality = p;
2984         return 0;
2985 }
2986
2987 int config_parse_runtime_directory(
2988                 const char *unit,
2989                 const char *filename,
2990                 unsigned line,
2991                 const char *section,
2992                 unsigned section_line,
2993                 const char *lvalue,
2994                 int ltype,
2995                 const char *rvalue,
2996                 void *data,
2997                 void *userdata) {
2998
2999         char***rt = data;
3000         const char *word, *state;
3001         size_t l;
3002         int r;
3003
3004         assert(filename);
3005         assert(lvalue);
3006         assert(rvalue);
3007         assert(data);
3008
3009         if (isempty(rvalue)) {
3010                 /* Empty assignment resets the list */
3011                 strv_free(*rt);
3012                 *rt = NULL;
3013                 return 0;
3014         }
3015
3016         FOREACH_WORD_QUOTED(word, l, rvalue, state) {
3017                 _cleanup_free_ char *n;
3018
3019                 n = strndup(word, l);
3020                 if (!n)
3021                         return log_oom();
3022
3023                 if (!filename_is_safe(n)) {
3024                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3025                                    "Runtime directory is not valid, ignoring assignment: %s", rvalue);
3026                         continue;
3027                 }
3028
3029                 r = strv_push(rt, n);
3030                 if (r < 0)
3031                         return log_oom();
3032
3033                 n = NULL;
3034         }
3035         if (!isempty(state))
3036                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3037                            "Trailing garbage, ignoring.");
3038
3039         return 0;
3040 }
3041
3042 int config_parse_set_status(
3043                 const char *unit,
3044                 const char *filename,
3045                 unsigned line,
3046                 const char *section,
3047                 unsigned section_line,
3048                 const char *lvalue,
3049                 int ltype,
3050                 const char *rvalue,
3051                 void *data,
3052                 void *userdata) {
3053
3054         size_t l;
3055         const char *word, *state;
3056         int r;
3057         ExitStatusSet *status_set = data;
3058
3059         assert(filename);
3060         assert(lvalue);
3061         assert(rvalue);
3062         assert(data);
3063
3064         /* Empty assignment resets the list */
3065         if (isempty(rvalue)) {
3066                 exit_status_set_free(status_set);
3067                 return 0;
3068         }
3069
3070         FOREACH_WORD(word, l, rvalue, state) {
3071                 _cleanup_free_ char *temp;
3072                 int val;
3073
3074                 temp = strndup(word, l);
3075                 if (!temp)
3076                         return log_oom();
3077
3078                 r = safe_atoi(temp, &val);
3079                 if (r < 0) {
3080                         val = signal_from_string_try_harder(temp);
3081
3082                         if (val <= 0) {
3083                                 log_syntax(unit, LOG_ERR, filename, line, -val,
3084                                            "Failed to parse value, ignoring: %s", word);
3085                                 return 0;
3086                         }
3087                 } else {
3088                         if (val < 0 || val > 255) {
3089                                 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
3090                                            "Value %d is outside range 0-255, ignoring", val);
3091                                 continue;
3092                         }
3093                 }
3094
3095                 r = set_ensure_allocated(&status_set->status, NULL, NULL);
3096                 if (r < 0)
3097                         return log_oom();
3098
3099                 r = set_put(status_set->status, INT_TO_PTR(val));
3100                 if (r < 0) {
3101                         log_syntax(unit, LOG_ERR, filename, line, -r,
3102                                    "Unable to store: %s", word);
3103                         return r;
3104                 }
3105         }
3106         if (!isempty(state))
3107                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3108                            "Trailing garbage, ignoring.");
3109
3110         return 0;
3111 }
3112
3113 int config_parse_namespace_path_strv(
3114                 const char *unit,
3115                 const char *filename,
3116                 unsigned line,
3117                 const char *section,
3118                 unsigned section_line,
3119                 const char *lvalue,
3120                 int ltype,
3121                 const char *rvalue,
3122                 void *data,
3123                 void *userdata) {
3124
3125         char*** sv = data;
3126         const char *word, *state;
3127         size_t l;
3128         int r;
3129
3130         assert(filename);
3131         assert(lvalue);
3132         assert(rvalue);
3133         assert(data);
3134
3135         if (isempty(rvalue)) {
3136                 /* Empty assignment resets the list */
3137                 strv_free(*sv);
3138                 *sv = NULL;
3139                 return 0;
3140         }
3141
3142         FOREACH_WORD_QUOTED(word, l, rvalue, state) {
3143                 _cleanup_free_ char *n;
3144                 int offset;
3145
3146                 n = strndup(word, l);
3147                 if (!n)
3148                         return log_oom();
3149
3150                 if (!utf8_is_valid(n)) {
3151                         log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
3152                         continue;
3153                 }
3154
3155                 offset = n[0] == '-';
3156                 if (!path_is_absolute(n + offset)) {
3157                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3158                                    "Not an absolute path, ignoring: %s", rvalue);
3159                         continue;
3160                 }
3161
3162                 path_kill_slashes(n);
3163
3164                 r = strv_push(sv, n);
3165                 if (r < 0)
3166                         return log_oom();
3167
3168                 n = NULL;
3169         }
3170         if (!isempty(state))
3171                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3172                            "Trailing garbage, ignoring.");
3173
3174         return 0;
3175 }
3176
3177 int config_parse_no_new_privileges(
3178                 const char* unit,
3179                 const char *filename,
3180                 unsigned line,
3181                 const char *section,
3182                 unsigned section_line,
3183                 const char *lvalue,
3184                 int ltype,
3185                 const char *rvalue,
3186                 void *data,
3187                 void *userdata) {
3188
3189         ExecContext *c = data;
3190         int k;
3191
3192         assert(filename);
3193         assert(lvalue);
3194         assert(rvalue);
3195         assert(data);
3196
3197         k = parse_boolean(rvalue);
3198         if (k < 0) {
3199                 log_syntax(unit, LOG_ERR, filename, line, -k,
3200                            "Failed to parse boolean value, ignoring: %s", rvalue);
3201                 return 0;
3202         }
3203
3204         c->no_new_privileges = !!k;
3205         c->no_new_privileges_set = true;
3206
3207         return 0;
3208 }
3209
3210 int config_parse_protect_home(
3211                 const char* unit,
3212                 const char *filename,
3213                 unsigned line,
3214                 const char *section,
3215                 unsigned section_line,
3216                 const char *lvalue,
3217                 int ltype,
3218                 const char *rvalue,
3219                 void *data,
3220                 void *userdata) {
3221
3222         ExecContext *c = data;
3223         int k;
3224
3225         assert(filename);
3226         assert(lvalue);
3227         assert(rvalue);
3228         assert(data);
3229
3230         /* Our enum shall be a superset of booleans, hence first try
3231          * to parse as as boolean, and then as enum */
3232
3233         k = parse_boolean(rvalue);
3234         if (k > 0)
3235                 c->protect_home = PROTECT_HOME_YES;
3236         else if (k == 0)
3237                 c->protect_home = PROTECT_HOME_NO;
3238         else {
3239                 ProtectHome h;
3240
3241                 h = protect_home_from_string(rvalue);
3242                 if (h < 0){
3243                         log_syntax(unit, LOG_ERR, filename, line, -h,
3244                                    "Failed to parse protect home value, ignoring: %s", rvalue);
3245                         return 0;
3246                 }
3247
3248                 c->protect_home = h;
3249         }
3250
3251         return 0;
3252 }
3253
3254 int config_parse_protect_system(
3255                 const char* unit,
3256                 const char *filename,
3257                 unsigned line,
3258                 const char *section,
3259                 unsigned section_line,
3260                 const char *lvalue,
3261                 int ltype,
3262                 const char *rvalue,
3263                 void *data,
3264                 void *userdata) {
3265
3266         ExecContext *c = data;
3267         int k;
3268
3269         assert(filename);
3270         assert(lvalue);
3271         assert(rvalue);
3272         assert(data);
3273
3274         /* Our enum shall be a superset of booleans, hence first try
3275          * to parse as as boolean, and then as enum */
3276
3277         k = parse_boolean(rvalue);
3278         if (k > 0)
3279                 c->protect_system = PROTECT_SYSTEM_YES;
3280         else if (k == 0)
3281                 c->protect_system = PROTECT_SYSTEM_NO;
3282         else {
3283                 ProtectSystem s;
3284
3285                 s = protect_system_from_string(rvalue);
3286                 if (s < 0){
3287                         log_syntax(unit, LOG_ERR, filename, line, -s,
3288                                    "Failed to parse protect system value, ignoring: %s", rvalue);
3289                         return 0;
3290                 }
3291
3292                 c->protect_system = s;
3293         }
3294
3295         return 0;
3296 }
3297
3298 #define FOLLOW_MAX 8
3299
3300 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
3301         unsigned c = 0;
3302         int fd, r;
3303         FILE *f;
3304         char *id = NULL;
3305
3306         assert(filename);
3307         assert(*filename);
3308         assert(_f);
3309         assert(names);
3310
3311         /* This will update the filename pointer if the loaded file is
3312          * reached by a symlink. The old string will be freed. */
3313
3314         for (;;) {
3315                 char *target, *name;
3316
3317                 if (c++ >= FOLLOW_MAX)
3318                         return -ELOOP;
3319
3320                 path_kill_slashes(*filename);
3321
3322                 /* Add the file name we are currently looking at to
3323                  * the names of this unit, but only if it is a valid
3324                  * unit name. */
3325                 name = basename(*filename);
3326
3327                 if (unit_name_is_valid(name, TEMPLATE_VALID)) {
3328
3329                         id = set_get(names, name);
3330                         if (!id) {
3331                                 id = strdup(name);
3332                                 if (!id)
3333                                         return -ENOMEM;
3334
3335                                 r = set_consume(names, id);
3336                                 if (r < 0)
3337                                         return r;
3338                         }
3339                 }
3340
3341                 /* Try to open the file name, but don't if its a symlink */
3342                 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
3343                 if (fd >= 0)
3344                         break;
3345
3346                 if (errno != ELOOP)
3347                         return -errno;
3348
3349                 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
3350                 r = readlink_and_make_absolute(*filename, &target);
3351                 if (r < 0)
3352                         return r;
3353
3354                 free(*filename);
3355                 *filename = target;
3356         }
3357
3358         f = fdopen(fd, "re");
3359         if (!f) {
3360                 r = -errno;
3361                 safe_close(fd);
3362                 return r;
3363         }
3364
3365         *_f = f;
3366         *_final = id;
3367         return 0;
3368 }
3369
3370 static int merge_by_names(Unit **u, Set *names, const char *id) {
3371         char *k;
3372         int r;
3373
3374         assert(u);
3375         assert(*u);
3376         assert(names);
3377
3378         /* Let's try to add in all symlink names we found */
3379         while ((k = set_steal_first(names))) {
3380
3381                 /* First try to merge in the other name into our
3382                  * unit */
3383                 r = unit_merge_by_name(*u, k);
3384                 if (r < 0) {
3385                         Unit *other;
3386
3387                         /* Hmm, we couldn't merge the other unit into
3388                          * ours? Then let's try it the other way
3389                          * round */
3390
3391                         other = manager_get_unit((*u)->manager, k);
3392                         free(k);
3393
3394                         if (other) {
3395                                 r = unit_merge(other, *u);
3396                                 if (r >= 0) {
3397                                         *u = other;
3398                                         return merge_by_names(u, names, NULL);
3399                                 }
3400                         }
3401
3402                         return r;
3403                 }
3404
3405                 if (id == k)
3406                         unit_choose_id(*u, id);
3407
3408                 free(k);
3409         }
3410
3411         return 0;
3412 }
3413
3414 static int load_from_path(Unit *u, const char *path) {
3415         int r;
3416         _cleanup_set_free_free_ Set *symlink_names = NULL;
3417         _cleanup_fclose_ FILE *f = NULL;
3418         _cleanup_free_ char *filename = NULL;
3419         char *id = NULL;
3420         Unit *merged;
3421         struct stat st;
3422
3423         assert(u);
3424         assert(path);
3425
3426         symlink_names = set_new(string_hash_func, string_compare_func);
3427         if (!symlink_names)
3428                 return -ENOMEM;
3429
3430         if (path_is_absolute(path)) {
3431
3432                 filename = strdup(path);
3433                 if (!filename)
3434                         return -ENOMEM;
3435
3436                 r = open_follow(&filename, &f, symlink_names, &id);
3437                 if (r < 0) {
3438                         free(filename);
3439                         filename = NULL;
3440
3441                         if (r != -ENOENT)
3442                                 return r;
3443                 }
3444
3445         } else  {
3446                 char **p;
3447
3448                 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
3449
3450                         /* Instead of opening the path right away, we manually
3451                          * follow all symlinks and add their name to our unit
3452                          * name set while doing so */
3453                         filename = path_make_absolute(path, *p);
3454                         if (!filename)
3455                                 return -ENOMEM;
3456
3457                         if (u->manager->unit_path_cache &&
3458                             !set_get(u->manager->unit_path_cache, filename))
3459                                 r = -ENOENT;
3460                         else
3461                                 r = open_follow(&filename, &f, symlink_names, &id);
3462
3463                         if (r < 0) {
3464                                 free(filename);
3465                                 filename = NULL;
3466
3467                                 if (r != -ENOENT)
3468                                         return r;
3469
3470                                 /* Empty the symlink names for the next run */
3471                                 set_clear_free(symlink_names);
3472                                 continue;
3473                         }
3474
3475                         break;
3476                 }
3477         }
3478
3479         if (!filename)
3480                 /* Hmm, no suitable file found? */
3481                 return 0;
3482
3483         merged = u;
3484         r = merge_by_names(&merged, symlink_names, id);
3485         if (r < 0)
3486                 return r;
3487
3488         if (merged != u) {
3489                 u->load_state = UNIT_MERGED;
3490                 return 0;
3491         }
3492
3493         if (fstat(fileno(f), &st) < 0)
3494                 return -errno;
3495
3496         if (null_or_empty(&st))
3497                 u->load_state = UNIT_MASKED;
3498         else {
3499                 u->load_state = UNIT_LOADED;
3500
3501                 /* Now, parse the file contents */
3502                 r = config_parse(u->id, filename, f,
3503                                  UNIT_VTABLE(u)->sections,
3504                                  config_item_perf_lookup, load_fragment_gperf_lookup,
3505                                  false, true, false, u);
3506                 if (r < 0)
3507                         return r;
3508         }
3509
3510         free(u->fragment_path);
3511         u->fragment_path = filename;
3512         filename = NULL;
3513
3514         u->fragment_mtime = timespec_load(&st.st_mtim);
3515
3516         if (u->source_path) {
3517                 if (stat(u->source_path, &st) >= 0)
3518                         u->source_mtime = timespec_load(&st.st_mtim);
3519                 else
3520                         u->source_mtime = 0;
3521         }
3522
3523         return 0;
3524 }
3525
3526 int unit_load_fragment(Unit *u) {
3527         int r;
3528         Iterator i;
3529         const char *t;
3530
3531         assert(u);
3532         assert(u->load_state == UNIT_STUB);
3533         assert(u->id);
3534
3535         /* First, try to find the unit under its id. We always look
3536          * for unit files in the default directories, to make it easy
3537          * to override things by placing things in /etc/systemd/system */
3538         r = load_from_path(u, u->id);
3539         if (r < 0)
3540                 return r;
3541
3542         /* Try to find an alias we can load this with */
3543         if (u->load_state == UNIT_STUB)
3544                 SET_FOREACH(t, u->names, i) {
3545
3546                         if (t == u->id)
3547                                 continue;
3548
3549                         r = load_from_path(u, t);
3550                         if (r < 0)
3551                                 return r;
3552
3553                         if (u->load_state != UNIT_STUB)
3554                                 break;
3555                 }
3556
3557         /* And now, try looking for it under the suggested (originally linked) path */
3558         if (u->load_state == UNIT_STUB && u->fragment_path) {
3559
3560                 r = load_from_path(u, u->fragment_path);
3561                 if (r < 0)
3562                         return r;
3563
3564                 if (u->load_state == UNIT_STUB) {
3565                         /* Hmm, this didn't work? Then let's get rid
3566                          * of the fragment path stored for us, so that
3567                          * we don't point to an invalid location. */
3568                         free(u->fragment_path);
3569                         u->fragment_path = NULL;
3570                 }
3571         }
3572
3573         /* Look for a template */
3574         if (u->load_state == UNIT_STUB && u->instance) {
3575                 _cleanup_free_ char *k;
3576
3577                 k = unit_name_template(u->id);
3578                 if (!k)
3579                         return -ENOMEM;
3580
3581                 r = load_from_path(u, k);
3582                 if (r < 0)
3583                         return r;
3584
3585                 if (u->load_state == UNIT_STUB)
3586                         SET_FOREACH(t, u->names, i) {
3587                                 _cleanup_free_ char *z = NULL;
3588
3589                                 if (t == u->id)
3590                                         continue;
3591
3592                                 z = unit_name_template(t);
3593                                 if (!z)
3594                                         return -ENOMEM;
3595
3596                                 r = load_from_path(u, z);
3597                                 if (r < 0)
3598                                         return r;
3599
3600                                 if (u->load_state != UNIT_STUB)
3601                                         break;
3602                         }
3603         }
3604
3605         return 0;
3606 }
3607
3608 void unit_dump_config_items(FILE *f) {
3609         static const struct {
3610                 const ConfigParserCallback callback;
3611                 const char *rvalue;
3612         } table[] = {