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