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