chiark / gitweb /
core: add SystemCallArchitectures= unit setting to allow disabling of non-native
[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)
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_timer(const char *unit,
1147                        const char *filename,
1148                        unsigned line,
1149                        const char *section,
1150                        unsigned section_line,
1151                        const char *lvalue,
1152                        int ltype,
1153                        const char *rvalue,
1154                        void *data,
1155                        void *userdata) {
1156
1157         Timer *t = data;
1158         usec_t u = 0;
1159         TimerValue *v;
1160         TimerBase b;
1161         CalendarSpec *c = NULL;
1162         clockid_t id;
1163
1164         assert(filename);
1165         assert(lvalue);
1166         assert(rvalue);
1167         assert(data);
1168
1169         if (isempty(rvalue)) {
1170                 /* Empty assignment resets list */
1171                 timer_free_values(t);
1172                 return 0;
1173         }
1174
1175         b = timer_base_from_string(lvalue);
1176         if (b < 0) {
1177                 log_syntax(unit, LOG_ERR, filename, line, -b,
1178                            "Failed to parse timer base, ignoring: %s", lvalue);
1179                 return 0;
1180         }
1181
1182         if (b == TIMER_CALENDAR) {
1183                 if (calendar_spec_from_string(rvalue, &c) < 0) {
1184                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1185                                    "Failed to parse calendar specification, ignoring: %s",
1186                                    rvalue);
1187                         return 0;
1188                 }
1189
1190                 id = CLOCK_REALTIME;
1191         } else {
1192                 if (parse_sec(rvalue, &u) < 0) {
1193                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1194                                    "Failed to parse timer value, ignoring: %s",
1195                                    rvalue);
1196                         return 0;
1197                 }
1198
1199                 id = CLOCK_MONOTONIC;
1200         }
1201
1202         v = new0(TimerValue, 1);
1203         if (!v)
1204                 return log_oom();
1205
1206         v->base = b;
1207         v->clock_id = id;
1208         v->value = u;
1209         v->calendar_spec = c;
1210
1211         LIST_PREPEND(value, t->values, v);
1212
1213         return 0;
1214 }
1215
1216 int config_parse_trigger_unit(
1217                 const char *unit,
1218                 const char *filename,
1219                 unsigned line,
1220                 const char *section,
1221                 unsigned section_line,
1222                 const char *lvalue,
1223                 int ltype,
1224                 const char *rvalue,
1225                 void *data,
1226                 void *userdata) {
1227
1228         _cleanup_free_ char *p = NULL;
1229         Unit *u = data;
1230         UnitType type;
1231         int r;
1232
1233         assert(filename);
1234         assert(lvalue);
1235         assert(rvalue);
1236         assert(data);
1237
1238         if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
1239                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1240                            "Multiple units to trigger specified, ignoring: %s", rvalue);
1241                 return 0;
1242         }
1243
1244         r = unit_name_printf(u, rvalue, &p);
1245         if (r < 0)
1246                 log_syntax(unit, LOG_ERR, filename, line, -r,
1247                            "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1248
1249         type = unit_name_to_type(p ?: rvalue);
1250         if (type < 0) {
1251                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1252                            "Unit type not valid, ignoring: %s", rvalue);
1253                 return 0;
1254         }
1255
1256         if (type == u->type) {
1257                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1258                            "Trigger cannot be of same type, ignoring: %s", rvalue);
1259                 return 0;
1260         }
1261
1262         r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p ?: rvalue, NULL, true);
1263         if (r < 0) {
1264                 log_syntax(unit, LOG_ERR, filename, line, -r,
1265                            "Failed to add trigger on %s, ignoring: %s", p ?: rvalue, strerror(-r));
1266                 return 0;
1267         }
1268
1269         return 0;
1270 }
1271
1272 int config_parse_path_spec(const char *unit,
1273                            const char *filename,
1274                            unsigned line,
1275                            const char *section,
1276                            unsigned section_line,
1277                            const char *lvalue,
1278                            int ltype,
1279                            const char *rvalue,
1280                            void *data,
1281                            void *userdata) {
1282
1283         Path *p = data;
1284         PathSpec *s;
1285         PathType b;
1286         _cleanup_free_ char *k = NULL;
1287         int r;
1288
1289         assert(filename);
1290         assert(lvalue);
1291         assert(rvalue);
1292         assert(data);
1293
1294         if (isempty(rvalue)) {
1295                 /* Empty assignment clears list */
1296                 path_free_specs(p);
1297                 return 0;
1298         }
1299
1300         b = path_type_from_string(lvalue);
1301         if (b < 0) {
1302                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1303                            "Failed to parse path type, ignoring: %s", lvalue);
1304                 return 0;
1305         }
1306
1307         r = unit_full_printf(UNIT(p), rvalue, &k);
1308         if (r < 0) {
1309                 k = strdup(rvalue);
1310                 if (!k)
1311                         return log_oom();
1312                 else
1313                         log_syntax(unit, LOG_ERR, filename, line, -r,
1314                                    "Failed to resolve unit specifiers on %s. Ignoring.",
1315                                    rvalue);
1316         }
1317
1318         if (!path_is_absolute(k)) {
1319                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1320                            "Path is not absolute, ignoring: %s", k);
1321                 return 0;
1322         }
1323
1324         s = new0(PathSpec, 1);
1325         if (!s)
1326                 return log_oom();
1327
1328         s->unit = UNIT(p);
1329         s->path = path_kill_slashes(k);
1330         k = NULL;
1331         s->type = b;
1332         s->inotify_fd = -1;
1333
1334         LIST_PREPEND(spec, p->specs, s);
1335
1336         return 0;
1337 }
1338
1339 int config_parse_socket_service(const char *unit,
1340                                 const char *filename,
1341                                 unsigned line,
1342                                 const char *section,
1343                                 unsigned section_line,
1344                                 const char *lvalue,
1345                                 int ltype,
1346                                 const char *rvalue,
1347                                 void *data,
1348                                 void *userdata) {
1349
1350         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1351         Socket *s = data;
1352         int r;
1353         Unit *x;
1354         _cleanup_free_ char *p = NULL;
1355
1356         assert(filename);
1357         assert(lvalue);
1358         assert(rvalue);
1359         assert(data);
1360
1361         r = unit_name_printf(UNIT(s), rvalue, &p);
1362         if (r < 0) {
1363                 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
1364                 return 0;
1365         }
1366
1367         if (!endswith(p, ".service")) {
1368                 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type service, ignoring: %s", rvalue);
1369                 return 0;
1370         }
1371
1372         r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
1373         if (r < 0) {
1374                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1375                 return 0;
1376         }
1377
1378         unit_ref_set(&s->service, x);
1379
1380         return 0;
1381 }
1382
1383 int config_parse_service_sockets(const char *unit,
1384                                  const char *filename,
1385                                  unsigned line,
1386                                  const char *section,
1387                                  unsigned section_line,
1388                                  const char *lvalue,
1389                                  int ltype,
1390                                  const char *rvalue,
1391                                  void *data,
1392                                  void *userdata) {
1393
1394         Service *s = data;
1395         int r;
1396         char *state, *w;
1397         size_t l;
1398
1399         assert(filename);
1400         assert(lvalue);
1401         assert(rvalue);
1402         assert(data);
1403
1404         FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1405                 _cleanup_free_ char *t = NULL, *k = NULL;
1406
1407                 t = strndup(w, l);
1408                 if (!t)
1409                         return log_oom();
1410
1411                 r = unit_name_printf(UNIT(s), t, &k);
1412                 if (r < 0)
1413                         log_syntax(unit, LOG_ERR, filename, line, -r,
1414                                    "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1415
1416                 if (!endswith(k ?: t, ".socket")) {
1417                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1418                                    "Unit must be of type socket, ignoring: %s", k ?: t);
1419                         continue;
1420                 }
1421
1422                 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k ?: t, NULL, true);
1423                 if (r < 0)
1424                         log_syntax(unit, LOG_ERR, filename, line, -r,
1425                                    "Failed to add dependency on %s, ignoring: %s",
1426                                    k ?: t, strerror(-r));
1427
1428                 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k ?: t, NULL, true);
1429                 if (r < 0)
1430                         return r;
1431         }
1432
1433         return 0;
1434 }
1435
1436 int config_parse_service_timeout(const char *unit,
1437                                  const char *filename,
1438                                  unsigned line,
1439                                  const char *section,
1440                                  unsigned section_line,
1441                                  const char *lvalue,
1442                                  int ltype,
1443                                  const char *rvalue,
1444                                  void *data,
1445                                  void *userdata) {
1446
1447         Service *s = userdata;
1448         int r;
1449
1450         assert(filename);
1451         assert(lvalue);
1452         assert(rvalue);
1453         assert(s);
1454
1455         r = config_parse_sec(unit, filename, line, section, section_line, lvalue, ltype,
1456                              rvalue, data, userdata);
1457         if (r < 0)
1458                 return r;
1459
1460         if (streq(lvalue, "TimeoutSec")) {
1461                 s->start_timeout_defined = true;
1462                 s->timeout_stop_usec = s->timeout_start_usec;
1463         } else if (streq(lvalue, "TimeoutStartSec"))
1464                 s->start_timeout_defined = true;
1465
1466         return 0;
1467 }
1468
1469 int config_parse_busname_service(
1470                 const char *unit,
1471                 const char *filename,
1472                 unsigned line,
1473                 const char *section,
1474                 unsigned section_line,
1475                 const char *lvalue,
1476                 int ltype,
1477                 const char *rvalue,
1478                 void *data,
1479                 void *userdata) {
1480
1481         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1482         BusName *n = data;
1483         int r;
1484         Unit *x;
1485         _cleanup_free_ char *p = NULL;
1486
1487         assert(filename);
1488         assert(lvalue);
1489         assert(rvalue);
1490         assert(data);
1491
1492         r = unit_name_printf(UNIT(n), rvalue, &p);
1493         if (r < 0) {
1494                 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
1495                 return 0;
1496         }
1497
1498         if (!endswith(p, ".service")) {
1499                 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type service, ignoring: %s", rvalue);
1500                 return 0;
1501         }
1502
1503         r = manager_load_unit(UNIT(n)->manager, p, NULL, &error, &x);
1504         if (r < 0) {
1505                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1506                 return 0;
1507         }
1508
1509         unit_ref_set(&n->service, x);
1510
1511         return 0;
1512 }
1513
1514 int config_parse_unit_env_file(const char *unit,
1515                                const char *filename,
1516                                unsigned line,
1517                                const char *section,
1518                                unsigned section_line,
1519                                const char *lvalue,
1520                                int ltype,
1521                                const char *rvalue,
1522                                void *data,
1523                                void *userdata) {
1524
1525         char ***env = data;
1526         Unit *u = userdata;
1527         _cleanup_free_ char *n = NULL;
1528         const char *s;
1529         int r;
1530
1531         assert(filename);
1532         assert(lvalue);
1533         assert(rvalue);
1534         assert(data);
1535
1536         if (isempty(rvalue)) {
1537                 /* Empty assignment frees the list */
1538                 strv_free(*env);
1539                 *env = NULL;
1540                 return 0;
1541         }
1542
1543         r = unit_full_printf(u, rvalue, &n);
1544         if (r < 0)
1545                 log_syntax(unit, LOG_ERR, filename, line, r,
1546                            "Failed to resolve specifiers, ignoring: %s", rvalue);
1547
1548         s = n ?: rvalue;
1549         if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1550                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1551                            "Path '%s' is not absolute, ignoring.", s);
1552                 return 0;
1553         }
1554
1555         r = strv_extend(env, s);
1556         if (r < 0)
1557                 return log_oom();
1558
1559         return 0;
1560 }
1561
1562 int config_parse_environ(const char *unit,
1563                          const char *filename,
1564                          unsigned line,
1565                          const char *section,
1566                          unsigned section_line,
1567                          const char *lvalue,
1568                          int ltype,
1569                          const char *rvalue,
1570                          void *data,
1571                          void *userdata) {
1572
1573         Unit *u = userdata;
1574         char*** env = data, *w, *state;
1575         size_t l;
1576         _cleanup_free_ char *k = NULL;
1577         int r;
1578
1579         assert(filename);
1580         assert(lvalue);
1581         assert(rvalue);
1582         assert(data);
1583
1584         if (isempty(rvalue)) {
1585                 /* Empty assignment resets the list */
1586                 strv_free(*env);
1587                 *env = NULL;
1588                 return 0;
1589         }
1590
1591         if (u) {
1592                 r = unit_full_printf(u, rvalue, &k);
1593                 if (r < 0)
1594                         log_syntax(unit, LOG_ERR, filename, line, -r,
1595                                    "Failed to resolve specifiers, ignoring: %s", rvalue);
1596         }
1597
1598         if (!k)
1599                 k = strdup(rvalue);
1600         if (!k)
1601                 return log_oom();
1602
1603         FOREACH_WORD_QUOTED(w, l, k, state) {
1604                 _cleanup_free_ char *n;
1605                 char **x;
1606
1607                 n = cunescape_length(w, l);
1608                 if (!n)
1609                         return log_oom();
1610
1611                 if (!env_assignment_is_valid(n)) {
1612                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1613                                    "Invalid environment assignment, ignoring: %s", rvalue);
1614                         continue;
1615                 }
1616
1617                 x = strv_env_set(*env, n);
1618                 if (!x)
1619                         return log_oom();
1620
1621                 strv_free(*env);
1622                 *env = x;
1623         }
1624
1625         return 0;
1626 }
1627
1628 int config_parse_ip_tos(const char *unit,
1629                         const char *filename,
1630                         unsigned line,
1631                         const char *section,
1632                         unsigned section_line,
1633                         const char *lvalue,
1634                         int ltype,
1635                         const char *rvalue,
1636                         void *data,
1637                         void *userdata) {
1638
1639         int *ip_tos = data, x;
1640
1641         assert(filename);
1642         assert(lvalue);
1643         assert(rvalue);
1644         assert(data);
1645
1646         x = ip_tos_from_string(rvalue);
1647         if (x < 0) {
1648                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1649                            "Failed to parse IP TOS value, ignoring: %s", rvalue);
1650                 return 0;
1651         }
1652
1653         *ip_tos = x;
1654         return 0;
1655 }
1656
1657 int config_parse_unit_condition_path(const char *unit,
1658                                      const char *filename,
1659                                      unsigned line,
1660                                      const char *section,
1661                                      unsigned section_line,
1662                                      const char *lvalue,
1663                                      int ltype,
1664                                      const char *rvalue,
1665                                      void *data,
1666                                      void *userdata) {
1667
1668         ConditionType cond = ltype;
1669         Unit *u = data;
1670         bool trigger, negate;
1671         Condition *c;
1672         _cleanup_free_ char *p = NULL;
1673         int r;
1674
1675         assert(filename);
1676         assert(lvalue);
1677         assert(rvalue);
1678         assert(data);
1679
1680         if (isempty(rvalue)) {
1681                 /* Empty assignment resets the list */
1682                 condition_free_list(u->conditions);
1683                 u->conditions = NULL;
1684                 return 0;
1685         }
1686
1687         trigger = rvalue[0] == '|';
1688         if (trigger)
1689                 rvalue++;
1690
1691         negate = rvalue[0] == '!';
1692         if (negate)
1693                 rvalue++;
1694
1695         r = unit_full_printf(u, rvalue, &p);
1696         if (r < 0)
1697                 log_syntax(unit, LOG_ERR, filename, line, -r,
1698                            "Failed to resolve specifiers, ignoring: %s", rvalue);
1699         if (!p) {
1700                 p = strdup(rvalue);
1701                 if (!p)
1702                         return log_oom();
1703         }
1704
1705         if (!path_is_absolute(p)) {
1706                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1707                            "Path in condition not absolute, ignoring: %s", p);
1708                 return 0;
1709         }
1710
1711         c = condition_new(cond, p, trigger, negate);
1712         if (!c)
1713                 return log_oom();
1714
1715         LIST_PREPEND(conditions, u->conditions, c);
1716         return 0;
1717 }
1718
1719 int config_parse_unit_condition_string(const char *unit,
1720                                        const char *filename,
1721                                        unsigned line,
1722                                        const char *section,
1723                                        unsigned section_line,
1724                                        const char *lvalue,
1725                                        int ltype,
1726                                        const char *rvalue,
1727                                        void *data,
1728                                        void *userdata) {
1729
1730         ConditionType cond = ltype;
1731         Unit *u = data;
1732         bool trigger, negate;
1733         Condition *c;
1734         _cleanup_free_ char *s = NULL;
1735         int r;
1736
1737         assert(filename);
1738         assert(lvalue);
1739         assert(rvalue);
1740         assert(data);
1741
1742         if (isempty(rvalue)) {
1743                 /* Empty assignment resets the list */
1744                 condition_free_list(u->conditions);
1745                 u->conditions = NULL;
1746                 return 0;
1747         }
1748
1749         trigger = rvalue[0] == '|';
1750         if (trigger)
1751                 rvalue++;
1752
1753         negate = rvalue[0] == '!';
1754         if (negate)
1755                 rvalue++;
1756
1757         r = unit_full_printf(u, rvalue, &s);
1758         if (r < 0)
1759                 log_syntax(unit, LOG_ERR, filename, line, -r,
1760                            "Failed to resolve specifiers, ignoring: %s", rvalue);
1761         if (!s) {
1762                 s = strdup(rvalue);
1763                 if (!s)
1764                         return log_oom();
1765         }
1766
1767         c = condition_new(cond, s, trigger, negate);
1768         if (!c)
1769                 return log_oom();
1770
1771         LIST_PREPEND(conditions, u->conditions, c);
1772         return 0;
1773 }
1774
1775 int config_parse_unit_condition_null(const char *unit,
1776                                      const char *filename,
1777                                      unsigned line,
1778                                      const char *section,
1779                                      unsigned section_line,
1780                                      const char *lvalue,
1781                                      int ltype,
1782                                      const char *rvalue,
1783                                      void *data,
1784                                      void *userdata) {
1785
1786         Unit *u = data;
1787         Condition *c;
1788         bool trigger, negate;
1789         int b;
1790
1791         assert(filename);
1792         assert(lvalue);
1793         assert(rvalue);
1794         assert(data);
1795
1796         if (isempty(rvalue)) {
1797                 /* Empty assignment resets the list */
1798                 condition_free_list(u->conditions);
1799                 u->conditions = NULL;
1800                 return 0;
1801         }
1802
1803         trigger = rvalue[0] == '|';
1804         if (trigger)
1805                 rvalue++;
1806
1807         negate = rvalue[0] == '!';
1808         if (negate)
1809                 rvalue++;
1810
1811         b = parse_boolean(rvalue);
1812         if (b < 0) {
1813                 log_syntax(unit, LOG_ERR, filename, line, -b,
1814                            "Failed to parse boolean value in condition, ignoring: %s",
1815                            rvalue);
1816                 return 0;
1817         }
1818
1819         if (!b)
1820                 negate = !negate;
1821
1822         c = condition_new(CONDITION_NULL, NULL, trigger, negate);
1823         if (!c)
1824                 return log_oom();
1825
1826         LIST_PREPEND(conditions, u->conditions, c);
1827         return 0;
1828 }
1829
1830 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
1831 DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
1832
1833 int config_parse_unit_requires_mounts_for(
1834                 const char *unit,
1835                 const char *filename,
1836                 unsigned line,
1837                 const char *section,
1838                 unsigned section_line,
1839                 const char *lvalue,
1840                 int ltype,
1841                 const char *rvalue,
1842                 void *data,
1843                 void *userdata) {
1844
1845         Unit *u = userdata;
1846         char *state;
1847         size_t l;
1848         char *w;
1849
1850         assert(filename);
1851         assert(lvalue);
1852         assert(rvalue);
1853         assert(data);
1854
1855         FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1856                 int r;
1857                 _cleanup_free_ char *n;
1858
1859                 n = strndup(w, l);
1860                 if (!n)
1861                         return log_oom();
1862
1863                 if (!utf8_is_valid(n)) {
1864                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1865                                    "Path is not UTF-8 clean, ignoring assignment: %s", rvalue);
1866                         continue;
1867                 }
1868
1869                 r = unit_require_mounts_for(u, n);
1870                 if (r < 0) {
1871                         log_syntax(unit, LOG_ERR, filename, line, r,
1872                                    "Failed to add required mount for, ignoring: %s", rvalue);
1873                         continue;
1874                 }
1875         }
1876
1877         return 0;
1878 }
1879
1880 int config_parse_documentation(const char *unit,
1881                                const char *filename,
1882                                unsigned line,
1883                                const char *section,
1884                                unsigned section_line,
1885                                const char *lvalue,
1886                                int ltype,
1887                                const char *rvalue,
1888                                void *data,
1889                                void *userdata) {
1890
1891         Unit *u = userdata;
1892         int r;
1893         char **a, **b;
1894
1895         assert(filename);
1896         assert(lvalue);
1897         assert(rvalue);
1898         assert(u);
1899
1900         if (isempty(rvalue)) {
1901                 /* Empty assignment resets the list */
1902                 strv_free(u->documentation);
1903                 u->documentation = NULL;
1904                 return 0;
1905         }
1906
1907         r = config_parse_unit_strv_printf(unit, filename, line, section, section_line, lvalue, ltype,
1908                                           rvalue, data, userdata);
1909         if (r < 0)
1910                 return r;
1911
1912         for (a = b = u->documentation; a && *a; a++) {
1913
1914                 if (is_valid_documentation_url(*a))
1915                         *(b++) = *a;
1916                 else {
1917                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1918                                    "Invalid URL, ignoring: %s", *a);
1919                         free(*a);
1920                 }
1921         }
1922         if (b)
1923                 *b = NULL;
1924
1925         return r;
1926 }
1927
1928 #ifdef HAVE_SECCOMP
1929 int config_parse_syscall_filter(
1930                 const char *unit,
1931                 const char *filename,
1932                 unsigned line,
1933                 const char *section,
1934                 unsigned section_line,
1935                 const char *lvalue,
1936                 int ltype,
1937                 const char *rvalue,
1938                 void *data,
1939                 void *userdata) {
1940
1941         static const char default_syscalls[] =
1942                 "execve\0"
1943                 "exit\0"
1944                 "exit_group\0"
1945                 "rt_sigreturn\0"
1946                 "sigreturn\0";
1947
1948         ExecContext *c = data;
1949         Unit *u = userdata;
1950         bool invert = false;
1951         char *w, *state;
1952         size_t l;
1953         int r;
1954
1955         assert(filename);
1956         assert(lvalue);
1957         assert(rvalue);
1958         assert(u);
1959
1960         if (isempty(rvalue)) {
1961                 /* Empty assignment resets the list */
1962                 set_free(c->syscall_filter);
1963                 c->syscall_filter = NULL;
1964                 c->syscall_whitelist = false;
1965                 return 0;
1966         }
1967
1968         if (rvalue[0] == '~') {
1969                 invert = true;
1970                 rvalue++;
1971         }
1972
1973         if (!c->syscall_filter) {
1974                 c->syscall_filter = set_new(trivial_hash_func, trivial_compare_func);
1975                 if (!c->syscall_filter)
1976                         return log_oom();
1977
1978                 if (invert)
1979                         /* Allow everything but the ones listed */
1980                         c->syscall_whitelist = false;
1981                 else {
1982                         const char *i;
1983
1984                         /* Allow nothing but the ones listed */
1985                         c->syscall_whitelist = true;
1986
1987                         /* Accept default syscalls if we are on a whitelist */
1988                         NULSTR_FOREACH(i, default_syscalls)  {
1989                                 int id;
1990
1991                                 id = seccomp_syscall_resolve_name(i);
1992                                 if (id < 0)
1993                                         continue;
1994
1995                                 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
1996                                 if (r == -EEXIST)
1997                                         continue;
1998                                 if (r < 0)
1999                                         return log_oom();
2000                         }
2001                 }
2002         }
2003
2004         FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2005                 _cleanup_free_ char *t = NULL;
2006                 int id;
2007
2008                 t = strndup(w, l);
2009                 if (!t)
2010                         return log_oom();
2011
2012                 id = seccomp_syscall_resolve_name(t);
2013                 if (id < 0)  {
2014                         log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse system call, ignoring: %s", t);
2015                         continue;
2016                 }
2017
2018                 /* If we previously wanted to forbid a syscall and now
2019                  * we want to allow it, then remove it from the list
2020                  */
2021                 if (!invert == c->syscall_whitelist)  {
2022                         r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2023                         if (r == -EEXIST)
2024                                 continue;
2025                         if (r < 0)
2026                                 return log_oom();
2027                 } else
2028                         set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
2029         }
2030
2031         c->no_new_privileges = true;
2032
2033         return 0;
2034 }
2035
2036 int config_parse_syscall_archs(
2037                 const char *unit,
2038                 const char *filename,
2039                 unsigned line,
2040                 const char *section,
2041                 unsigned section_line,
2042                 const char *lvalue,
2043                 int ltype,
2044                 const char *rvalue,
2045                 void *data,
2046                 void *userdata) {
2047
2048         ExecContext *c = data;
2049         char *w, *state;
2050         size_t l;
2051         int r;
2052
2053         if (isempty(rvalue)) {
2054                 set_free(c->syscall_archs);
2055                 c->syscall_archs = NULL;
2056                 return 0;
2057         }
2058
2059         r = set_ensure_allocated(&c->syscall_archs, trivial_hash_func, trivial_compare_func);
2060         if (r < 0)
2061                 return log_oom();
2062
2063         FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2064                 _cleanup_free_ char *t = NULL;
2065                 uint32_t a;
2066
2067                 t = strndup(w, l);
2068                 if (!t)
2069                         return log_oom();
2070
2071                 r = seccomp_arch_from_string(t, &a);
2072                 if (r < 0) {
2073                         log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse system call architecture, ignoring: %s", t);
2074                         continue;
2075                 }
2076
2077                 r = set_put(c->syscall_archs, UINT32_TO_PTR(a + 1));
2078                 if (r == -EEXIST)
2079                         continue;
2080                 if (r < 0)
2081                         return log_oom();
2082         }
2083
2084         return 0;
2085 }
2086
2087 int config_parse_syscall_errno(
2088                 const char *unit,
2089                 const char *filename,
2090                 unsigned line,
2091                 const char *section,
2092                 unsigned section_line,
2093                 const char *lvalue,
2094                 int ltype,
2095                 const char *rvalue,
2096                 void *data,
2097                 void *userdata) {
2098
2099         ExecContext *c = data;
2100         int e;
2101
2102         assert(filename);
2103         assert(lvalue);
2104         assert(rvalue);
2105
2106         if (isempty(rvalue)) {
2107                 /* Empty assignment resets to KILL */
2108                 c->syscall_errno = 0;
2109                 return 0;
2110         }
2111
2112         e = errno_from_name(rvalue);
2113         if (e < 0) {
2114                 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse error number, ignoring: %s", rvalue);
2115                 return 0;
2116         }
2117
2118         c->syscall_errno = e;
2119         return 0;
2120 }
2121 #endif
2122
2123 int config_parse_unit_slice(
2124                 const char *unit,
2125                 const char *filename,
2126                 unsigned line,
2127                 const char *section,
2128                 unsigned section_line,
2129                 const char *lvalue,
2130                 int ltype,
2131                 const char *rvalue,
2132                 void *data,
2133                 void *userdata) {
2134
2135         _cleanup_free_ char *k = NULL;
2136         Unit *u = userdata, *slice;
2137         int r;
2138
2139         assert(filename);
2140         assert(lvalue);
2141         assert(rvalue);
2142         assert(u);
2143
2144         r = unit_name_printf(u, rvalue, &k);
2145         if (r < 0)
2146                 log_syntax(unit, LOG_ERR, filename, line, -r,
2147                            "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
2148         if (!k) {
2149                 k = strdup(rvalue);
2150                 if (!k)
2151                         return log_oom();
2152         }
2153
2154         r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
2155         if (r < 0) {
2156                 log_syntax(unit, LOG_ERR, filename, line, -r,
2157                            "Failed to load slice unit %s. Ignoring.", k);
2158                 return 0;
2159         }
2160
2161         if (slice->type != UNIT_SLICE) {
2162                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2163                            "Slice unit %s is not a slice. Ignoring.", k);
2164                 return 0;
2165         }
2166
2167         unit_ref_set(&u->slice, slice);
2168         return 0;
2169 }
2170
2171 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
2172
2173 int config_parse_cpu_shares(
2174                 const char *unit,
2175                 const char *filename,
2176                 unsigned line,
2177                 const char *section,
2178                 unsigned section_line,
2179                 const char *lvalue,
2180                 int ltype,
2181                 const char *rvalue,
2182                 void *data,
2183                 void *userdata) {
2184
2185         CGroupContext *c = data;
2186         unsigned long lu;
2187         int r;
2188
2189         assert(filename);
2190         assert(lvalue);
2191         assert(rvalue);
2192
2193         if (isempty(rvalue)) {
2194                 c->cpu_shares = 1024;
2195                 return 0;
2196         }
2197
2198         r = safe_atolu(rvalue, &lu);
2199         if (r < 0 || lu <= 0) {
2200                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2201                            "CPU shares '%s' invalid. Ignoring.", rvalue);
2202                 return 0;
2203         }
2204
2205         c->cpu_shares = lu;
2206         return 0;
2207 }
2208
2209 int config_parse_memory_limit(
2210                 const char *unit,
2211                 const char *filename,
2212                 unsigned line,
2213                 const char *section,
2214                 unsigned section_line,
2215                 const char *lvalue,
2216                 int ltype,
2217                 const char *rvalue,
2218                 void *data,
2219                 void *userdata) {
2220
2221         CGroupContext *c = data;
2222         off_t bytes;
2223         int r;
2224
2225         if (isempty(rvalue)) {
2226                 c->memory_limit = (uint64_t) -1;
2227                 return 0;
2228         }
2229
2230         assert_cc(sizeof(uint64_t) == sizeof(off_t));
2231
2232         r = parse_bytes(rvalue, &bytes);
2233         if (r < 0) {
2234                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2235                            "Memory limit '%s' invalid. Ignoring.", rvalue);
2236                 return 0;
2237         }
2238
2239         c->memory_limit = (uint64_t) bytes;
2240         return 0;
2241 }
2242
2243 int config_parse_device_allow(
2244                 const char *unit,
2245                 const char *filename,
2246                 unsigned line,
2247                 const char *section,
2248                 unsigned section_line,
2249                 const char *lvalue,
2250                 int ltype,
2251                 const char *rvalue,
2252                 void *data,
2253                 void *userdata) {
2254
2255         _cleanup_free_ char *path = NULL;
2256         CGroupContext *c = data;
2257         CGroupDeviceAllow *a;
2258         const char *m;
2259         size_t n;
2260
2261         if (isempty(rvalue)) {
2262                 while (c->device_allow)
2263                         cgroup_context_free_device_allow(c, c->device_allow);
2264
2265                 return 0;
2266         }
2267
2268         n = strcspn(rvalue, WHITESPACE);
2269         path = strndup(rvalue, n);
2270         if (!path)
2271                 return log_oom();
2272
2273         if (!path_startswith(path, "/dev")) {
2274                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2275                            "Invalid device node path '%s'. Ignoring.", path);
2276                 return 0;
2277         }
2278
2279         m = rvalue + n + strspn(rvalue + n, WHITESPACE);
2280         if (isempty(m))
2281                 m = "rwm";
2282
2283         if (!in_charset(m, "rwm")) {
2284                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2285                            "Invalid device rights '%s'. Ignoring.", m);
2286                 return 0;
2287         }
2288
2289         a = new0(CGroupDeviceAllow, 1);
2290         if (!a)
2291                 return log_oom();
2292
2293         a->path = path;
2294         path = NULL;
2295         a->r = !!strchr(m, 'r');
2296         a->w = !!strchr(m, 'w');
2297         a->m = !!strchr(m, 'm');
2298
2299         LIST_PREPEND(device_allow, c->device_allow, a);
2300         return 0;
2301 }
2302
2303 int config_parse_blockio_weight(
2304                 const char *unit,
2305                 const char *filename,
2306                 unsigned line,
2307                 const char *section,
2308                 unsigned section_line,
2309                 const char *lvalue,
2310                 int ltype,
2311                 const char *rvalue,
2312                 void *data,
2313                 void *userdata) {
2314
2315         CGroupContext *c = data;
2316         unsigned long lu;
2317         int r;
2318
2319         assert(filename);
2320         assert(lvalue);
2321         assert(rvalue);
2322
2323         if (isempty(rvalue)) {
2324                 c->blockio_weight = 1000;
2325                 return 0;
2326         }
2327
2328         r = safe_atolu(rvalue, &lu);
2329         if (r < 0 || lu < 10 || lu > 1000) {
2330                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2331                            "Block IO weight '%s' invalid. Ignoring.", rvalue);
2332                 return 0;
2333         }
2334
2335         c->blockio_weight = lu;
2336
2337         return 0;
2338 }
2339
2340 int config_parse_blockio_device_weight(
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         CGroupBlockIODeviceWeight *w;
2354         CGroupContext *c = data;
2355         unsigned long lu;
2356         const char *weight;
2357         size_t n;
2358         int r;
2359
2360         assert(filename);
2361         assert(lvalue);
2362         assert(rvalue);
2363
2364         if (isempty(rvalue)) {
2365                 while (c->blockio_device_weights)
2366                         cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
2367
2368                 return 0;
2369         }
2370
2371         n = strcspn(rvalue, WHITESPACE);
2372         weight = rvalue + n;
2373         if (!*weight) {
2374                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2375                            "Expected block device and device weight. Ignoring.");
2376                 return 0;
2377         }
2378
2379         path = strndup(rvalue, n);
2380         if (!path)
2381                 return log_oom();
2382
2383         if (!path_startswith(path, "/dev")) {
2384                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2385                            "Invalid device node path '%s'. Ignoring.", path);
2386                 return 0;
2387         }
2388
2389         weight += strspn(weight, WHITESPACE);
2390         r = safe_atolu(weight, &lu);
2391         if (r < 0 || lu < 10 || lu > 1000) {
2392                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2393                            "Block IO weight '%s' invalid. Ignoring.", rvalue);
2394                 return 0;
2395         }
2396
2397
2398         w = new0(CGroupBlockIODeviceWeight, 1);
2399         if (!w)
2400                 return log_oom();
2401
2402         w->path = path;
2403         path = NULL;
2404
2405         w->weight = lu;
2406
2407         LIST_PREPEND(device_weights, c->blockio_device_weights, w);
2408         return 0;
2409 }
2410
2411 int config_parse_blockio_bandwidth(
2412                 const char *unit,
2413                 const char *filename,
2414                 unsigned line,
2415                 const char *section,
2416                 unsigned section_line,
2417                 const char *lvalue,
2418                 int ltype,
2419                 const char *rvalue,
2420                 void *data,
2421                 void *userdata) {
2422
2423         _cleanup_free_ char *path = NULL;
2424         CGroupBlockIODeviceBandwidth *b;
2425         CGroupContext *c = data;
2426         const char *bandwidth;
2427         off_t bytes;
2428         bool read;
2429         size_t n;
2430         int r;
2431
2432         assert(filename);
2433         assert(lvalue);
2434         assert(rvalue);
2435
2436         read = streq("BlockIOReadBandwidth", lvalue);
2437
2438         if (isempty(rvalue)) {
2439                 CGroupBlockIODeviceBandwidth *next;
2440
2441                 LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
2442                         if (b->read == read)
2443                                 cgroup_context_free_blockio_device_bandwidth(c, b);
2444
2445                 return 0;
2446         }
2447
2448         n = strcspn(rvalue, WHITESPACE);
2449         bandwidth = rvalue + n;
2450         bandwidth += strspn(bandwidth, WHITESPACE);
2451
2452         if (!*bandwidth) {
2453                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2454                            "Expected space separated pair of device node and bandwidth. Ignoring.");
2455                 return 0;
2456         }
2457
2458         path = strndup(rvalue, n);
2459         if (!path)
2460                 return log_oom();
2461
2462         if (!path_startswith(path, "/dev")) {
2463                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2464                            "Invalid device node path '%s'. Ignoring.", path);
2465                 return 0;
2466         }
2467
2468         r = parse_bytes(bandwidth, &bytes);
2469         if (r < 0 || bytes <= 0) {
2470                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2471                            "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
2472                 return 0;
2473         }
2474
2475         b = new0(CGroupBlockIODeviceBandwidth, 1);
2476         if (!b)
2477                 return log_oom();
2478
2479         b->path = path;
2480         path = NULL;
2481         b->bandwidth = (uint64_t) bytes;
2482         b->read = read;
2483
2484         LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
2485
2486         return 0;
2487 }
2488
2489 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
2490
2491 int config_parse_job_mode_isolate(
2492                 const char *unit,
2493                 const char *filename,
2494                 unsigned line,
2495                 const char *section,
2496                 unsigned section_line,
2497                 const char *lvalue,
2498                 int ltype,
2499                 const char *rvalue,
2500                 void *data,
2501                 void *userdata) {
2502
2503         JobMode *m = data;
2504         int r;
2505
2506         assert(filename);
2507         assert(lvalue);
2508         assert(rvalue);
2509
2510         r = parse_boolean(rvalue);
2511         if (r < 0) {
2512                 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse boolean, ignoring: %s", rvalue);
2513                 return 0;
2514         }
2515
2516         *m = r ? JOB_ISOLATE : JOB_REPLACE;
2517         return 0;
2518 }
2519
2520 #define FOLLOW_MAX 8
2521
2522 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
2523         unsigned c = 0;
2524         int fd, r;
2525         FILE *f;
2526         char *id = NULL;
2527
2528         assert(filename);
2529         assert(*filename);
2530         assert(_f);
2531         assert(names);
2532
2533         /* This will update the filename pointer if the loaded file is
2534          * reached by a symlink. The old string will be freed. */
2535
2536         for (;;) {
2537                 char *target, *name;
2538
2539                 if (c++ >= FOLLOW_MAX)
2540                         return -ELOOP;
2541
2542                 path_kill_slashes(*filename);
2543
2544                 /* Add the file name we are currently looking at to
2545                  * the names of this unit, but only if it is a valid
2546                  * unit name. */
2547                 name = basename(*filename);
2548
2549                 if (unit_name_is_valid(name, TEMPLATE_VALID)) {
2550
2551                         id = set_get(names, name);
2552                         if (!id) {
2553                                 id = strdup(name);
2554                                 if (!id)
2555                                         return -ENOMEM;
2556
2557                                 r = set_consume(names, id);
2558                                 if (r < 0)
2559                                         return r;
2560                         }
2561                 }
2562
2563                 /* Try to open the file name, but don't if its a symlink */
2564                 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
2565                 if (fd >= 0)
2566                         break;
2567
2568                 if (errno != ELOOP)
2569                         return -errno;
2570
2571                 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
2572                 r = readlink_and_make_absolute(*filename, &target);
2573                 if (r < 0)
2574                         return r;
2575
2576                 free(*filename);
2577                 *filename = target;
2578         }
2579
2580         f = fdopen(fd, "re");
2581         if (!f) {
2582                 r = -errno;
2583                 close_nointr_nofail(fd);
2584                 return r;
2585         }
2586
2587         *_f = f;
2588         *_final = id;
2589         return 0;
2590 }
2591
2592 static int merge_by_names(Unit **u, Set *names, const char *id) {
2593         char *k;
2594         int r;
2595
2596         assert(u);
2597         assert(*u);
2598         assert(names);
2599
2600         /* Let's try to add in all symlink names we found */
2601         while ((k = set_steal_first(names))) {
2602
2603                 /* First try to merge in the other name into our
2604                  * unit */
2605                 r = unit_merge_by_name(*u, k);
2606                 if (r < 0) {
2607                         Unit *other;
2608
2609                         /* Hmm, we couldn't merge the other unit into
2610                          * ours? Then let's try it the other way
2611                          * round */
2612
2613                         other = manager_get_unit((*u)->manager, k);
2614                         free(k);
2615
2616                         if (other) {
2617                                 r = unit_merge(other, *u);
2618                                 if (r >= 0) {
2619                                         *u = other;
2620                                         return merge_by_names(u, names, NULL);
2621                                 }
2622                         }
2623
2624                         return r;
2625                 }
2626
2627                 if (id == k)
2628                         unit_choose_id(*u, id);
2629
2630                 free(k);
2631         }
2632
2633         return 0;
2634 }
2635
2636 static int load_from_path(Unit *u, const char *path) {
2637         int r;
2638         _cleanup_set_free_free_ Set *symlink_names = NULL;
2639         _cleanup_fclose_ FILE *f = NULL;
2640         _cleanup_free_ char *filename = NULL;
2641         char *id = NULL;
2642         Unit *merged;
2643         struct stat st;
2644
2645         assert(u);
2646         assert(path);
2647
2648         symlink_names = set_new(string_hash_func, string_compare_func);
2649         if (!symlink_names)
2650                 return -ENOMEM;
2651
2652         if (path_is_absolute(path)) {
2653
2654                 filename = strdup(path);
2655                 if (!filename)
2656                         return -ENOMEM;
2657
2658                 r = open_follow(&filename, &f, symlink_names, &id);
2659                 if (r < 0) {
2660                         free(filename);
2661                         filename = NULL;
2662
2663                         if (r != -ENOENT)
2664                                 return r;
2665                 }
2666
2667         } else  {
2668                 char **p;
2669
2670                 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
2671
2672                         /* Instead of opening the path right away, we manually
2673                          * follow all symlinks and add their name to our unit
2674                          * name set while doing so */
2675                         filename = path_make_absolute(path, *p);
2676                         if (!filename)
2677                                 return -ENOMEM;
2678
2679                         if (u->manager->unit_path_cache &&
2680                             !set_get(u->manager->unit_path_cache, filename))
2681                                 r = -ENOENT;
2682                         else
2683                                 r = open_follow(&filename, &f, symlink_names, &id);
2684
2685                         if (r < 0) {
2686                                 free(filename);
2687                                 filename = NULL;
2688
2689                                 if (r != -ENOENT)
2690                                         return r;
2691
2692                                 /* Empty the symlink names for the next run */
2693                                 set_clear_free(symlink_names);
2694                                 continue;
2695                         }
2696
2697                         break;
2698                 }
2699         }
2700
2701         if (!filename)
2702                 /* Hmm, no suitable file found? */
2703                 return 0;
2704
2705         merged = u;
2706         r = merge_by_names(&merged, symlink_names, id);
2707         if (r < 0)
2708                 return r;
2709
2710         if (merged != u) {
2711                 u->load_state = UNIT_MERGED;
2712                 return 0;
2713         }
2714
2715         if (fstat(fileno(f), &st) < 0)
2716                 return -errno;
2717
2718         if (null_or_empty(&st))
2719                 u->load_state = UNIT_MASKED;
2720         else {
2721                 u->load_state = UNIT_LOADED;
2722
2723                 /* Now, parse the file contents */
2724                 r = config_parse(u->id, filename, f, UNIT_VTABLE(u)->sections,
2725                                  config_item_perf_lookup,
2726                                  (void*) load_fragment_gperf_lookup, false, true, u);
2727                 if (r < 0)
2728                         return r;
2729         }
2730
2731         free(u->fragment_path);
2732         u->fragment_path = filename;
2733         filename = NULL;
2734
2735         u->fragment_mtime = timespec_load(&st.st_mtim);
2736
2737         if (u->source_path) {
2738                 if (stat(u->source_path, &st) >= 0)
2739                         u->source_mtime = timespec_load(&st.st_mtim);
2740                 else
2741                         u->source_mtime = 0;
2742         }
2743
2744         return 0;
2745 }
2746
2747 int unit_load_fragment(Unit *u) {
2748         int r;
2749         Iterator i;
2750         const char *t;
2751
2752         assert(u);
2753         assert(u->load_state == UNIT_STUB);
2754         assert(u->id);
2755
2756         /* First, try to find the unit under its id. We always look
2757          * for unit files in the default directories, to make it easy
2758          * to override things by placing things in /etc/systemd/system */
2759         r = load_from_path(u, u->id);
2760         if (r < 0)
2761                 return r;
2762
2763         /* Try to find an alias we can load this with */
2764         if (u->load_state == UNIT_STUB)
2765                 SET_FOREACH(t, u->names, i) {
2766
2767                         if (t == u->id)
2768                                 continue;
2769
2770                         r = load_from_path(u, t);
2771                         if (r < 0)
2772                                 return r;
2773
2774                         if (u->load_state != UNIT_STUB)
2775                                 break;
2776                 }
2777
2778         /* And now, try looking for it under the suggested (originally linked) path */
2779         if (u->load_state == UNIT_STUB && u->fragment_path) {
2780
2781                 r = load_from_path(u, u->fragment_path);
2782                 if (r < 0)
2783                         return r;
2784
2785                 if (u->load_state == UNIT_STUB) {
2786                         /* Hmm, this didn't work? Then let's get rid
2787                          * of the fragment path stored for us, so that
2788                          * we don't point to an invalid location. */
2789                         free(u->fragment_path);
2790                         u->fragment_path = NULL;
2791                 }
2792         }
2793
2794         /* Look for a template */
2795         if (u->load_state == UNIT_STUB && u->instance) {
2796                 _cleanup_free_ char *k;
2797
2798                 k = unit_name_template(u->id);
2799                 if (!k)
2800                         return -ENOMEM;
2801
2802                 r = load_from_path(u, k);
2803                 if (r < 0)
2804                         return r;
2805
2806                 if (u->load_state == UNIT_STUB)
2807                         SET_FOREACH(t, u->names, i) {
2808                                 _cleanup_free_ char *z = NULL;
2809
2810                                 if (t == u->id)
2811                                         continue;
2812
2813                                 z = unit_name_template(t);
2814                                 if (!z)
2815                                         return -ENOMEM;
2816
2817                                 r = load_from_path(u, z);
2818                                 if (r < 0)
2819                                         return r;
2820
2821                                 if (u->load_state != UNIT_STUB)
2822                                         break;
2823                         }
2824         }
2825
2826         return 0;
2827 }
2828
2829 void unit_dump_config_items(FILE *f) {
2830         static const struct {
2831                 const ConfigParserCallback callback;
2832                 const char *rvalue;
2833         } table[] = {
2834 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP)
2835                 { config_parse_warn_compat,           "NOTSUPPORTED" },
2836 #endif
2837                 { config_parse_int,                   "INTEGER" },
2838                 { config_parse_unsigned,              "UNSIGNED" },
2839                 { config_parse_bytes_size,            "SIZE" },
2840                 { config_parse_bool,                  "BOOLEAN" },
2841                 { config_parse_string,                "STRING" },
2842                 { config_parse_path,                  "PATH" },
2843                 { config_parse_unit_path_printf,      "PATH" },
2844                 { config_parse_strv,                  "STRING [...]" },
2845                 { config_parse_exec_nice,             "NICE" },
2846                 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
2847                 { config_parse_exec_io_class,         "IOCLASS" },
2848                 { config_parse_exec_io_priority,      "IOPRIORITY" },
2849                 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
2850                 { config_parse_exec_cpu_sched_prio,   "CPUSCHEDPRIO" },
2851                 { config_parse_exec_cpu_affinity,     "CPUAFFINITY" },
2852                 { config_parse_mode,                  "MODE" },
2853                 { config_parse_unit_env_file,         "FILE" },
2854                 { config_parse_output,                "OUTPUT" },
2855                 { config_parse_input,                 "INPUT" },
2856                 { config_parse_facility,              "FACILITY" },
2857                 { config_parse_level,                 "LEVEL" },
2858                 { config_parse_exec_capabilities,     "CAPABILITIES" },
2859                 { config_parse_exec_secure_bits,      "SECUREBITS" },
2860                 { config_parse_bounding_set,          "BOUNDINGSET" },
2861                 { config_parse_limit,                 "LIMIT" },
2862                 { config_parse_unit_deps,             "UNIT [...]" },
2863                 { config_parse_exec,                  "PATH [ARGUMENT [...]]" },
2864                 { config_parse_service_type,          "SERVICETYPE" },
2865                 { config_parse_service_restart,       "SERVICERESTART" },
2866 #ifdef HAVE_SYSV_COMPAT
2867                 { config_parse_sysv_priority,         "SYSVPRIORITY" },
2868 #endif
2869                 { config_parse_kill_mode,             "KILLMODE" },
2870                 { config_parse_kill_signal,           "SIGNAL" },
2871                 { config_parse_socket_listen,         "SOCKET [...]" },
2872                 { config_parse_socket_bind,           "SOCKETBIND" },
2873                 { config_parse_socket_bindtodevice,   "NETWORKINTERFACE" },
2874                 { config_parse_sec,                   "SECONDS" },
2875                 { config_parse_nsec,                  "NANOSECONDS" },
2876                 { config_parse_path_strv,             "PATH [...]" },
2877                 { config_parse_unit_requires_mounts_for, "PATH [...]" },
2878                 { config_parse_exec_mount_flags,      "MOUNTFLAG [...]" },
2879                 { config_parse_unit_string_printf,    "STRING" },
2880                 { config_parse_trigger_unit,          "UNIT" },
2881                 { config_parse_timer,                 "TIMER" },
2882                 { config_parse_path_spec,             "PATH" },
2883                 { config_parse_notify_access,         "ACCESS" },
2884                 { config_parse_ip_tos,                "TOS" },
2885                 { config_parse_unit_condition_path,   "CONDITION" },
2886                 { config_parse_unit_condition_string, "CONDITION" },
2887                 { config_parse_unit_condition_null,   "CONDITION" },
2888                 { config_parse_unit_slice,            "SLICE" },
2889                 { config_parse_documentation,         "URL" },
2890                 { config_parse_service_timeout,       "SECONDS" },
2891                 { config_parse_start_limit_action,    "ACTION" },
2892                 { config_parse_set_status,            "STATUS" },
2893                 { config_parse_service_sockets,       "SOCKETS" },
2894                 { config_parse_environ,               "ENVIRON" },
2895 #ifdef HAVE_SECCOMP
2896                 { config_parse_syscall_filter,        "SYSCALLS" },
2897                 { config_parse_syscall_errno,         "ERRNO" },
2898 #endif
2899                 { config_parse_cpu_shares,            "SHARES" },
2900                 { config_parse_memory_limit,          "LIMIT" },
2901                 { config_parse_device_allow,          "DEVICE" },
2902                 { config_parse_device_policy,         "POLICY" },
2903                 { config_parse_blockio_bandwidth,     "BANDWIDTH" },
2904                 { config_parse_blockio_weight,        "WEIGHT" },
2905                 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
2906                 { config_parse_long,                  "LONG" },
2907                 { config_parse_socket_service,        "SERVICE" },
2908         };
2909
2910         const char *prev = NULL;
2911         const char *i;
2912
2913         assert(f);
2914
2915         NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
2916                 const char *rvalue = "OTHER", *lvalue;
2917                 unsigned j;
2918                 size_t prefix_len;
2919                 const char *dot;
2920                 const ConfigPerfItem *p;
2921
2922                 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
2923
2924                 dot = strchr(i, '.');
2925                 lvalue = dot ? dot + 1 : i;
2926                 prefix_len = dot-i;
2927
2928                 if (dot)
2929                         if (!prev || !strneq(prev, i, prefix_len+1)) {
2930                                 if (prev)
2931                                         fputc('\n', f);
2932
2933                                 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
2934                         }
2935
2936                 for (j = 0; j < ELEMENTSOF(table); j++)
2937                         if (p->parse == table[j].callback) {
2938                                 rvalue = table[j].rvalue;
2939                                 break;
2940                         }
2941
2942                 fprintf(f, "%s=%s\n", lvalue, rvalue);
2943                 prev = i;
2944         }
2945 }