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