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