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