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