chiark / gitweb /
smack: introduce new SmackProcessLabel option
[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_exec_smack_process_label(
1317                 const char *unit,
1318                 const char *filename,
1319                 unsigned line,
1320                 const char *section,
1321                 unsigned section_line,
1322                 const char *lvalue,
1323                 int ltype,
1324                 const char *rvalue,
1325                 void *data,
1326                 void *userdata) {
1327
1328         ExecContext *c = data;
1329         Unit *u = userdata;
1330         bool ignore;
1331         char *k;
1332         int r;
1333
1334         assert(filename);
1335         assert(lvalue);
1336         assert(rvalue);
1337         assert(data);
1338
1339         if (isempty(rvalue)) {
1340                 free(c->smack_process_label);
1341                 c->smack_process_label = NULL;
1342                 c->smack_process_label_ignore = false;
1343                 return 0;
1344         }
1345
1346         if (rvalue[0] == '-') {
1347                 ignore = true;
1348                 rvalue++;
1349         } else
1350                 ignore = false;
1351
1352         r = unit_name_printf(u, rvalue, &k);
1353         if (r < 0) {
1354                 log_syntax(unit, LOG_ERR, filename, line, -r,
1355                            "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1356                 return 0;
1357         }
1358
1359         free(c->smack_process_label);
1360         c->smack_process_label = k;
1361         c->smack_process_label_ignore = ignore;
1362
1363         return 0;
1364 }
1365
1366 int config_parse_timer(const char *unit,
1367                        const char *filename,
1368                        unsigned line,
1369                        const char *section,
1370                        unsigned section_line,
1371                        const char *lvalue,
1372                        int ltype,
1373                        const char *rvalue,
1374                        void *data,
1375                        void *userdata) {
1376
1377         Timer *t = data;
1378         usec_t u = 0;
1379         TimerValue *v;
1380         TimerBase b;
1381         CalendarSpec *c = NULL;
1382
1383         assert(filename);
1384         assert(lvalue);
1385         assert(rvalue);
1386         assert(data);
1387
1388         if (isempty(rvalue)) {
1389                 /* Empty assignment resets list */
1390                 timer_free_values(t);
1391                 return 0;
1392         }
1393
1394         b = timer_base_from_string(lvalue);
1395         if (b < 0) {
1396                 log_syntax(unit, LOG_ERR, filename, line, -b,
1397                            "Failed to parse timer base, ignoring: %s", lvalue);
1398                 return 0;
1399         }
1400
1401         if (b == TIMER_CALENDAR) {
1402                 if (calendar_spec_from_string(rvalue, &c) < 0) {
1403                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1404                                    "Failed to parse calendar specification, ignoring: %s",
1405                                    rvalue);
1406                         return 0;
1407                 }
1408         } else {
1409                 if (parse_sec(rvalue, &u) < 0) {
1410                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1411                                    "Failed to parse timer value, ignoring: %s",
1412                                    rvalue);
1413                         return 0;
1414                 }
1415         }
1416
1417         v = new0(TimerValue, 1);
1418         if (!v) {
1419                 calendar_spec_free(c);
1420                 return log_oom();
1421         }
1422
1423         v->base = b;
1424         v->value = u;
1425         v->calendar_spec = c;
1426
1427         LIST_PREPEND(value, t->values, v);
1428
1429         return 0;
1430 }
1431
1432 int config_parse_trigger_unit(
1433                 const char *unit,
1434                 const char *filename,
1435                 unsigned line,
1436                 const char *section,
1437                 unsigned section_line,
1438                 const char *lvalue,
1439                 int ltype,
1440                 const char *rvalue,
1441                 void *data,
1442                 void *userdata) {
1443
1444         _cleanup_free_ char *p = NULL;
1445         Unit *u = data;
1446         UnitType type;
1447         int r;
1448
1449         assert(filename);
1450         assert(lvalue);
1451         assert(rvalue);
1452         assert(data);
1453
1454         if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
1455                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1456                            "Multiple units to trigger specified, ignoring: %s", rvalue);
1457                 return 0;
1458         }
1459
1460         r = unit_name_printf(u, rvalue, &p);
1461         if (r < 0)
1462                 log_syntax(unit, LOG_ERR, filename, line, -r,
1463                            "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1464
1465         type = unit_name_to_type(p ?: rvalue);
1466         if (type < 0) {
1467                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1468                            "Unit type not valid, ignoring: %s", rvalue);
1469                 return 0;
1470         }
1471
1472         if (type == u->type) {
1473                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1474                            "Trigger cannot be of same type, ignoring: %s", rvalue);
1475                 return 0;
1476         }
1477
1478         r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p ?: rvalue, NULL, true);
1479         if (r < 0) {
1480                 log_syntax(unit, LOG_ERR, filename, line, -r,
1481                            "Failed to add trigger on %s, ignoring: %s", p ?: rvalue, strerror(-r));
1482                 return 0;
1483         }
1484
1485         return 0;
1486 }
1487
1488 int config_parse_path_spec(const char *unit,
1489                            const char *filename,
1490                            unsigned line,
1491                            const char *section,
1492                            unsigned section_line,
1493                            const char *lvalue,
1494                            int ltype,
1495                            const char *rvalue,
1496                            void *data,
1497                            void *userdata) {
1498
1499         Path *p = data;
1500         PathSpec *s;
1501         PathType b;
1502         _cleanup_free_ char *k = NULL;
1503         int r;
1504
1505         assert(filename);
1506         assert(lvalue);
1507         assert(rvalue);
1508         assert(data);
1509
1510         if (isempty(rvalue)) {
1511                 /* Empty assignment clears list */
1512                 path_free_specs(p);
1513                 return 0;
1514         }
1515
1516         b = path_type_from_string(lvalue);
1517         if (b < 0) {
1518                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1519                            "Failed to parse path type, ignoring: %s", lvalue);
1520                 return 0;
1521         }
1522
1523         r = unit_full_printf(UNIT(p), rvalue, &k);
1524         if (r < 0) {
1525                 k = strdup(rvalue);
1526                 if (!k)
1527                         return log_oom();
1528                 else
1529                         log_syntax(unit, LOG_ERR, filename, line, -r,
1530                                    "Failed to resolve unit specifiers on %s. Ignoring.",
1531                                    rvalue);
1532         }
1533
1534         if (!path_is_absolute(k)) {
1535                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1536                            "Path is not absolute, ignoring: %s", k);
1537                 return 0;
1538         }
1539
1540         s = new0(PathSpec, 1);
1541         if (!s)
1542                 return log_oom();
1543
1544         s->unit = UNIT(p);
1545         s->path = path_kill_slashes(k);
1546         k = NULL;
1547         s->type = b;
1548         s->inotify_fd = -1;
1549
1550         LIST_PREPEND(spec, p->specs, s);
1551
1552         return 0;
1553 }
1554
1555 int config_parse_socket_service(const char *unit,
1556                                 const char *filename,
1557                                 unsigned line,
1558                                 const char *section,
1559                                 unsigned section_line,
1560                                 const char *lvalue,
1561                                 int ltype,
1562                                 const char *rvalue,
1563                                 void *data,
1564                                 void *userdata) {
1565
1566         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1567         Socket *s = data;
1568         int r;
1569         Unit *x;
1570         _cleanup_free_ char *p = NULL;
1571
1572         assert(filename);
1573         assert(lvalue);
1574         assert(rvalue);
1575         assert(data);
1576
1577         r = unit_name_printf(UNIT(s), rvalue, &p);
1578         if (r < 0) {
1579                 log_syntax(unit, LOG_ERR, filename, line, -r,
1580                            "Failed to resolve specifiers, ignoring: %s", rvalue);
1581                 return 0;
1582         }
1583
1584         if (!endswith(p, ".service")) {
1585                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1586                            "Unit must be of type service, ignoring: %s", rvalue);
1587                 return 0;
1588         }
1589
1590         r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
1591         if (r < 0) {
1592                 log_syntax(unit, LOG_ERR, filename, line, -r,
1593                            "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1594                 return 0;
1595         }
1596
1597         unit_ref_set(&s->service, x);
1598
1599         return 0;
1600 }
1601
1602 int config_parse_service_sockets(const char *unit,
1603                                  const char *filename,
1604                                  unsigned line,
1605                                  const char *section,
1606                                  unsigned section_line,
1607                                  const char *lvalue,
1608                                  int ltype,
1609                                  const char *rvalue,
1610                                  void *data,
1611                                  void *userdata) {
1612
1613         Service *s = data;
1614         int r;
1615         const char *word, *state;
1616         size_t l;
1617
1618         assert(filename);
1619         assert(lvalue);
1620         assert(rvalue);
1621         assert(data);
1622
1623         FOREACH_WORD_QUOTED(word, l, rvalue, state) {
1624                 _cleanup_free_ char *t = NULL, *k = NULL;
1625
1626                 t = strndup(word, l);
1627                 if (!t)
1628                         return log_oom();
1629
1630                 r = unit_name_printf(UNIT(s), t, &k);
1631                 if (r < 0)
1632                         log_syntax(unit, LOG_ERR, filename, line, -r,
1633                                    "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1634
1635                 if (!endswith(k ?: t, ".socket")) {
1636                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1637                                    "Unit must be of type socket, ignoring: %s", k ?: t);
1638                         continue;
1639                 }
1640
1641                 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k ?: t, NULL, true);
1642                 if (r < 0)
1643                         log_syntax(unit, LOG_ERR, filename, line, -r,
1644                                    "Failed to add dependency on %s, ignoring: %s",
1645                                    k ?: t, strerror(-r));
1646
1647                 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k ?: t, NULL, true);
1648                 if (r < 0)
1649                         return r;
1650         }
1651         if (!isempty(state))
1652                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1653                            "Trailing garbage, ignoring.");
1654
1655         return 0;
1656 }
1657
1658 int config_parse_service_timeout(const char *unit,
1659                                  const char *filename,
1660                                  unsigned line,
1661                                  const char *section,
1662                                  unsigned section_line,
1663                                  const char *lvalue,
1664                                  int ltype,
1665                                  const char *rvalue,
1666                                  void *data,
1667                                  void *userdata) {
1668
1669         Service *s = userdata;
1670         int r;
1671
1672         assert(filename);
1673         assert(lvalue);
1674         assert(rvalue);
1675         assert(s);
1676
1677         r = config_parse_sec(unit, filename, line, section, section_line, lvalue, ltype,
1678                              rvalue, data, userdata);
1679         if (r < 0)
1680                 return r;
1681
1682         if (streq(lvalue, "TimeoutSec")) {
1683                 s->start_timeout_defined = true;
1684                 s->timeout_stop_usec = s->timeout_start_usec;
1685         } else if (streq(lvalue, "TimeoutStartSec"))
1686                 s->start_timeout_defined = true;
1687
1688         return 0;
1689 }
1690
1691 int config_parse_busname_service(
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_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1704         BusName *n = data;
1705         int r;
1706         Unit *x;
1707         _cleanup_free_ char *p = NULL;
1708
1709         assert(filename);
1710         assert(lvalue);
1711         assert(rvalue);
1712         assert(data);
1713
1714         r = unit_name_printf(UNIT(n), rvalue, &p);
1715         if (r < 0) {
1716                 log_syntax(unit, LOG_ERR, filename, line, -r,
1717                            "Failed to resolve specifiers, ignoring: %s", rvalue);
1718                 return 0;
1719         }
1720
1721         if (!endswith(p, ".service")) {
1722                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1723                            "Unit must be of type service, ignoring: %s", rvalue);
1724                 return 0;
1725         }
1726
1727         r = manager_load_unit(UNIT(n)->manager, p, NULL, &error, &x);
1728         if (r < 0) {
1729                 log_syntax(unit, LOG_ERR, filename, line, -r,
1730                            "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1731                 return 0;
1732         }
1733
1734         unit_ref_set(&n->service, x);
1735
1736         return 0;
1737 }
1738
1739 DEFINE_CONFIG_PARSE_ENUM(config_parse_bus_policy_world, bus_policy_access, BusPolicyAccess, "Failed to parse bus name policy access");
1740
1741 int config_parse_bus_policy(
1742                 const char *unit,
1743                 const char *filename,
1744                 unsigned line,
1745                 const char *section,
1746                 unsigned section_line,
1747                 const char *lvalue,
1748                 int ltype,
1749                 const char *rvalue,
1750                 void *data,
1751                 void *userdata) {
1752
1753         _cleanup_free_ BusNamePolicy *p = NULL;
1754         _cleanup_free_ char *id_str = NULL;
1755         BusName *busname = data;
1756         char *access_str;
1757
1758         assert(filename);
1759         assert(lvalue);
1760         assert(rvalue);
1761         assert(data);
1762
1763         p = new0(BusNamePolicy, 1);
1764         if (!p)
1765                 return log_oom();
1766
1767         if (streq(lvalue, "AllowUser"))
1768                 p->type = BUSNAME_POLICY_TYPE_USER;
1769         else if (streq(lvalue, "AllowGroup"))
1770                 p->type = BUSNAME_POLICY_TYPE_GROUP;
1771         else
1772                 assert_not_reached("Unknown lvalue");
1773
1774         id_str = strdup(rvalue);
1775         if (!id_str)
1776                 return log_oom();
1777
1778         access_str = strpbrk(id_str, WHITESPACE);
1779         if (!access_str) {
1780                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1781                            "Invalid busname policy value '%s'", rvalue);
1782                 return 0;
1783         }
1784
1785         *access_str = '\0';
1786         access_str++;
1787         access_str += strspn(access_str, WHITESPACE);
1788
1789         p->access = bus_policy_access_from_string(access_str);
1790         if (p->access < 0) {
1791                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1792                            "Invalid busname policy access type '%s'", access_str);
1793                 return 0;
1794         }
1795
1796         p->name = id_str;
1797         id_str = NULL;
1798
1799         LIST_PREPEND(policy, busname->policy, p);
1800         p = NULL;
1801
1802         return 0;
1803 }
1804
1805 int config_parse_bus_endpoint_policy(
1806                 const char *unit,
1807                 const char *filename,
1808                 unsigned line,
1809                 const char *section,
1810                 unsigned section_line,
1811                 const char *lvalue,
1812                 int ltype,
1813                 const char *rvalue,
1814                 void *data,
1815                 void *userdata) {
1816
1817         _cleanup_free_ char *name = NULL;
1818         BusPolicyAccess access;
1819         ExecContext *c = data;
1820         char *access_str;
1821         int r;
1822
1823         assert(filename);
1824         assert(lvalue);
1825         assert(rvalue);
1826         assert(data);
1827
1828         name = strdup(rvalue);
1829         if (!name)
1830                 return log_oom();
1831
1832         access_str = strpbrk(name, WHITESPACE);
1833         if (!access_str) {
1834                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1835                            "Invalid endpoint policy value '%s'", rvalue);
1836                 return 0;
1837         }
1838
1839         *access_str = '\0';
1840         access_str++;
1841         access_str += strspn(access_str, WHITESPACE);
1842
1843         access = bus_policy_access_from_string(access_str);
1844         if (access <= _BUS_POLICY_ACCESS_INVALID ||
1845             access >= _BUS_POLICY_ACCESS_MAX) {
1846                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1847                            "Invalid endpoint policy access type '%s'", access_str);
1848                 return 0;
1849         }
1850
1851         if (!c->bus_endpoint) {
1852                 r = bus_endpoint_new(&c->bus_endpoint);
1853
1854                 if (r < 0)
1855                         return r;
1856         }
1857
1858         return bus_endpoint_add_policy(c->bus_endpoint, name, access);
1859 }
1860
1861 int config_parse_unit_env_file(const char *unit,
1862                                const char *filename,
1863                                unsigned line,
1864                                const char *section,
1865                                unsigned section_line,
1866                                const char *lvalue,
1867                                int ltype,
1868                                const char *rvalue,
1869                                void *data,
1870                                void *userdata) {
1871
1872         char ***env = data;
1873         Unit *u = userdata;
1874         _cleanup_free_ char *n = NULL;
1875         const char *s;
1876         int r;
1877
1878         assert(filename);
1879         assert(lvalue);
1880         assert(rvalue);
1881         assert(data);
1882
1883         if (isempty(rvalue)) {
1884                 /* Empty assignment frees the list */
1885                 strv_free(*env);
1886                 *env = NULL;
1887                 return 0;
1888         }
1889
1890         r = unit_full_printf(u, rvalue, &n);
1891         if (r < 0)
1892                 log_syntax(unit, LOG_ERR, filename, line, -r,
1893                            "Failed to resolve specifiers, ignoring: %s", rvalue);
1894
1895         s = n ?: rvalue;
1896         if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1897                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1898                            "Path '%s' is not absolute, ignoring.", s);
1899                 return 0;
1900         }
1901
1902         r = strv_extend(env, s);
1903         if (r < 0)
1904                 return log_oom();
1905
1906         return 0;
1907 }
1908
1909 int config_parse_environ(const char *unit,
1910                          const char *filename,
1911                          unsigned line,
1912                          const char *section,
1913                          unsigned section_line,
1914                          const char *lvalue,
1915                          int ltype,
1916                          const char *rvalue,
1917                          void *data,
1918                          void *userdata) {
1919
1920         Unit *u = userdata;
1921         char*** env = data;
1922         const char *word, *state;
1923         size_t l;
1924         _cleanup_free_ char *k = NULL;
1925         int r;
1926
1927         assert(filename);
1928         assert(lvalue);
1929         assert(rvalue);
1930         assert(data);
1931
1932         if (isempty(rvalue)) {
1933                 /* Empty assignment resets the list */
1934                 strv_free(*env);
1935                 *env = NULL;
1936                 return 0;
1937         }
1938
1939         if (u) {
1940                 r = unit_full_printf(u, rvalue, &k);
1941                 if (r < 0)
1942                         log_syntax(unit, LOG_ERR, filename, line, -r,
1943                                    "Failed to resolve specifiers, ignoring: %s", rvalue);
1944         }
1945
1946         if (!k)
1947                 k = strdup(rvalue);
1948         if (!k)
1949                 return log_oom();
1950
1951         FOREACH_WORD_QUOTED(word, l, k, state) {
1952                 _cleanup_free_ char *n;
1953                 char **x;
1954
1955                 n = cunescape_length(word, l);
1956                 if (!n)
1957                         return log_oom();
1958
1959                 if (!env_assignment_is_valid(n)) {
1960                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1961                                    "Invalid environment assignment, ignoring: %s", rvalue);
1962                         continue;
1963                 }
1964
1965                 x = strv_env_set(*env, n);
1966                 if (!x)
1967                         return log_oom();
1968
1969                 strv_free(*env);
1970                 *env = x;
1971         }
1972         if (!isempty(state))
1973                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1974                            "Trailing garbage, ignoring.");
1975
1976         return 0;
1977 }
1978
1979 int config_parse_ip_tos(const char *unit,
1980                         const char *filename,
1981                         unsigned line,
1982                         const char *section,
1983                         unsigned section_line,
1984                         const char *lvalue,
1985                         int ltype,
1986                         const char *rvalue,
1987                         void *data,
1988                         void *userdata) {
1989
1990         int *ip_tos = data, x;
1991
1992         assert(filename);
1993         assert(lvalue);
1994         assert(rvalue);
1995         assert(data);
1996
1997         x = ip_tos_from_string(rvalue);
1998         if (x < 0) {
1999                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2000                            "Failed to parse IP TOS value, ignoring: %s", rvalue);
2001                 return 0;
2002         }
2003
2004         *ip_tos = x;
2005         return 0;
2006 }
2007
2008 int config_parse_unit_condition_path(
2009                 const char *unit,
2010                 const char *filename,
2011                 unsigned line,
2012                 const char *section,
2013                 unsigned section_line,
2014                 const char *lvalue,
2015                 int ltype,
2016                 const char *rvalue,
2017                 void *data,
2018                 void *userdata) {
2019
2020         _cleanup_free_ char *p = NULL;
2021         Condition **list = data, *c;
2022         ConditionType t = ltype;
2023         bool trigger, negate;
2024         Unit *u = userdata;
2025         int r;
2026
2027         assert(filename);
2028         assert(lvalue);
2029         assert(rvalue);
2030         assert(data);
2031
2032         if (isempty(rvalue)) {
2033                 /* Empty assignment resets the list */
2034                 condition_free_list(*list);
2035                 *list = NULL;
2036                 return 0;
2037         }
2038
2039         trigger = rvalue[0] == '|';
2040         if (trigger)
2041                 rvalue++;
2042
2043         negate = rvalue[0] == '!';
2044         if (negate)
2045                 rvalue++;
2046
2047         r = unit_full_printf(u, rvalue, &p);
2048         if (r < 0) {
2049                 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
2050                 return 0;
2051         }
2052
2053         if (!path_is_absolute(p)) {
2054                 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Path in condition not absolute, ignoring: %s", p);
2055                 return 0;
2056         }
2057
2058         c = condition_new(t, p, trigger, negate);
2059         if (!c)
2060                 return log_oom();
2061
2062         LIST_PREPEND(conditions, *list, c);
2063         return 0;
2064 }
2065
2066 int config_parse_unit_condition_string(
2067                 const char *unit,
2068                 const char *filename,
2069                 unsigned line,
2070                 const char *section,
2071                 unsigned section_line,
2072                 const char *lvalue,
2073                 int ltype,
2074                 const char *rvalue,
2075                 void *data,
2076                 void *userdata) {
2077
2078         _cleanup_free_ char *s = NULL;
2079         Condition **list = data, *c;
2080         ConditionType t = ltype;
2081         bool trigger, negate;
2082         Unit *u = userdata;
2083         int r;
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         r = unit_full_printf(u, rvalue, &s);
2106         if (r < 0) {
2107                 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
2108                 return 0;
2109         }
2110
2111         c = condition_new(t, s, trigger, negate);
2112         if (!c)
2113                 return log_oom();
2114
2115         LIST_PREPEND(conditions, *list, c);
2116         return 0;
2117 }
2118
2119 int config_parse_unit_condition_null(
2120                 const char *unit,
2121                 const char *filename,
2122                 unsigned line,
2123                 const char *section,
2124                 unsigned section_line,
2125                 const char *lvalue,
2126                 int ltype,
2127                 const char *rvalue,
2128                 void *data,
2129                 void *userdata) {
2130
2131         Condition **list = data, *c;
2132         bool trigger, negate;
2133         int b;
2134
2135         assert(filename);
2136         assert(lvalue);
2137         assert(rvalue);
2138         assert(data);
2139
2140         if (isempty(rvalue)) {
2141                 /* Empty assignment resets the list */
2142                 condition_free_list(*list);
2143                 *list = NULL;
2144                 return 0;
2145         }
2146
2147         trigger = rvalue[0] == '|';
2148         if (trigger)
2149                 rvalue++;
2150
2151         negate = rvalue[0] == '!';
2152         if (negate)
2153                 rvalue++;
2154
2155         b = parse_boolean(rvalue);
2156         if (b < 0) {
2157                 log_syntax(unit, LOG_ERR, filename, line, -b, "Failed to parse boolean value in condition, ignoring: %s", rvalue);
2158                 return 0;
2159         }
2160
2161         if (!b)
2162                 negate = !negate;
2163
2164         c = condition_new(CONDITION_NULL, NULL, trigger, negate);
2165         if (!c)
2166                 return log_oom();
2167
2168         LIST_PREPEND(conditions, *list, c);
2169         return 0;
2170 }
2171
2172 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
2173 DEFINE_CONFIG_PARSE_ENUM(config_parse_failure_action, failure_action, FailureAction, "Failed to parse failure action specifier");
2174
2175 int config_parse_unit_requires_mounts_for(
2176                 const char *unit,
2177                 const char *filename,
2178                 unsigned line,
2179                 const char *section,
2180                 unsigned section_line,
2181                 const char *lvalue,
2182                 int ltype,
2183                 const char *rvalue,
2184                 void *data,
2185                 void *userdata) {
2186
2187         Unit *u = userdata;
2188         const char *word, *state;
2189         size_t l;
2190
2191         assert(filename);
2192         assert(lvalue);
2193         assert(rvalue);
2194         assert(data);
2195
2196         FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2197                 int r;
2198                 _cleanup_free_ char *n;
2199
2200                 n = strndup(word, l);
2201                 if (!n)
2202                         return log_oom();
2203
2204                 if (!utf8_is_valid(n)) {
2205                         log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
2206                         continue;
2207                 }
2208
2209                 r = unit_require_mounts_for(u, n);
2210                 if (r < 0) {
2211                         log_syntax(unit, LOG_ERR, filename, line, -r,
2212                                    "Failed to add required mount for, ignoring: %s", rvalue);
2213                         continue;
2214                 }
2215         }
2216         if (!isempty(state))
2217                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2218                            "Trailing garbage, ignoring.");
2219
2220         return 0;
2221 }
2222
2223 int config_parse_documentation(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         Unit *u = userdata;
2235         int r;
2236         char **a, **b;
2237
2238         assert(filename);
2239         assert(lvalue);
2240         assert(rvalue);
2241         assert(u);
2242
2243         if (isempty(rvalue)) {
2244                 /* Empty assignment resets the list */
2245                 strv_free(u->documentation);
2246                 u->documentation = NULL;
2247                 return 0;
2248         }
2249
2250         r = config_parse_unit_strv_printf(unit, filename, line, section, section_line, lvalue, ltype,
2251                                           rvalue, data, userdata);
2252         if (r < 0)
2253                 return r;
2254
2255         for (a = b = u->documentation; a && *a; a++) {
2256
2257                 if (is_valid_documentation_url(*a))
2258                         *(b++) = *a;
2259                 else {
2260                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2261                                    "Invalid URL, ignoring: %s", *a);
2262                         free(*a);
2263                 }
2264         }
2265         if (b)
2266                 *b = NULL;
2267
2268         return r;
2269 }
2270
2271 #ifdef HAVE_SECCOMP
2272 int config_parse_syscall_filter(
2273                 const char *unit,
2274                 const char *filename,
2275                 unsigned line,
2276                 const char *section,
2277                 unsigned section_line,
2278                 const char *lvalue,
2279                 int ltype,
2280                 const char *rvalue,
2281                 void *data,
2282                 void *userdata) {
2283
2284         static const char default_syscalls[] =
2285                 "execve\0"
2286                 "exit\0"
2287                 "exit_group\0"
2288                 "rt_sigreturn\0"
2289                 "sigreturn\0";
2290
2291         ExecContext *c = data;
2292         Unit *u = userdata;
2293         bool invert = false;
2294         const char *word, *state;
2295         size_t l;
2296         int r;
2297
2298         assert(filename);
2299         assert(lvalue);
2300         assert(rvalue);
2301         assert(u);
2302
2303         if (isempty(rvalue)) {
2304                 /* Empty assignment resets the list */
2305                 set_free(c->syscall_filter);
2306                 c->syscall_filter = NULL;
2307                 c->syscall_whitelist = false;
2308                 return 0;
2309         }
2310
2311         if (rvalue[0] == '~') {
2312                 invert = true;
2313                 rvalue++;
2314         }
2315
2316         if (!c->syscall_filter) {
2317                 c->syscall_filter = set_new(NULL);
2318                 if (!c->syscall_filter)
2319                         return log_oom();
2320
2321                 if (invert)
2322                         /* Allow everything but the ones listed */
2323                         c->syscall_whitelist = false;
2324                 else {
2325                         const char *i;
2326
2327                         /* Allow nothing but the ones listed */
2328                         c->syscall_whitelist = true;
2329
2330                         /* Accept default syscalls if we are on a whitelist */
2331                         NULSTR_FOREACH(i, default_syscalls)  {
2332                                 int id;
2333
2334                                 id = seccomp_syscall_resolve_name(i);
2335                                 if (id < 0)
2336                                         continue;
2337
2338                                 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2339                                 if (r == -EEXIST)
2340                                         continue;
2341                                 if (r < 0)
2342                                         return log_oom();
2343                         }
2344                 }
2345         }
2346
2347         FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2348                 _cleanup_free_ char *t = NULL;
2349                 int id;
2350
2351                 t = strndup(word, l);
2352                 if (!t)
2353                         return log_oom();
2354
2355                 id = seccomp_syscall_resolve_name(t);
2356                 if (id < 0)  {
2357                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2358                                    "Failed to parse system call, ignoring: %s", t);
2359                         continue;
2360                 }
2361
2362                 /* If we previously wanted to forbid a syscall and now
2363                  * we want to allow it, then remove it from the list
2364                  */
2365                 if (!invert == c->syscall_whitelist)  {
2366                         r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2367                         if (r == -EEXIST)
2368                                 continue;
2369                         if (r < 0)
2370                                 return log_oom();
2371                 } else
2372                         set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
2373         }
2374         if (!isempty(state))
2375                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2376                            "Trailing garbage, ignoring.");
2377
2378         /* Turn on NNP, but only if it wasn't configured explicitly
2379          * before, and only if we are in user mode. */
2380         if (!c->no_new_privileges_set && u->manager->running_as == SYSTEMD_USER)
2381                 c->no_new_privileges = true;
2382
2383         return 0;
2384 }
2385
2386 int config_parse_syscall_archs(
2387                 const char *unit,
2388                 const char *filename,
2389                 unsigned line,
2390                 const char *section,
2391                 unsigned section_line,
2392                 const char *lvalue,
2393                 int ltype,
2394                 const char *rvalue,
2395                 void *data,
2396                 void *userdata) {
2397
2398         Set **archs = data;
2399         const char *word, *state;
2400         size_t l;
2401         int r;
2402
2403         if (isempty(rvalue)) {
2404                 set_free(*archs);
2405                 *archs = NULL;
2406                 return 0;
2407         }
2408
2409         r = set_ensure_allocated(archs, NULL);
2410         if (r < 0)
2411                 return log_oom();
2412
2413         FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2414                 _cleanup_free_ char *t = NULL;
2415                 uint32_t a;
2416
2417                 t = strndup(word, l);
2418                 if (!t)
2419                         return log_oom();
2420
2421                 r = seccomp_arch_from_string(t, &a);
2422                 if (r < 0) {
2423                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2424                                    "Failed to parse system call architecture, ignoring: %s", t);
2425                         continue;
2426                 }
2427
2428                 r = set_put(*archs, UINT32_TO_PTR(a + 1));
2429                 if (r == -EEXIST)
2430                         continue;
2431                 if (r < 0)
2432                         return log_oom();
2433         }
2434         if (!isempty(state))
2435                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2436                            "Trailing garbage, ignoring.");
2437
2438         return 0;
2439 }
2440
2441 int config_parse_syscall_errno(
2442                 const char *unit,
2443                 const char *filename,
2444                 unsigned line,
2445                 const char *section,
2446                 unsigned section_line,
2447                 const char *lvalue,
2448                 int ltype,
2449                 const char *rvalue,
2450                 void *data,
2451                 void *userdata) {
2452
2453         ExecContext *c = data;
2454         int e;
2455
2456         assert(filename);
2457         assert(lvalue);
2458         assert(rvalue);
2459
2460         if (isempty(rvalue)) {
2461                 /* Empty assignment resets to KILL */
2462                 c->syscall_errno = 0;
2463                 return 0;
2464         }
2465
2466         e = errno_from_name(rvalue);
2467         if (e < 0) {
2468                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2469                            "Failed to parse error number, ignoring: %s", rvalue);
2470                 return 0;
2471         }
2472
2473         c->syscall_errno = e;
2474         return 0;
2475 }
2476
2477 int config_parse_address_families(
2478                 const char *unit,
2479                 const char *filename,
2480                 unsigned line,
2481                 const char *section,
2482                 unsigned section_line,
2483                 const char *lvalue,
2484                 int ltype,
2485                 const char *rvalue,
2486                 void *data,
2487                 void *userdata) {
2488
2489         ExecContext *c = data;
2490         Unit *u = userdata;
2491         bool invert = false;
2492         const char *word, *state;
2493         size_t l;
2494         int r;
2495
2496         assert(filename);
2497         assert(lvalue);
2498         assert(rvalue);
2499         assert(u);
2500
2501         if (isempty(rvalue)) {
2502                 /* Empty assignment resets the list */
2503                 set_free(c->address_families);
2504                 c->address_families = NULL;
2505                 c->address_families_whitelist = false;
2506                 return 0;
2507         }
2508
2509         if (rvalue[0] == '~') {
2510                 invert = true;
2511                 rvalue++;
2512         }
2513
2514         if (!c->address_families) {
2515                 c->address_families = set_new(NULL);
2516                 if (!c->address_families)
2517                         return log_oom();
2518
2519                 c->address_families_whitelist = !invert;
2520         }
2521
2522         FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2523                 _cleanup_free_ char *t = NULL;
2524                 int af;
2525
2526                 t = strndup(word, l);
2527                 if (!t)
2528                         return log_oom();
2529
2530                 af = af_from_name(t);
2531                 if (af <= 0)  {
2532                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2533                                    "Failed to parse address family, ignoring: %s", t);
2534                         continue;
2535                 }
2536
2537                 /* If we previously wanted to forbid an address family and now
2538                  * we want to allow it, then remove it from the list
2539                  */
2540                 if (!invert == c->address_families_whitelist)  {
2541                         r = set_put(c->address_families, INT_TO_PTR(af));
2542                         if (r == -EEXIST)
2543                                 continue;
2544                         if (r < 0)
2545                                 return log_oom();
2546                 } else
2547                         set_remove(c->address_families, INT_TO_PTR(af));
2548         }
2549         if (!isempty(state))
2550                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2551                            "Trailing garbage, ignoring.");
2552
2553         return 0;
2554 }
2555 #endif
2556
2557 int config_parse_unit_slice(
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         _cleanup_free_ char *k = NULL;
2570         Unit *u = userdata, *slice;
2571         int r;
2572
2573         assert(filename);
2574         assert(lvalue);
2575         assert(rvalue);
2576         assert(u);
2577
2578         r = unit_name_printf(u, rvalue, &k);
2579         if (r < 0)
2580                 log_syntax(unit, LOG_ERR, filename, line, -r,
2581                            "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
2582         if (!k) {
2583                 k = strdup(rvalue);
2584                 if (!k)
2585                         return log_oom();
2586         }
2587
2588         r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
2589         if (r < 0) {
2590                 log_syntax(unit, LOG_ERR, filename, line, -r,
2591                            "Failed to load slice unit %s. Ignoring.", k);
2592                 return 0;
2593         }
2594
2595         if (slice->type != UNIT_SLICE) {
2596                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2597                            "Slice unit %s is not a slice. Ignoring.", k);
2598                 return 0;
2599         }
2600
2601         unit_ref_set(&u->slice, slice);
2602         return 0;
2603 }
2604
2605 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
2606
2607 int config_parse_cpu_shares(
2608                 const char *unit,
2609                 const char *filename,
2610                 unsigned line,
2611                 const char *section,
2612                 unsigned section_line,
2613                 const char *lvalue,
2614                 int ltype,
2615                 const char *rvalue,
2616                 void *data,
2617                 void *userdata) {
2618
2619         unsigned long *shares = data, lu;
2620         int r;
2621
2622         assert(filename);
2623         assert(lvalue);
2624         assert(rvalue);
2625
2626         if (isempty(rvalue)) {
2627                 *shares = (unsigned long) -1;
2628                 return 0;
2629         }
2630
2631         r = safe_atolu(rvalue, &lu);
2632         if (r < 0 || lu <= 0) {
2633                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2634                            "CPU shares '%s' invalid. Ignoring.", rvalue);
2635                 return 0;
2636         }
2637
2638         *shares = lu;
2639         return 0;
2640 }
2641
2642 int config_parse_cpu_quota(
2643                 const char *unit,
2644                 const char *filename,
2645                 unsigned line,
2646                 const char *section,
2647                 unsigned section_line,
2648                 const char *lvalue,
2649                 int ltype,
2650                 const char *rvalue,
2651                 void *data,
2652                 void *userdata) {
2653
2654         CGroupContext *c = data;
2655         double percent;
2656
2657         assert(filename);
2658         assert(lvalue);
2659         assert(rvalue);
2660
2661         if (isempty(rvalue)) {
2662                 c->cpu_quota_per_sec_usec = USEC_INFINITY;
2663                 return 0;
2664         }
2665
2666         if (!endswith(rvalue, "%")) {
2667
2668                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2669                            "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue);
2670                 return 0;
2671         }
2672
2673         if (sscanf(rvalue, "%lf%%", &percent) != 1 || percent <= 0) {
2674                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2675                            "CPU quota '%s' invalid. Ignoring.", rvalue);
2676                 return 0;
2677         }
2678
2679         c->cpu_quota_per_sec_usec = (usec_t) (percent * USEC_PER_SEC / 100);
2680
2681         return 0;
2682 }
2683
2684 int config_parse_memory_limit(
2685                 const char *unit,
2686                 const char *filename,
2687                 unsigned line,
2688                 const char *section,
2689                 unsigned section_line,
2690                 const char *lvalue,
2691                 int ltype,
2692                 const char *rvalue,
2693                 void *data,
2694                 void *userdata) {
2695
2696         CGroupContext *c = data;
2697         off_t bytes;
2698         int r;
2699
2700         if (isempty(rvalue)) {
2701                 c->memory_limit = (uint64_t) -1;
2702                 return 0;
2703         }
2704
2705         assert_cc(sizeof(uint64_t) == sizeof(off_t));
2706
2707         r = parse_size(rvalue, 1024, &bytes);
2708         if (r < 0) {
2709                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2710                            "Memory limit '%s' invalid. Ignoring.", rvalue);
2711                 return 0;
2712         }
2713
2714         c->memory_limit = (uint64_t) bytes;
2715         return 0;
2716 }
2717
2718 int config_parse_device_allow(
2719                 const char *unit,
2720                 const char *filename,
2721                 unsigned line,
2722                 const char *section,
2723                 unsigned section_line,
2724                 const char *lvalue,
2725                 int ltype,
2726                 const char *rvalue,
2727                 void *data,
2728                 void *userdata) {
2729
2730         _cleanup_free_ char *path = NULL;
2731         CGroupContext *c = data;
2732         CGroupDeviceAllow *a;
2733         const char *m;
2734         size_t n;
2735
2736         if (isempty(rvalue)) {
2737                 while (c->device_allow)
2738                         cgroup_context_free_device_allow(c, c->device_allow);
2739
2740                 return 0;
2741         }
2742
2743         n = strcspn(rvalue, WHITESPACE);
2744         path = strndup(rvalue, n);
2745         if (!path)
2746                 return log_oom();
2747
2748         if (!startswith(path, "/dev/") &&
2749             !startswith(path, "block-") &&
2750             !startswith(path, "char-")) {
2751                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2752                            "Invalid device node path '%s'. Ignoring.", path);
2753                 return 0;
2754         }
2755
2756         m = rvalue + n + strspn(rvalue + n, WHITESPACE);
2757         if (isempty(m))
2758                 m = "rwm";
2759
2760         if (!in_charset(m, "rwm")) {
2761                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2762                            "Invalid device rights '%s'. Ignoring.", m);
2763                 return 0;
2764         }
2765
2766         a = new0(CGroupDeviceAllow, 1);
2767         if (!a)
2768                 return log_oom();
2769
2770         a->path = path;
2771         path = NULL;
2772         a->r = !!strchr(m, 'r');
2773         a->w = !!strchr(m, 'w');
2774         a->m = !!strchr(m, 'm');
2775
2776         LIST_PREPEND(device_allow, c->device_allow, a);
2777         return 0;
2778 }
2779
2780 int config_parse_blockio_weight(
2781                 const char *unit,
2782                 const char *filename,
2783                 unsigned line,
2784                 const char *section,
2785                 unsigned section_line,
2786                 const char *lvalue,
2787                 int ltype,
2788                 const char *rvalue,
2789                 void *data,
2790                 void *userdata) {
2791
2792         unsigned long *weight = data, lu;
2793         int r;
2794
2795         assert(filename);
2796         assert(lvalue);
2797         assert(rvalue);
2798
2799         if (isempty(rvalue)) {
2800                 *weight = (unsigned long) -1;
2801                 return 0;
2802         }
2803
2804         r = safe_atolu(rvalue, &lu);
2805         if (r < 0 || lu < 10 || lu > 1000) {
2806                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2807                            "Block IO weight '%s' invalid. Ignoring.", rvalue);
2808                 return 0;
2809         }
2810
2811         *weight = lu;
2812         return 0;
2813 }
2814
2815 int config_parse_blockio_device_weight(
2816                 const char *unit,
2817                 const char *filename,
2818                 unsigned line,
2819                 const char *section,
2820                 unsigned section_line,
2821                 const char *lvalue,
2822                 int ltype,
2823                 const char *rvalue,
2824                 void *data,
2825                 void *userdata) {
2826
2827         _cleanup_free_ char *path = NULL;
2828         CGroupBlockIODeviceWeight *w;
2829         CGroupContext *c = data;
2830         unsigned long lu;
2831         const char *weight;
2832         size_t n;
2833         int r;
2834
2835         assert(filename);
2836         assert(lvalue);
2837         assert(rvalue);
2838
2839         if (isempty(rvalue)) {
2840                 while (c->blockio_device_weights)
2841                         cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
2842
2843                 return 0;
2844         }
2845
2846         n = strcspn(rvalue, WHITESPACE);
2847         weight = rvalue + n;
2848         if (!*weight) {
2849                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2850                            "Expected block device and device weight. Ignoring.");
2851                 return 0;
2852         }
2853
2854         path = strndup(rvalue, n);
2855         if (!path)
2856                 return log_oom();
2857
2858         if (!path_startswith(path, "/dev")) {
2859                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2860                            "Invalid device node path '%s'. Ignoring.", path);
2861                 return 0;
2862         }
2863
2864         weight += strspn(weight, WHITESPACE);
2865         r = safe_atolu(weight, &lu);
2866         if (r < 0 || lu < 10 || lu > 1000) {
2867                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2868                            "Block IO weight '%s' invalid. Ignoring.", rvalue);
2869                 return 0;
2870         }
2871
2872         w = new0(CGroupBlockIODeviceWeight, 1);
2873         if (!w)
2874                 return log_oom();
2875
2876         w->path = path;
2877         path = NULL;
2878
2879         w->weight = lu;
2880
2881         LIST_PREPEND(device_weights, c->blockio_device_weights, w);
2882         return 0;
2883 }
2884
2885 int config_parse_blockio_bandwidth(
2886                 const char *unit,
2887                 const char *filename,
2888                 unsigned line,
2889                 const char *section,
2890                 unsigned section_line,
2891                 const char *lvalue,
2892                 int ltype,
2893                 const char *rvalue,
2894                 void *data,
2895                 void *userdata) {
2896
2897         _cleanup_free_ char *path = NULL;
2898         CGroupBlockIODeviceBandwidth *b;
2899         CGroupContext *c = data;
2900         const char *bandwidth;
2901         off_t bytes;
2902         bool read;
2903         size_t n;
2904         int r;
2905
2906         assert(filename);
2907         assert(lvalue);
2908         assert(rvalue);
2909
2910         read = streq("BlockIOReadBandwidth", lvalue);
2911
2912         if (isempty(rvalue)) {
2913                 CGroupBlockIODeviceBandwidth *next;
2914
2915                 LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
2916                         if (b->read == read)
2917                                 cgroup_context_free_blockio_device_bandwidth(c, b);
2918
2919                 return 0;
2920         }
2921
2922         n = strcspn(rvalue, WHITESPACE);
2923         bandwidth = rvalue + n;
2924         bandwidth += strspn(bandwidth, WHITESPACE);
2925
2926         if (!*bandwidth) {
2927                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2928                            "Expected space separated pair of device node and bandwidth. Ignoring.");
2929                 return 0;
2930         }
2931
2932         path = strndup(rvalue, n);
2933         if (!path)
2934                 return log_oom();
2935
2936         if (!path_startswith(path, "/dev")) {
2937                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2938                            "Invalid device node path '%s'. Ignoring.", path);
2939                 return 0;
2940         }
2941
2942         r = parse_size(bandwidth, 1000, &bytes);
2943         if (r < 0 || bytes <= 0) {
2944                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2945                            "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
2946                 return 0;
2947         }
2948
2949         b = new0(CGroupBlockIODeviceBandwidth, 1);
2950         if (!b)
2951                 return log_oom();
2952
2953         b->path = path;
2954         path = NULL;
2955         b->bandwidth = (uint64_t) bytes;
2956         b->read = read;
2957
2958         LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
2959
2960         return 0;
2961 }
2962
2963 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
2964
2965 int config_parse_job_mode_isolate(
2966                 const char *unit,
2967                 const char *filename,
2968                 unsigned line,
2969                 const char *section,
2970                 unsigned section_line,
2971                 const char *lvalue,
2972                 int ltype,
2973                 const char *rvalue,
2974                 void *data,
2975                 void *userdata) {
2976
2977         JobMode *m = data;
2978         int r;
2979
2980         assert(filename);
2981         assert(lvalue);
2982         assert(rvalue);
2983
2984         r = parse_boolean(rvalue);
2985         if (r < 0) {
2986                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2987                            "Failed to parse boolean, ignoring: %s", rvalue);
2988                 return 0;
2989         }
2990
2991         *m = r ? JOB_ISOLATE : JOB_REPLACE;
2992         return 0;
2993 }
2994
2995 int config_parse_personality(
2996                 const char *unit,
2997                 const char *filename,
2998                 unsigned line,
2999                 const char *section,
3000                 unsigned section_line,
3001                 const char *lvalue,
3002                 int ltype,
3003                 const char *rvalue,
3004                 void *data,
3005                 void *userdata) {
3006
3007         unsigned long *personality = data, p;
3008
3009         assert(filename);
3010         assert(lvalue);
3011         assert(rvalue);
3012         assert(personality);
3013
3014         p = personality_from_string(rvalue);
3015         if (p == 0xffffffffUL) {
3016                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3017                            "Failed to parse personality, ignoring: %s", rvalue);
3018                 return 0;
3019         }
3020
3021         *personality = p;
3022         return 0;
3023 }
3024
3025 int config_parse_runtime_directory(
3026                 const char *unit,
3027                 const char *filename,
3028                 unsigned line,
3029                 const char *section,
3030                 unsigned section_line,
3031                 const char *lvalue,
3032                 int ltype,
3033                 const char *rvalue,
3034                 void *data,
3035                 void *userdata) {
3036
3037         char***rt = data;
3038         const char *word, *state;
3039         size_t l;
3040         int r;
3041
3042         assert(filename);
3043         assert(lvalue);
3044         assert(rvalue);
3045         assert(data);
3046
3047         if (isempty(rvalue)) {
3048                 /* Empty assignment resets the list */
3049                 strv_free(*rt);
3050                 *rt = NULL;
3051                 return 0;
3052         }
3053
3054         FOREACH_WORD_QUOTED(word, l, rvalue, state) {
3055                 _cleanup_free_ char *n;
3056
3057                 n = strndup(word, l);
3058                 if (!n)
3059                         return log_oom();
3060
3061                 if (!filename_is_safe(n)) {
3062                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3063                                    "Runtime directory is not valid, ignoring assignment: %s", rvalue);
3064                         continue;
3065                 }
3066
3067                 r = strv_push(rt, n);
3068                 if (r < 0)
3069                         return log_oom();
3070
3071                 n = NULL;
3072         }
3073         if (!isempty(state))
3074                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3075                            "Trailing garbage, ignoring.");
3076
3077         return 0;
3078 }
3079
3080 int config_parse_set_status(
3081                 const char *unit,
3082                 const char *filename,
3083                 unsigned line,
3084                 const char *section,
3085                 unsigned section_line,
3086                 const char *lvalue,
3087                 int ltype,
3088                 const char *rvalue,
3089                 void *data,
3090                 void *userdata) {
3091
3092         size_t l;
3093         const char *word, *state;
3094         int r;
3095         ExitStatusSet *status_set = data;
3096
3097         assert(filename);
3098         assert(lvalue);
3099         assert(rvalue);
3100         assert(data);
3101
3102         /* Empty assignment resets the list */
3103         if (isempty(rvalue)) {
3104                 exit_status_set_free(status_set);
3105                 return 0;
3106         }
3107
3108         FOREACH_WORD(word, l, rvalue, state) {
3109                 _cleanup_free_ char *temp;
3110                 int val;
3111
3112                 temp = strndup(word, l);
3113                 if (!temp)
3114                         return log_oom();
3115
3116                 r = safe_atoi(temp, &val);
3117                 if (r < 0) {
3118                         val = signal_from_string_try_harder(temp);
3119
3120                         if (val <= 0) {
3121                                 log_syntax(unit, LOG_ERR, filename, line, -val,
3122                                            "Failed to parse value, ignoring: %s", word);
3123                                 return 0;
3124                         }
3125                 } else {
3126                         if (val < 0 || val > 255) {
3127                                 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
3128                                            "Value %d is outside range 0-255, ignoring", val);
3129                                 continue;
3130                         }
3131                 }
3132
3133                 r = set_ensure_allocated(&status_set->status, NULL);
3134                 if (r < 0)
3135                         return log_oom();
3136
3137                 r = set_put(status_set->status, INT_TO_PTR(val));
3138                 if (r < 0) {
3139                         log_syntax(unit, LOG_ERR, filename, line, -r,
3140                                    "Unable to store: %s", word);
3141                         return r;
3142                 }
3143         }
3144         if (!isempty(state))
3145                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3146                            "Trailing garbage, ignoring.");
3147
3148         return 0;
3149 }
3150
3151 int config_parse_namespace_path_strv(
3152                 const char *unit,
3153                 const char *filename,
3154                 unsigned line,
3155                 const char *section,
3156                 unsigned section_line,
3157                 const char *lvalue,
3158                 int ltype,
3159                 const char *rvalue,
3160                 void *data,
3161                 void *userdata) {
3162
3163         char*** sv = data;
3164         const char *word, *state;
3165         size_t l;
3166         int r;
3167
3168         assert(filename);
3169         assert(lvalue);
3170         assert(rvalue);
3171         assert(data);
3172
3173         if (isempty(rvalue)) {
3174                 /* Empty assignment resets the list */
3175                 strv_free(*sv);
3176                 *sv = NULL;
3177                 return 0;
3178         }
3179
3180         FOREACH_WORD_QUOTED(word, l, rvalue, state) {
3181                 _cleanup_free_ char *n;
3182                 int offset;
3183
3184                 n = strndup(word, l);
3185                 if (!n)
3186                         return log_oom();
3187
3188                 if (!utf8_is_valid(n)) {
3189                         log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
3190                         continue;
3191                 }
3192
3193                 offset = n[0] == '-';
3194                 if (!path_is_absolute(n + offset)) {
3195                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3196                                    "Not an absolute path, ignoring: %s", rvalue);
3197                         continue;
3198                 }
3199
3200                 path_kill_slashes(n);
3201
3202                 r = strv_push(sv, n);
3203                 if (r < 0)
3204                         return log_oom();
3205
3206                 n = NULL;
3207         }
3208         if (!isempty(state))
3209                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3210                            "Trailing garbage, ignoring.");
3211
3212         return 0;
3213 }
3214
3215 int config_parse_no_new_privileges(
3216                 const char* unit,
3217                 const char *filename,
3218                 unsigned line,
3219                 const char *section,
3220                 unsigned section_line,
3221                 const char *lvalue,
3222                 int ltype,
3223                 const char *rvalue,
3224                 void *data,
3225                 void *userdata) {
3226
3227         ExecContext *c = data;
3228         int k;
3229
3230         assert(filename);
3231         assert(lvalue);
3232         assert(rvalue);
3233         assert(data);
3234
3235         k = parse_boolean(rvalue);
3236         if (k < 0) {
3237                 log_syntax(unit, LOG_ERR, filename, line, -k,
3238                            "Failed to parse boolean value, ignoring: %s", rvalue);
3239                 return 0;
3240         }
3241
3242         c->no_new_privileges = !!k;
3243         c->no_new_privileges_set = true;
3244
3245         return 0;
3246 }
3247
3248 int config_parse_protect_home(
3249                 const char* unit,
3250                 const char *filename,
3251                 unsigned line,
3252                 const char *section,
3253                 unsigned section_line,
3254                 const char *lvalue,
3255                 int ltype,
3256                 const char *rvalue,
3257                 void *data,
3258                 void *userdata) {
3259
3260         ExecContext *c = data;
3261         int k;
3262
3263         assert(filename);
3264         assert(lvalue);
3265         assert(rvalue);
3266         assert(data);
3267
3268         /* Our enum shall be a superset of booleans, hence first try
3269          * to parse as as boolean, and then as enum */
3270
3271         k = parse_boolean(rvalue);
3272         if (k > 0)
3273                 c->protect_home = PROTECT_HOME_YES;
3274         else if (k == 0)
3275                 c->protect_home = PROTECT_HOME_NO;
3276         else {
3277                 ProtectHome h;
3278
3279                 h = protect_home_from_string(rvalue);
3280                 if (h < 0){
3281                         log_syntax(unit, LOG_ERR, filename, line, -h,
3282                                    "Failed to parse protect home value, ignoring: %s", rvalue);
3283                         return 0;
3284                 }
3285
3286                 c->protect_home = h;
3287         }
3288
3289         return 0;
3290 }
3291
3292 int config_parse_protect_system(
3293                 const char* unit,
3294                 const char *filename,
3295                 unsigned line,
3296                 const char *section,
3297                 unsigned section_line,
3298                 const char *lvalue,
3299                 int ltype,
3300                 const char *rvalue,
3301                 void *data,
3302                 void *userdata) {
3303
3304         ExecContext *c = data;
3305         int k;
3306
3307         assert(filename);
3308         assert(lvalue);
3309         assert(rvalue);
3310         assert(data);
3311
3312         /* Our enum shall be a superset of booleans, hence first try
3313          * to parse as as boolean, and then as enum */
3314
3315         k = parse_boolean(rvalue);
3316         if (k > 0)
3317                 c->protect_system = PROTECT_SYSTEM_YES;
3318         else if (k == 0)
3319                 c->protect_system = PROTECT_SYSTEM_NO;
3320         else {
3321                 ProtectSystem s;
3322
3323                 s = protect_system_from_string(rvalue);
3324                 if (s < 0){
3325                         log_syntax(unit, LOG_ERR, filename, line, -s,
3326                                    "Failed to parse protect system value, ignoring: %s", rvalue);
3327                         return 0;
3328                 }
3329
3330                 c->protect_system = s;
3331         }
3332
3333         return 0;
3334 }
3335
3336 #define FOLLOW_MAX 8
3337
3338 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
3339         unsigned c = 0;
3340         int fd, r;
3341         FILE *f;
3342         char *id = NULL;
3343
3344         assert(filename);
3345         assert(*filename);
3346         assert(_f);
3347         assert(names);
3348
3349         /* This will update the filename pointer if the loaded file is
3350          * reached by a symlink. The old string will be freed. */
3351
3352         for (;;) {
3353                 char *target, *name;
3354
3355                 if (c++ >= FOLLOW_MAX)
3356                         return -ELOOP;
3357
3358                 path_kill_slashes(*filename);
3359
3360                 /* Add the file name we are currently looking at to
3361                  * the names of this unit, but only if it is a valid
3362                  * unit name. */
3363                 name = basename(*filename);
3364
3365                 if (unit_name_is_valid(name, TEMPLATE_VALID)) {
3366
3367                         id = set_get(names, name);
3368                         if (!id) {
3369                                 id = strdup(name);
3370                                 if (!id)
3371                                         return -ENOMEM;
3372
3373                                 r = set_consume(names, id);
3374                                 if (r < 0)
3375                                         return r;
3376                         }
3377                 }
3378
3379                 /* Try to open the file name, but don't if its a symlink */
3380                 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
3381                 if (fd >= 0)
3382                         break;
3383
3384                 if (errno != ELOOP)
3385                         return -errno;
3386
3387                 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
3388                 r = readlink_and_make_absolute(*filename, &target);
3389                 if (r < 0)
3390                         return r;
3391
3392                 free(*filename);
3393                 *filename = target;
3394         }
3395
3396         f = fdopen(fd, "re");
3397         if (!f) {
3398                 r = -errno;
3399                 safe_close(fd);
3400                 return r;
3401         }
3402
3403         *_f = f;
3404         *_final = id;
3405         return 0;
3406 }
3407
3408 static int merge_by_names(Unit **u, Set *names, const char *id) {
3409         char *k;
3410         int r;
3411
3412         assert(u);
3413         assert(*u);
3414         assert(names);
3415
3416         /* Let's try to add in all symlink names we found */
3417         while ((k = set_steal_first(names))) {
3418
3419                 /* First try to merge in the other name into our
3420                  * unit */
3421                 r = unit_merge_by_name(*u, k);
3422                 if (r < 0) {
3423                         Unit *other;
3424
3425                         /* Hmm, we couldn't merge the other unit into
3426                          * ours? Then let's try it the other way
3427                          * round */
3428
3429                         other = manager_get_unit((*u)->manager, k);
3430                         free(k);
3431
3432                         if (other) {
3433                                 r = unit_merge(other, *u);
3434                                 if (r >= 0) {
3435                                         *u = other;
3436                                         return merge_by_names(u, names, NULL);
3437                                 }
3438                         }
3439
3440                         return r;
3441                 }
3442
3443                 if (id == k)
3444                         unit_choose_id(*u, id);
3445
3446                 free(k);
3447         }
3448
3449         return 0;
3450 }
3451
3452 static int load_from_path(Unit *u, const char *path) {
3453         int r;
3454         _cleanup_set_free_free_ Set *symlink_names = NULL;
3455         _cleanup_fclose_ FILE *f = NULL;
3456         _cleanup_free_ char *filename = NULL;
3457         char *id = NULL;
3458         Unit *merged;
3459         struct stat st;
3460
3461         assert(u);
3462         assert(path);
3463
3464         symlink_names = set_new(&string_hash_ops);
3465         if (!symlink_names)
3466                 return -ENOMEM;
3467
3468         if (path_is_absolute(path)) {
3469
3470                 filename = strdup(path);
3471                 if (!filename)
3472                         return -ENOMEM;
3473
3474                 r = open_follow(&filename, &f, symlink_names, &id);
3475                 if (r < 0) {
3476                         free(filename);
3477                         filename = NULL;
3478
3479                         if (r != -ENOENT)
3480                                 return r;
3481                 }
3482
3483         } else  {
3484                 char **p;
3485
3486                 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
3487
3488                         /* Instead of opening the path right away, we manually
3489                          * follow all symlinks and add their name to our unit
3490                          * name set while doing so */
3491                         filename = path_make_absolute(path, *p);
3492                         if (!filename)
3493                                 return -ENOMEM;
3494
3495                         if (u->manager->unit_path_cache &&
3496                             !set_get(u->manager->unit_path_cache, filename))
3497                                 r = -ENOENT;
3498                         else
3499                                 r = open_follow(&filename, &f, symlink_names, &id);
3500
3501                         if (r < 0) {
3502                                 free(filename);
3503                                 filename = NULL;
3504
3505                                 if (r != -ENOENT)
3506                                         return r;
3507
3508                                 /* Empty the symlink names for the next run */
3509                                 set_clear_free(symlink_names);
3510                                 continue;
3511                         }
3512
3513                         break;
3514                 }
3515         }
3516
3517         if (!filename)
3518                 /* Hmm, no suitable file found? */
3519                 return 0;
3520
3521         merged = u;
3522         r = merge_by_names(&merged, symlink_names, id);
3523         if (r < 0)
3524                 return r;
3525
3526         if (merged != u) {
3527                 u->load_state = UNIT_MERGED;
3528                 return 0;
3529         }
3530
3531         if (fstat(fileno(f), &st) < 0)
3532                 return -errno;
3533
3534         if (null_or_empty(&st))
3535                 u->load_state = UNIT_MASKED;
3536         else {
3537                 u->load_state = UNIT_LOADED;
3538
3539                 /* Now, parse the file contents */
3540                 r = config_parse(u->id, filename, f,
3541                                  UNIT_VTABLE(u)->sections,
3542                                  config_item_perf_lookup, load_fragment_gperf_lookup,
3543                                  false, true, false, u);
3544                 if (r < 0)
3545                         return r;
3546         }
3547
3548         free(u->fragment_path);
3549         u->fragment_path = filename;
3550         filename = NULL;
3551
3552         u->fragment_mtime = timespec_load(&st.st_mtim);
3553
3554         if (u->source_path) {
3555                 if (stat(u->source_path, &st) >= 0)
3556                         u->source_mtime = timespec_load(&st.st_mtim);
3557                 else
3558                         u->source_mtime = 0;
3559         }
3560
3561         return 0;
3562 }
3563
3564 int unit_load_fragment(Unit *u) {
3565         int r;
3566         Iterator i;
3567         const char *t;
3568
3569         assert(u);
3570         assert(u->load_state == UNIT_STUB);
3571         assert(u->id);
3572
3573         /* First, try to find the unit under its id. We always look
3574          * for unit files in the default directories, to make it easy
3575          * to override things by placing things in /etc/systemd/system */
3576         r = load_from_path(u, u->id);
3577         if (r < 0)
3578                 return r;
3579
3580         /* Try to find an alias we can load this with */
3581         if (u->load_state == UNIT_STUB)
3582                 SET_FOREACH(t, u->names, i) {
3583
3584                         if (t == u->id)
3585                                 continue;
3586
3587                         r = load_from_path(u, t);
3588                         if (r < 0)
3589                                 return r;
3590
3591                         if (u->load_state != UNIT_STUB)
3592                                 break;
3593                 }
3594
3595         /* And now, try looking for it under the suggested (originally linked) path */
3596         if (u->load_state == UNIT_STUB && u->fragment_path) {
3597
3598                 r = load_from_path(u, u->fragment_path);
3599                 if (r < 0)
3600                         return r;
3601
3602                 if (u->load_state == UNIT_STUB) {
3603                         /* Hmm, this didn't work? Then let's get rid
3604                          * of the fragment path stored for us, so that
3605                          * we don't point to an invalid location. */
3606                         free(u->fragment_path);
3607                         u->fragment_path = NULL;
3608                 }
3609         }
3610
3611         /* Look for a template */
3612         if (u->load_state == UNIT_STUB && u->instance) {
3613                 _cleanup_free_ char *k;
3614
3615                 k = unit_name_template(u->id);
3616                 if (!k)
3617                         return -ENOMEM;
3618
3619                 r = load_from_path(u, k);
3620                 if (r < 0)
3621                         return r;
3622
3623                 if (u->load_state == UNIT_STUB)
3624                         SET_FOREACH(t, u->names, i) {
3625                                 _cleanup_free_ char *z = NULL;
3626
3627                                 if (t == u->id)
3628                                         continue;
3629
3630                                 z = unit_name_template(t);
3631                                 if (!z)
3632                                         return -ENOMEM;
3633
3634                                 r = load_from_path(u, z);
3635                                 if (r < 0)
3636                                         return r;
3637
3638                                 if (u->load_state != UNIT_STUB)
3639                                         break;
3640                         }
3641         }
3642
3643         return 0;
3644 }
3645
3646 void unit_dump_config_items(FILE *f) {
3647         static const struct {
3648                 const ConfigParserCallback callback;
3649                 const char *rvalue;
3650         } table[] = {
3651 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
3652                 { config_parse_warn_compat,           "NOTSUPPORTED" },
3653 #endif
3654                 { config_parse_int,                   "INTEGER" },
3655                 { config_parse_unsigned,              "UNSIGNED" },
3656                 { config_parse_iec_size,              "SIZE" },
3657                 { config_parse_iec_off,               "SIZE" },
3658                 { config_parse_si_size,               "SIZE" },
3659                 { config_parse_bool,                  "BOOLEAN" },
3660                 { config_parse_string,                "STRING" },
3661                 { config_parse_path,                  "PATH" },
3662                 { config_parse_unit_path_printf,      "PATH" },
3663                 { config_parse_strv,                  "STRING [...]" },
3664                 { config_parse_exec_nice,             "NICE" },
3665                 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
3666                 { config_parse_exec_io_class,         "IOCLASS" },
3667                 { config_parse_exec_io_priority,      "IOPRIORITY" },
3668                 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
3669                 { config_parse_exec_cpu_sched_prio,   "CPUSCHEDPRIO" },
3670                 { config_parse_exec_cpu_affinity,     "CPUAFFINITY" },
3671                 { config_parse_mode,                  "MODE" },
3672                 { config_parse_unit_env_file,         "FILE" },
3673                 { config_parse_output,                "OUTPUT" },
3674                 { config_parse_input,                 "INPUT" },
3675                 { config_parse_log_facility,          "FACILITY" },
3676                 { config_parse_log_level,             "LEVEL" },
3677                 { config_parse_exec_capabilities,     "CAPABILITIES" },
3678                 { config_parse_exec_secure_bits,      "SECUREBITS" },
3679                 { config_parse_bounding_set,          "BOUNDINGSET" },
3680                 { config_parse_limit,                 "LIMIT" },
3681                 { config_parse_unit_deps,             "UNIT [...]" },
3682                 { config_parse_exec,                  "PATH [ARGUMENT [...]]" },
3683                 { config_parse_service_type,          "SERVICETYPE" },
3684                 { config_parse_service_restart,       "SERVICERESTART" },
3685 #ifdef HAVE_SYSV_COMPAT
3686                 { config_parse_sysv_priority,         "SYSVPRIORITY" },
3687 #endif
3688                 { config_parse_kill_mode,             "KILLMODE" },
3689                 { config_parse_kill_signal,           "SIGNAL" },
3690                 { config_parse_socket_listen,         "SOCKET [...]" },
3691                 { config_parse_socket_bind,           "SOCKETBIND" },
3692                 { config_parse_socket_bindtodevice,   "NETWORKINTERFACE" },
3693                 { config_parse_sec,                   "SECONDS" },
3694                 { config_parse_nsec,                  "NANOSECONDS" },
3695                 { config_parse_namespace_path_strv,   "PATH [...]" },
3696                 { config_parse_unit_requires_mounts_for, "PATH [...]" },
3697                 { config_parse_exec_mount_flags,      "MOUNTFLAG [...]" },
3698                 { config_parse_unit_string_printf,    "STRING" },
3699                 { config_parse_trigger_unit,          "UNIT" },
3700                 { config_parse_timer,                 "TIMER" },
3701                 { config_parse_path_spec,             "PATH" },
3702                 { config_parse_notify_access,         "ACCESS" },
3703                 { config_parse_ip_tos,                "TOS" },
3704                 { config_parse_unit_condition_path,   "CONDITION" },
3705                 { config_parse_unit_condition_string, "CONDITION" },
3706                 { config_parse_unit_condition_null,   "CONDITION" },
3707                 { config_parse_unit_slice,            "SLICE" },
3708                 { config_parse_documentation,         "URL" },
3709                 { config_parse_service_timeout,       "SECONDS" },
3710                 { config_parse_failure_action,        "ACTION" },
3711                 { config_parse_set_status,            "STATUS" },
3712                 { config_parse_service_sockets,       "SOCKETS" },
3713                 { config_parse_environ,               "ENVIRON" },
3714 #ifdef HAVE_SECCOMP
3715                 { config_parse_syscall_filter,        "SYSCALLS" },
3716                 { config_parse_syscall_archs,         "ARCHS" },
3717                 { config_parse_syscall_errno,         "ERRNO" },
3718                 { config_parse_address_families,      "FAMILIES" },
3719 #endif
3720                 { config_parse_cpu_shares,            "SHARES" },
3721                 { config_parse_memory_limit,          "LIMIT" },
3722                 { config_parse_device_allow,          "DEVICE" },
3723                 { config_parse_device_policy,         "POLICY" },
3724                 { config_parse_blockio_bandwidth,     "BANDWIDTH" },
3725                 { config_parse_blockio_weight,        "WEIGHT" },
3726                 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
3727                 { config_parse_long,                  "LONG" },
3728                 { config_parse_socket_service,        "SERVICE" },
3729 #ifdef HAVE_SELINUX
3730                 { config_parse_exec_selinux_context,  "LABEL" },
3731 #endif
3732                 { config_parse_job_mode,              "MODE" },
3733                 { config_parse_job_mode_isolate,      "BOOLEAN" },
3734                 { config_parse_personality,           "PERSONALITY" },
3735         };
3736
3737         const char *prev = NULL;
3738         const char *i;
3739
3740         assert(f);
3741
3742         NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
3743                 const char *rvalue = "OTHER", *lvalue;
3744                 unsigned j;
3745                 size_t prefix_len;
3746                 const char *dot;
3747                 const ConfigPerfItem *p;
3748
3749                 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
3750
3751                 dot = strchr(i, '.');
3752                 lvalue = dot ? dot + 1 : i;
3753                 prefix_len = dot-i;
3754
3755                 if (dot)
3756                         if (!prev || !strneq(prev, i, prefix_len+1)) {
3757                                 if (prev)
3758                                         fputc('\n', f);
3759
3760                                 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
3761                         }
3762
3763                 for (j = 0; j < ELEMENTSOF(table); j++)
3764                         if (p->parse == table[j].callback) {
3765                                 rvalue = table[j].rvalue;
3766                                 break;
3767                         }
3768
3769                 fprintf(f, "%s=%s\n", lvalue, rvalue);
3770                 prev = i;
3771         }
3772 }