chiark / gitweb /
core: remove unused variables
[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         bool invert = false;
2491         const char *word, *state;
2492         size_t l;
2493         int r;
2494
2495         assert(filename);
2496         assert(lvalue);
2497         assert(rvalue);
2498
2499         if (isempty(rvalue)) {
2500                 /* Empty assignment resets the list */
2501                 set_free(c->address_families);
2502                 c->address_families = NULL;
2503                 c->address_families_whitelist = false;
2504                 return 0;
2505         }
2506
2507         if (rvalue[0] == '~') {
2508                 invert = true;
2509                 rvalue++;
2510         }
2511
2512         if (!c->address_families) {
2513                 c->address_families = set_new(NULL);
2514                 if (!c->address_families)
2515                         return log_oom();
2516
2517                 c->address_families_whitelist = !invert;
2518         }
2519
2520         FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2521                 _cleanup_free_ char *t = NULL;
2522                 int af;
2523
2524                 t = strndup(word, l);
2525                 if (!t)
2526                         return log_oom();
2527
2528                 af = af_from_name(t);
2529                 if (af <= 0)  {
2530                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2531                                    "Failed to parse address family, ignoring: %s", t);
2532                         continue;
2533                 }
2534
2535                 /* If we previously wanted to forbid an address family and now
2536                  * we want to allow it, then remove it from the list
2537                  */
2538                 if (!invert == c->address_families_whitelist)  {
2539                         r = set_put(c->address_families, INT_TO_PTR(af));
2540                         if (r == -EEXIST)
2541                                 continue;
2542                         if (r < 0)
2543                                 return log_oom();
2544                 } else
2545                         set_remove(c->address_families, INT_TO_PTR(af));
2546         }
2547         if (!isempty(state))
2548                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2549                            "Trailing garbage, ignoring.");
2550
2551         return 0;
2552 }
2553 #endif
2554
2555 int config_parse_unit_slice(
2556                 const char *unit,
2557                 const char *filename,
2558                 unsigned line,
2559                 const char *section,
2560                 unsigned section_line,
2561                 const char *lvalue,
2562                 int ltype,
2563                 const char *rvalue,
2564                 void *data,
2565                 void *userdata) {
2566
2567         _cleanup_free_ char *k = NULL;
2568         Unit *u = userdata, *slice;
2569         int r;
2570
2571         assert(filename);
2572         assert(lvalue);
2573         assert(rvalue);
2574         assert(u);
2575
2576         r = unit_name_printf(u, rvalue, &k);
2577         if (r < 0)
2578                 log_syntax(unit, LOG_ERR, filename, line, -r,
2579                            "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
2580         if (!k) {
2581                 k = strdup(rvalue);
2582                 if (!k)
2583                         return log_oom();
2584         }
2585
2586         r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
2587         if (r < 0) {
2588                 log_syntax(unit, LOG_ERR, filename, line, -r,
2589                            "Failed to load slice unit %s. Ignoring.", k);
2590                 return 0;
2591         }
2592
2593         if (slice->type != UNIT_SLICE) {
2594                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2595                            "Slice unit %s is not a slice. Ignoring.", k);
2596                 return 0;
2597         }
2598
2599         unit_ref_set(&u->slice, slice);
2600         return 0;
2601 }
2602
2603 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
2604
2605 int config_parse_cpu_shares(
2606                 const char *unit,
2607                 const char *filename,
2608                 unsigned line,
2609                 const char *section,
2610                 unsigned section_line,
2611                 const char *lvalue,
2612                 int ltype,
2613                 const char *rvalue,
2614                 void *data,
2615                 void *userdata) {
2616
2617         unsigned long *shares = data, lu;
2618         int r;
2619
2620         assert(filename);
2621         assert(lvalue);
2622         assert(rvalue);
2623
2624         if (isempty(rvalue)) {
2625                 *shares = (unsigned long) -1;
2626                 return 0;
2627         }
2628
2629         r = safe_atolu(rvalue, &lu);
2630         if (r < 0 || lu <= 0) {
2631                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2632                            "CPU shares '%s' invalid. Ignoring.", rvalue);
2633                 return 0;
2634         }
2635
2636         *shares = lu;
2637         return 0;
2638 }
2639
2640 int config_parse_cpu_quota(
2641                 const char *unit,
2642                 const char *filename,
2643                 unsigned line,
2644                 const char *section,
2645                 unsigned section_line,
2646                 const char *lvalue,
2647                 int ltype,
2648                 const char *rvalue,
2649                 void *data,
2650                 void *userdata) {
2651
2652         CGroupContext *c = data;
2653         double percent;
2654
2655         assert(filename);
2656         assert(lvalue);
2657         assert(rvalue);
2658
2659         if (isempty(rvalue)) {
2660                 c->cpu_quota_per_sec_usec = USEC_INFINITY;
2661                 return 0;
2662         }
2663
2664         if (!endswith(rvalue, "%")) {
2665
2666                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2667                            "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue);
2668                 return 0;
2669         }
2670
2671         if (sscanf(rvalue, "%lf%%", &percent) != 1 || percent <= 0) {
2672                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2673                            "CPU quota '%s' invalid. Ignoring.", rvalue);
2674                 return 0;
2675         }
2676
2677         c->cpu_quota_per_sec_usec = (usec_t) (percent * USEC_PER_SEC / 100);
2678
2679         return 0;
2680 }
2681
2682 int config_parse_memory_limit(
2683                 const char *unit,
2684                 const char *filename,
2685                 unsigned line,
2686                 const char *section,
2687                 unsigned section_line,
2688                 const char *lvalue,
2689                 int ltype,
2690                 const char *rvalue,
2691                 void *data,
2692                 void *userdata) {
2693
2694         CGroupContext *c = data;
2695         off_t bytes;
2696         int r;
2697
2698         if (isempty(rvalue)) {
2699                 c->memory_limit = (uint64_t) -1;
2700                 return 0;
2701         }
2702
2703         assert_cc(sizeof(uint64_t) == sizeof(off_t));
2704
2705         r = parse_size(rvalue, 1024, &bytes);
2706         if (r < 0) {
2707                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2708                            "Memory limit '%s' invalid. Ignoring.", rvalue);
2709                 return 0;
2710         }
2711
2712         c->memory_limit = (uint64_t) bytes;
2713         return 0;
2714 }
2715
2716 int config_parse_device_allow(
2717                 const char *unit,
2718                 const char *filename,
2719                 unsigned line,
2720                 const char *section,
2721                 unsigned section_line,
2722                 const char *lvalue,
2723                 int ltype,
2724                 const char *rvalue,
2725                 void *data,
2726                 void *userdata) {
2727
2728         _cleanup_free_ char *path = NULL;
2729         CGroupContext *c = data;
2730         CGroupDeviceAllow *a;
2731         const char *m;
2732         size_t n;
2733
2734         if (isempty(rvalue)) {
2735                 while (c->device_allow)
2736                         cgroup_context_free_device_allow(c, c->device_allow);
2737
2738                 return 0;
2739         }
2740
2741         n = strcspn(rvalue, WHITESPACE);
2742         path = strndup(rvalue, n);
2743         if (!path)
2744                 return log_oom();
2745
2746         if (!startswith(path, "/dev/") &&
2747             !startswith(path, "block-") &&
2748             !startswith(path, "char-")) {
2749                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2750                            "Invalid device node path '%s'. Ignoring.", path);
2751                 return 0;
2752         }
2753
2754         m = rvalue + n + strspn(rvalue + n, WHITESPACE);
2755         if (isempty(m))
2756                 m = "rwm";
2757
2758         if (!in_charset(m, "rwm")) {
2759                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2760                            "Invalid device rights '%s'. Ignoring.", m);
2761                 return 0;
2762         }
2763
2764         a = new0(CGroupDeviceAllow, 1);
2765         if (!a)
2766                 return log_oom();
2767
2768         a->path = path;
2769         path = NULL;
2770         a->r = !!strchr(m, 'r');
2771         a->w = !!strchr(m, 'w');
2772         a->m = !!strchr(m, 'm');
2773
2774         LIST_PREPEND(device_allow, c->device_allow, a);
2775         return 0;
2776 }
2777
2778 int config_parse_blockio_weight(
2779                 const char *unit,
2780                 const char *filename,
2781                 unsigned line,
2782                 const char *section,
2783                 unsigned section_line,
2784                 const char *lvalue,
2785                 int ltype,
2786                 const char *rvalue,
2787                 void *data,
2788                 void *userdata) {
2789
2790         unsigned long *weight = data, lu;
2791         int r;
2792
2793         assert(filename);
2794         assert(lvalue);
2795         assert(rvalue);
2796
2797         if (isempty(rvalue)) {
2798                 *weight = (unsigned long) -1;
2799                 return 0;
2800         }
2801
2802         r = safe_atolu(rvalue, &lu);
2803         if (r < 0 || lu < 10 || lu > 1000) {
2804                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2805                            "Block IO weight '%s' invalid. Ignoring.", rvalue);
2806                 return 0;
2807         }
2808
2809         *weight = lu;
2810         return 0;
2811 }
2812
2813 int config_parse_blockio_device_weight(
2814                 const char *unit,
2815                 const char *filename,
2816                 unsigned line,
2817                 const char *section,
2818                 unsigned section_line,
2819                 const char *lvalue,
2820                 int ltype,
2821                 const char *rvalue,
2822                 void *data,
2823                 void *userdata) {
2824
2825         _cleanup_free_ char *path = NULL;
2826         CGroupBlockIODeviceWeight *w;
2827         CGroupContext *c = data;
2828         unsigned long lu;
2829         const char *weight;
2830         size_t n;
2831         int r;
2832
2833         assert(filename);
2834         assert(lvalue);
2835         assert(rvalue);
2836
2837         if (isempty(rvalue)) {
2838                 while (c->blockio_device_weights)
2839                         cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
2840
2841                 return 0;
2842         }
2843
2844         n = strcspn(rvalue, WHITESPACE);
2845         weight = rvalue + n;
2846         if (!*weight) {
2847                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2848                            "Expected block device and device weight. Ignoring.");
2849                 return 0;
2850         }
2851
2852         path = strndup(rvalue, n);
2853         if (!path)
2854                 return log_oom();
2855
2856         if (!path_startswith(path, "/dev")) {
2857                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2858                            "Invalid device node path '%s'. Ignoring.", path);
2859                 return 0;
2860         }
2861
2862         weight += strspn(weight, WHITESPACE);
2863         r = safe_atolu(weight, &lu);
2864         if (r < 0 || lu < 10 || lu > 1000) {
2865                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2866                            "Block IO weight '%s' invalid. Ignoring.", rvalue);
2867                 return 0;
2868         }
2869
2870         w = new0(CGroupBlockIODeviceWeight, 1);
2871         if (!w)
2872                 return log_oom();
2873
2874         w->path = path;
2875         path = NULL;
2876
2877         w->weight = lu;
2878
2879         LIST_PREPEND(device_weights, c->blockio_device_weights, w);
2880         return 0;
2881 }
2882
2883 int config_parse_blockio_bandwidth(
2884                 const char *unit,
2885                 const char *filename,
2886                 unsigned line,
2887                 const char *section,
2888                 unsigned section_line,
2889                 const char *lvalue,
2890                 int ltype,
2891                 const char *rvalue,
2892                 void *data,
2893                 void *userdata) {
2894
2895         _cleanup_free_ char *path = NULL;
2896         CGroupBlockIODeviceBandwidth *b;
2897         CGroupContext *c = data;
2898         const char *bandwidth;
2899         off_t bytes;
2900         bool read;
2901         size_t n;
2902         int r;
2903
2904         assert(filename);
2905         assert(lvalue);
2906         assert(rvalue);
2907
2908         read = streq("BlockIOReadBandwidth", lvalue);
2909
2910         if (isempty(rvalue)) {
2911                 CGroupBlockIODeviceBandwidth *next;
2912
2913                 LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
2914                         if (b->read == read)
2915                                 cgroup_context_free_blockio_device_bandwidth(c, b);
2916
2917                 return 0;
2918         }
2919
2920         n = strcspn(rvalue, WHITESPACE);
2921         bandwidth = rvalue + n;
2922         bandwidth += strspn(bandwidth, WHITESPACE);
2923
2924         if (!*bandwidth) {
2925                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2926                            "Expected space separated pair of device node and bandwidth. Ignoring.");
2927                 return 0;
2928         }
2929
2930         path = strndup(rvalue, n);
2931         if (!path)
2932                 return log_oom();
2933
2934         if (!path_startswith(path, "/dev")) {
2935                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2936                            "Invalid device node path '%s'. Ignoring.", path);
2937                 return 0;
2938         }
2939
2940         r = parse_size(bandwidth, 1000, &bytes);
2941         if (r < 0 || bytes <= 0) {
2942                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2943                            "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
2944                 return 0;
2945         }
2946
2947         b = new0(CGroupBlockIODeviceBandwidth, 1);
2948         if (!b)
2949                 return log_oom();
2950
2951         b->path = path;
2952         path = NULL;
2953         b->bandwidth = (uint64_t) bytes;
2954         b->read = read;
2955
2956         LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
2957
2958         return 0;
2959 }
2960
2961 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
2962
2963 int config_parse_job_mode_isolate(
2964                 const char *unit,
2965                 const char *filename,
2966                 unsigned line,
2967                 const char *section,
2968                 unsigned section_line,
2969                 const char *lvalue,
2970                 int ltype,
2971                 const char *rvalue,
2972                 void *data,
2973                 void *userdata) {
2974
2975         JobMode *m = data;
2976         int r;
2977
2978         assert(filename);
2979         assert(lvalue);
2980         assert(rvalue);
2981
2982         r = parse_boolean(rvalue);
2983         if (r < 0) {
2984                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2985                            "Failed to parse boolean, ignoring: %s", rvalue);
2986                 return 0;
2987         }
2988
2989         *m = r ? JOB_ISOLATE : JOB_REPLACE;
2990         return 0;
2991 }
2992
2993 int config_parse_personality(
2994                 const char *unit,
2995                 const char *filename,
2996                 unsigned line,
2997                 const char *section,
2998                 unsigned section_line,
2999                 const char *lvalue,
3000                 int ltype,
3001                 const char *rvalue,
3002                 void *data,
3003                 void *userdata) {
3004
3005         unsigned long *personality = data, p;
3006
3007         assert(filename);
3008         assert(lvalue);
3009         assert(rvalue);
3010         assert(personality);
3011
3012         p = personality_from_string(rvalue);
3013         if (p == 0xffffffffUL) {
3014                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3015                            "Failed to parse personality, ignoring: %s", rvalue);
3016                 return 0;
3017         }
3018
3019         *personality = p;
3020         return 0;
3021 }
3022
3023 int config_parse_runtime_directory(
3024                 const char *unit,
3025                 const char *filename,
3026                 unsigned line,
3027                 const char *section,
3028                 unsigned section_line,
3029                 const char *lvalue,
3030                 int ltype,
3031                 const char *rvalue,
3032                 void *data,
3033                 void *userdata) {
3034
3035         char***rt = data;
3036         const char *word, *state;
3037         size_t l;
3038         int r;
3039
3040         assert(filename);
3041         assert(lvalue);
3042         assert(rvalue);
3043         assert(data);
3044
3045         if (isempty(rvalue)) {
3046                 /* Empty assignment resets the list */
3047                 strv_free(*rt);
3048                 *rt = NULL;
3049                 return 0;
3050         }
3051
3052         FOREACH_WORD_QUOTED(word, l, rvalue, state) {
3053                 _cleanup_free_ char *n;
3054
3055                 n = strndup(word, l);
3056                 if (!n)
3057                         return log_oom();
3058
3059                 if (!filename_is_safe(n)) {
3060                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3061                                    "Runtime directory is not valid, ignoring assignment: %s", rvalue);
3062                         continue;
3063                 }
3064
3065                 r = strv_push(rt, n);
3066                 if (r < 0)
3067                         return log_oom();
3068
3069                 n = NULL;
3070         }
3071         if (!isempty(state))
3072                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3073                            "Trailing garbage, ignoring.");
3074
3075         return 0;
3076 }
3077
3078 int config_parse_set_status(
3079                 const char *unit,
3080                 const char *filename,
3081                 unsigned line,
3082                 const char *section,
3083                 unsigned section_line,
3084                 const char *lvalue,
3085                 int ltype,
3086                 const char *rvalue,
3087                 void *data,
3088                 void *userdata) {
3089
3090         size_t l;
3091         const char *word, *state;
3092         int r;
3093         ExitStatusSet *status_set = data;
3094
3095         assert(filename);
3096         assert(lvalue);
3097         assert(rvalue);
3098         assert(data);
3099
3100         /* Empty assignment resets the list */
3101         if (isempty(rvalue)) {
3102                 exit_status_set_free(status_set);
3103                 return 0;
3104         }
3105
3106         FOREACH_WORD(word, l, rvalue, state) {
3107                 _cleanup_free_ char *temp;
3108                 int val;
3109
3110                 temp = strndup(word, l);
3111                 if (!temp)
3112                         return log_oom();
3113
3114                 r = safe_atoi(temp, &val);
3115                 if (r < 0) {
3116                         val = signal_from_string_try_harder(temp);
3117
3118                         if (val <= 0) {
3119                                 log_syntax(unit, LOG_ERR, filename, line, -val,
3120                                            "Failed to parse value, ignoring: %s", word);
3121                                 return 0;
3122                         }
3123                 } else {
3124                         if (val < 0 || val > 255) {
3125                                 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
3126                                            "Value %d is outside range 0-255, ignoring", val);
3127                                 continue;
3128                         }
3129                 }
3130
3131                 r = set_ensure_allocated(&status_set->status, NULL);
3132                 if (r < 0)
3133                         return log_oom();
3134
3135                 r = set_put(status_set->status, INT_TO_PTR(val));
3136                 if (r < 0) {
3137                         log_syntax(unit, LOG_ERR, filename, line, -r,
3138                                    "Unable to store: %s", word);
3139                         return r;
3140                 }
3141         }
3142         if (!isempty(state))
3143                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3144                            "Trailing garbage, ignoring.");
3145
3146         return 0;
3147 }
3148
3149 int config_parse_namespace_path_strv(
3150                 const char *unit,
3151                 const char *filename,
3152                 unsigned line,
3153                 const char *section,
3154                 unsigned section_line,
3155                 const char *lvalue,
3156                 int ltype,
3157                 const char *rvalue,
3158                 void *data,
3159                 void *userdata) {
3160
3161         char*** sv = data;
3162         const char *word, *state;
3163         size_t l;
3164         int r;
3165
3166         assert(filename);
3167         assert(lvalue);
3168         assert(rvalue);
3169         assert(data);
3170
3171         if (isempty(rvalue)) {
3172                 /* Empty assignment resets the list */
3173                 strv_free(*sv);
3174                 *sv = NULL;
3175                 return 0;
3176         }
3177
3178         FOREACH_WORD_QUOTED(word, l, rvalue, state) {
3179                 _cleanup_free_ char *n;
3180                 int offset;
3181
3182                 n = strndup(word, l);
3183                 if (!n)
3184                         return log_oom();
3185
3186                 if (!utf8_is_valid(n)) {
3187                         log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
3188                         continue;
3189                 }
3190
3191                 offset = n[0] == '-';
3192                 if (!path_is_absolute(n + offset)) {
3193                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3194                                    "Not an absolute path, ignoring: %s", rvalue);
3195                         continue;
3196                 }
3197
3198                 path_kill_slashes(n);
3199
3200                 r = strv_push(sv, n);
3201                 if (r < 0)
3202                         return log_oom();
3203
3204                 n = NULL;
3205         }
3206         if (!isempty(state))
3207                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3208                            "Trailing garbage, ignoring.");
3209
3210         return 0;
3211 }
3212
3213 int config_parse_no_new_privileges(
3214                 const char* unit,
3215                 const char *filename,
3216                 unsigned line,
3217                 const char *section,
3218                 unsigned section_line,
3219                 const char *lvalue,
3220                 int ltype,
3221                 const char *rvalue,
3222                 void *data,
3223                 void *userdata) {
3224
3225         ExecContext *c = data;
3226         int k;
3227
3228         assert(filename);
3229         assert(lvalue);
3230         assert(rvalue);
3231         assert(data);
3232
3233         k = parse_boolean(rvalue);
3234         if (k < 0) {
3235                 log_syntax(unit, LOG_ERR, filename, line, -k,
3236                            "Failed to parse boolean value, ignoring: %s", rvalue);
3237                 return 0;
3238         }
3239
3240         c->no_new_privileges = !!k;
3241         c->no_new_privileges_set = true;
3242
3243         return 0;
3244 }
3245
3246 int config_parse_protect_home(
3247                 const char* unit,
3248                 const char *filename,
3249                 unsigned line,
3250                 const char *section,
3251                 unsigned section_line,
3252                 const char *lvalue,
3253                 int ltype,
3254                 const char *rvalue,
3255                 void *data,
3256                 void *userdata) {
3257
3258         ExecContext *c = data;
3259         int k;
3260
3261         assert(filename);
3262         assert(lvalue);
3263         assert(rvalue);
3264         assert(data);
3265
3266         /* Our enum shall be a superset of booleans, hence first try
3267          * to parse as as boolean, and then as enum */
3268
3269         k = parse_boolean(rvalue);
3270         if (k > 0)
3271                 c->protect_home = PROTECT_HOME_YES;
3272         else if (k == 0)
3273                 c->protect_home = PROTECT_HOME_NO;
3274         else {
3275                 ProtectHome h;
3276
3277                 h = protect_home_from_string(rvalue);
3278                 if (h < 0){
3279                         log_syntax(unit, LOG_ERR, filename, line, -h,
3280                                    "Failed to parse protect home value, ignoring: %s", rvalue);
3281                         return 0;
3282                 }
3283
3284                 c->protect_home = h;
3285         }
3286
3287         return 0;
3288 }
3289
3290 int config_parse_protect_system(
3291                 const char* unit,
3292                 const char *filename,
3293                 unsigned line,
3294                 const char *section,
3295                 unsigned section_line,
3296                 const char *lvalue,
3297                 int ltype,
3298                 const char *rvalue,
3299                 void *data,
3300                 void *userdata) {
3301
3302         ExecContext *c = data;
3303         int k;
3304
3305         assert(filename);
3306         assert(lvalue);
3307         assert(rvalue);
3308         assert(data);
3309
3310         /* Our enum shall be a superset of booleans, hence first try
3311          * to parse as as boolean, and then as enum */
3312
3313         k = parse_boolean(rvalue);
3314         if (k > 0)
3315                 c->protect_system = PROTECT_SYSTEM_YES;
3316         else if (k == 0)
3317                 c->protect_system = PROTECT_SYSTEM_NO;
3318         else {
3319                 ProtectSystem s;
3320
3321                 s = protect_system_from_string(rvalue);
3322                 if (s < 0){
3323                         log_syntax(unit, LOG_ERR, filename, line, -s,
3324                                    "Failed to parse protect system value, ignoring: %s", rvalue);
3325                         return 0;
3326                 }
3327
3328                 c->protect_system = s;
3329         }
3330
3331         return 0;
3332 }
3333
3334 #define FOLLOW_MAX 8
3335
3336 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
3337         unsigned c = 0;
3338         int fd, r;
3339         FILE *f;
3340         char *id = NULL;
3341
3342         assert(filename);
3343         assert(*filename);
3344         assert(_f);
3345         assert(names);
3346
3347         /* This will update the filename pointer if the loaded file is
3348          * reached by a symlink. The old string will be freed. */
3349
3350         for (;;) {
3351                 char *target, *name;
3352
3353                 if (c++ >= FOLLOW_MAX)
3354                         return -ELOOP;
3355
3356                 path_kill_slashes(*filename);
3357
3358                 /* Add the file name we are currently looking at to
3359                  * the names of this unit, but only if it is a valid
3360                  * unit name. */
3361                 name = basename(*filename);
3362
3363                 if (unit_name_is_valid(name, TEMPLATE_VALID)) {
3364
3365                         id = set_get(names, name);
3366                         if (!id) {
3367                                 id = strdup(name);
3368                                 if (!id)
3369                                         return -ENOMEM;
3370
3371                                 r = set_consume(names, id);
3372                                 if (r < 0)
3373                                         return r;
3374                         }
3375                 }
3376
3377                 /* Try to open the file name, but don't if its a symlink */
3378                 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
3379                 if (fd >= 0)
3380                         break;
3381
3382                 if (errno != ELOOP)
3383                         return -errno;
3384
3385                 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
3386                 r = readlink_and_make_absolute(*filename, &target);
3387                 if (r < 0)
3388                         return r;
3389
3390                 free(*filename);
3391                 *filename = target;
3392         }
3393
3394         f = fdopen(fd, "re");
3395         if (!f) {
3396                 r = -errno;
3397                 safe_close(fd);
3398                 return r;
3399         }
3400
3401         *_f = f;
3402         *_final = id;
3403         return 0;
3404 }
3405
3406 static int merge_by_names(Unit **u, Set *names, const char *id) {
3407         char *k;
3408         int r;
3409
3410         assert(u);
3411         assert(*u);
3412         assert(names);
3413
3414         /* Let's try to add in all symlink names we found */
3415         while ((k = set_steal_first(names))) {
3416
3417                 /* First try to merge in the other name into our
3418                  * unit */
3419                 r = unit_merge_by_name(*u, k);
3420                 if (r < 0) {
3421                         Unit *other;
3422
3423                         /* Hmm, we couldn't merge the other unit into
3424                          * ours? Then let's try it the other way
3425                          * round */
3426
3427                         other = manager_get_unit((*u)->manager, k);
3428                         free(k);
3429
3430                         if (other) {
3431                                 r = unit_merge(other, *u);
3432                                 if (r >= 0) {
3433                                         *u = other;
3434                                         return merge_by_names(u, names, NULL);
3435                                 }
3436                         }
3437
3438                         return r;
3439                 }
3440
3441                 if (id == k)
3442                         unit_choose_id(*u, id);
3443
3444                 free(k);
3445         }
3446
3447         return 0;
3448 }
3449
3450 static int load_from_path(Unit *u, const char *path) {
3451         int r;
3452         _cleanup_set_free_free_ Set *symlink_names = NULL;
3453         _cleanup_fclose_ FILE *f = NULL;
3454         _cleanup_free_ char *filename = NULL;
3455         char *id = NULL;
3456         Unit *merged;
3457         struct stat st;
3458
3459         assert(u);
3460         assert(path);
3461
3462         symlink_names = set_new(&string_hash_ops);
3463         if (!symlink_names)
3464                 return -ENOMEM;
3465
3466         if (path_is_absolute(path)) {
3467
3468                 filename = strdup(path);
3469                 if (!filename)
3470                         return -ENOMEM;
3471
3472                 r = open_follow(&filename, &f, symlink_names, &id);
3473                 if (r < 0) {
3474                         free(filename);
3475                         filename = NULL;
3476
3477                         if (r != -ENOENT)
3478                                 return r;
3479                 }
3480
3481         } else  {
3482                 char **p;
3483
3484                 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
3485
3486                         /* Instead of opening the path right away, we manually
3487                          * follow all symlinks and add their name to our unit
3488                          * name set while doing so */
3489                         filename = path_make_absolute(path, *p);
3490                         if (!filename)
3491                                 return -ENOMEM;
3492
3493                         if (u->manager->unit_path_cache &&
3494                             !set_get(u->manager->unit_path_cache, filename))
3495                                 r = -ENOENT;
3496                         else
3497                                 r = open_follow(&filename, &f, symlink_names, &id);
3498
3499                         if (r < 0) {
3500                                 free(filename);
3501                                 filename = NULL;
3502
3503                                 if (r != -ENOENT)
3504                                         return r;
3505
3506                                 /* Empty the symlink names for the next run */
3507                                 set_clear_free(symlink_names);
3508                                 continue;
3509                         }
3510
3511                         break;
3512                 }
3513         }
3514
3515         if (!filename)
3516                 /* Hmm, no suitable file found? */
3517                 return 0;
3518
3519         merged = u;
3520         r = merge_by_names(&merged, symlink_names, id);
3521         if (r < 0)
3522                 return r;
3523
3524         if (merged != u) {
3525                 u->load_state = UNIT_MERGED;
3526                 return 0;
3527         }
3528
3529         if (fstat(fileno(f), &st) < 0)
3530                 return -errno;
3531
3532         if (null_or_empty(&st))
3533                 u->load_state = UNIT_MASKED;
3534         else {
3535                 u->load_state = UNIT_LOADED;
3536
3537                 /* Now, parse the file contents */
3538                 r = config_parse(u->id, filename, f,
3539                                  UNIT_VTABLE(u)->sections,
3540                                  config_item_perf_lookup, load_fragment_gperf_lookup,
3541                                  false, true, false, u);
3542                 if (r < 0)
3543                         return r;
3544         }
3545
3546         free(u->fragment_path);
3547         u->fragment_path = filename;
3548         filename = NULL;
3549
3550         u->fragment_mtime = timespec_load(&st.st_mtim);
3551
3552         if (u->source_path) {
3553                 if (stat(u->source_path, &st) >= 0)
3554                         u->source_mtime = timespec_load(&st.st_mtim);
3555                 else
3556                         u->source_mtime = 0;
3557         }
3558
3559         return 0;
3560 }
3561
3562 int unit_load_fragment(Unit *u) {
3563         int r;
3564         Iterator i;
3565         const char *t;
3566
3567         assert(u);
3568         assert(u->load_state == UNIT_STUB);
3569         assert(u->id);
3570
3571         /* First, try to find the unit under its id. We always look
3572          * for unit files in the default directories, to make it easy
3573          * to override things by placing things in /etc/systemd/system */
3574         r = load_from_path(u, u->id);
3575         if (r < 0)
3576                 return r;
3577
3578         /* Try to find an alias we can load this with */
3579         if (u->load_state == UNIT_STUB)
3580                 SET_FOREACH(t, u->names, i) {
3581
3582                         if (t == u->id)
3583                                 continue;
3584
3585                         r = load_from_path(u, t);
3586                         if (r < 0)
3587                                 return r;
3588
3589                         if (u->load_state != UNIT_STUB)
3590                                 break;
3591                 }
3592
3593         /* And now, try looking for it under the suggested (originally linked) path */
3594         if (u->load_state == UNIT_STUB && u->fragment_path) {
3595
3596                 r = load_from_path(u, u->fragment_path);
3597                 if (r < 0)
3598                         return r;
3599
3600                 if (u->load_state == UNIT_STUB) {
3601                         /* Hmm, this didn't work? Then let's get rid
3602                          * of the fragment path stored for us, so that
3603                          * we don't point to an invalid location. */
3604                         free(u->fragment_path);
3605                         u->fragment_path = NULL;
3606                 }
3607         }
3608
3609         /* Look for a template */
3610         if (u->load_state == UNIT_STUB && u->instance) {
3611                 _cleanup_free_ char *k;
3612
3613                 k = unit_name_template(u->id);
3614                 if (!k)
3615                         return -ENOMEM;
3616
3617                 r = load_from_path(u, k);
3618                 if (r < 0)
3619                         return r;
3620
3621                 if (u->load_state == UNIT_STUB)
3622                         SET_FOREACH(t, u->names, i) {
3623                                 _cleanup_free_ char *z = NULL;
3624
3625                                 if (t == u->id)
3626                                         continue;
3627
3628                                 z = unit_name_template(t);
3629                                 if (!z)
3630                                         return -ENOMEM;
3631
3632                                 r = load_from_path(u, z);
3633                                 if (r < 0)
3634                                         return r;
3635
3636                                 if (u->load_state != UNIT_STUB)
3637                                         break;
3638                         }
3639         }
3640
3641         return 0;
3642 }
3643
3644 void unit_dump_config_items(FILE *f) {
3645         static const struct {
3646                 const ConfigParserCallback callback;
3647                 const char *rvalue;
3648         } table[] = {
3649 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
3650                 { config_parse_warn_compat,           "NOTSUPPORTED" },
3651 #endif
3652                 { config_parse_int,                   "INTEGER" },
3653                 { config_parse_unsigned,              "UNSIGNED" },
3654                 { config_parse_iec_size,              "SIZE" },
3655                 { config_parse_iec_off,               "SIZE" },
3656                 { config_parse_si_size,               "SIZE" },
3657                 { config_parse_bool,                  "BOOLEAN" },
3658                 { config_parse_string,                "STRING" },
3659                 { config_parse_path,                  "PATH" },
3660                 { config_parse_unit_path_printf,      "PATH" },
3661                 { config_parse_strv,                  "STRING [...]" },
3662                 { config_parse_exec_nice,             "NICE" },
3663                 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
3664                 { config_parse_exec_io_class,         "IOCLASS" },
3665                 { config_parse_exec_io_priority,      "IOPRIORITY" },
3666                 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
3667                 { config_parse_exec_cpu_sched_prio,   "CPUSCHEDPRIO" },
3668                 { config_parse_exec_cpu_affinity,     "CPUAFFINITY" },
3669                 { config_parse_mode,                  "MODE" },
3670                 { config_parse_unit_env_file,         "FILE" },
3671                 { config_parse_output,                "OUTPUT" },
3672                 { config_parse_input,                 "INPUT" },
3673                 { config_parse_log_facility,          "FACILITY" },
3674                 { config_parse_log_level,             "LEVEL" },
3675                 { config_parse_exec_capabilities,     "CAPABILITIES" },
3676                 { config_parse_exec_secure_bits,      "SECUREBITS" },
3677                 { config_parse_bounding_set,          "BOUNDINGSET" },
3678                 { config_parse_limit,                 "LIMIT" },
3679                 { config_parse_unit_deps,             "UNIT [...]" },
3680                 { config_parse_exec,                  "PATH [ARGUMENT [...]]" },
3681                 { config_parse_service_type,          "SERVICETYPE" },
3682                 { config_parse_service_restart,       "SERVICERESTART" },
3683 #ifdef HAVE_SYSV_COMPAT
3684                 { config_parse_sysv_priority,         "SYSVPRIORITY" },
3685 #endif
3686                 { config_parse_kill_mode,             "KILLMODE" },
3687                 { config_parse_kill_signal,           "SIGNAL" },
3688                 { config_parse_socket_listen,         "SOCKET [...]" },
3689                 { config_parse_socket_bind,           "SOCKETBIND" },
3690                 { config_parse_socket_bindtodevice,   "NETWORKINTERFACE" },
3691                 { config_parse_sec,                   "SECONDS" },
3692                 { config_parse_nsec,                  "NANOSECONDS" },
3693                 { config_parse_namespace_path_strv,   "PATH [...]" },
3694                 { config_parse_unit_requires_mounts_for, "PATH [...]" },
3695                 { config_parse_exec_mount_flags,      "MOUNTFLAG [...]" },
3696                 { config_parse_unit_string_printf,    "STRING" },
3697                 { config_parse_trigger_unit,          "UNIT" },
3698                 { config_parse_timer,                 "TIMER" },
3699                 { config_parse_path_spec,             "PATH" },
3700                 { config_parse_notify_access,         "ACCESS" },
3701                 { config_parse_ip_tos,                "TOS" },
3702                 { config_parse_unit_condition_path,   "CONDITION" },
3703                 { config_parse_unit_condition_string, "CONDITION" },
3704                 { config_parse_unit_condition_null,   "CONDITION" },
3705                 { config_parse_unit_slice,            "SLICE" },
3706                 { config_parse_documentation,         "URL" },
3707                 { config_parse_service_timeout,       "SECONDS" },
3708                 { config_parse_failure_action,        "ACTION" },
3709                 { config_parse_set_status,            "STATUS" },
3710                 { config_parse_service_sockets,       "SOCKETS" },
3711                 { config_parse_environ,               "ENVIRON" },
3712 #ifdef HAVE_SECCOMP
3713                 { config_parse_syscall_filter,        "SYSCALLS" },
3714                 { config_parse_syscall_archs,         "ARCHS" },
3715                 { config_parse_syscall_errno,         "ERRNO" },
3716                 { config_parse_address_families,      "FAMILIES" },
3717 #endif
3718                 { config_parse_cpu_shares,            "SHARES" },
3719                 { config_parse_memory_limit,          "LIMIT" },
3720                 { config_parse_device_allow,          "DEVICE" },
3721                 { config_parse_device_policy,         "POLICY" },
3722                 { config_parse_blockio_bandwidth,     "BANDWIDTH" },
3723                 { config_parse_blockio_weight,        "WEIGHT" },
3724                 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
3725                 { config_parse_long,                  "LONG" },
3726                 { config_parse_socket_service,        "SERVICE" },
3727 #ifdef HAVE_SELINUX
3728                 { config_parse_exec_selinux_context,  "LABEL" },
3729 #endif
3730                 { config_parse_job_mode,              "MODE" },
3731                 { config_parse_job_mode_isolate,      "BOOLEAN" },
3732                 { config_parse_personality,           "PERSONALITY" },
3733         };
3734
3735         const char *prev = NULL;
3736         const char *i;
3737
3738         assert(f);
3739
3740         NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
3741                 const char *rvalue = "OTHER", *lvalue;
3742                 unsigned j;
3743                 size_t prefix_len;
3744                 const char *dot;
3745                 const ConfigPerfItem *p;
3746
3747                 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
3748
3749                 dot = strchr(i, '.');
3750                 lvalue = dot ? dot + 1 : i;
3751                 prefix_len = dot-i;
3752
3753                 if (dot)
3754                         if (!prev || !strneq(prev, i, prefix_len+1)) {
3755                                 if (prev)
3756                                         fputc('\n', f);
3757
3758                                 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
3759                         }
3760
3761                 for (j = 0; j < ELEMENTSOF(table); j++)
3762                         if (p->parse == table[j].callback) {
3763                                 rvalue = table[j].rvalue;
3764                                 break;
3765                         }
3766
3767                 fprintf(f, "%s=%s\n", lvalue, rvalue);
3768                 prev = i;
3769         }
3770 }