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