chiark / gitweb /
0571d517b0113572ba4167eecd1a0d4b5e04020f
[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 #include <systemd/sd-messages.h>
38
39 #include "unit.h"
40 #include "strv.h"
41 #include "conf-parser.h"
42 #include "load-fragment.h"
43 #include "log.h"
44 #include "ioprio.h"
45 #include "securebits.h"
46 #include "missing.h"
47 #include "unit-name.h"
48 #include "unit-printf.h"
49 #include "dbus-common.h"
50 #include "utf8.h"
51 #include "path-util.h"
52 #include "syscall-list.h"
53 #include "env-util.h"
54
55 #ifndef HAVE_SYSV_COMPAT
56 int config_parse_warn_compat(const char *unit,
57                              const char *filename,
58                              unsigned line,
59                              const char *section,
60                              const char *lvalue,
61                              int ltype,
62                              const char *rvalue,
63                              void *data,
64                              void *userdata) {
65
66         log_syntax(unit, LOG_DEBUG, filename, line, EINVAL,
67                    "Support for option %s= has been disabled at compile time and is ignored",
68                    lvalue);
69         return 0;
70 }
71 #endif
72
73 int config_parse_unit_deps(const char* unit,
74                            const char *filename,
75                            unsigned line,
76                            const char *section,
77                            const char *lvalue,
78                            int ltype,
79                            const char *rvalue,
80                            void *data,
81                            void *userdata) {
82
83         UnitDependency d = ltype;
84         Unit *u = userdata;
85         char *w;
86         size_t l;
87         char *state;
88
89         assert(filename);
90         assert(lvalue);
91         assert(rvalue);
92
93         FOREACH_WORD_QUOTED(w, l, rvalue, state) {
94                 _cleanup_free_ char *t = NULL, *k = NULL;
95                 int r;
96
97                 t = strndup(w, l);
98                 if (!t)
99                         return log_oom();
100
101                 k = unit_name_printf(u, t);
102                 if (!k)
103                         return log_oom();
104
105                 r = unit_add_dependency_by_name(u, d, k, NULL, true);
106                 if (r < 0)
107                         log_syntax(unit, LOG_ERR, filename, line, -r,
108                                    "Failed to add dependency on %s, ignoring: %s", k, strerror(-r));
109         }
110
111         return 0;
112 }
113
114 int config_parse_unit_string_printf(const char *unit,
115                                     const char *filename,
116                                     unsigned line,
117                                     const char *section,
118                                     const char *lvalue,
119                                     int ltype,
120                                     const char *rvalue,
121                                     void *data,
122                                     void *userdata) {
123
124         Unit *u = userdata;
125         _cleanup_free_ char *k = NULL;
126
127         assert(filename);
128         assert(lvalue);
129         assert(rvalue);
130         assert(u);
131
132         k = unit_full_printf(u, rvalue);
133         if (!k)
134                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
135                            "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
136
137         return config_parse_string(unit, filename, line, section, lvalue, ltype,
138                                    k ? k : rvalue, data, userdata);
139 }
140
141 int config_parse_unit_strv_printf(const char *unit,
142                                   const char *filename,
143                                   unsigned line,
144                                   const char *section,
145                                   const char *lvalue,
146                                   int ltype,
147                                   const char *rvalue,
148                                   void *data,
149                                   void *userdata) {
150
151         Unit *u = userdata;
152         _cleanup_free_ char *k = NULL;
153
154         assert(filename);
155         assert(lvalue);
156         assert(rvalue);
157         assert(u);
158
159         k = unit_full_printf(u, rvalue);
160         if (!k)
161                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
162                            "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
163
164         return config_parse_strv(unit, filename, line, section, lvalue, ltype,
165                                  k ? k : rvalue, data, userdata);
166 }
167
168 int config_parse_unit_path_printf(const char *unit,
169                                   const char *filename,
170                                   unsigned line,
171                                   const char *section,
172                                   const char *lvalue,
173                                   int ltype,
174                                   const char *rvalue,
175                                   void *data,
176                                   void *userdata) {
177
178         Unit *u = userdata;
179         _cleanup_free_ char *k = NULL;
180
181         assert(filename);
182         assert(lvalue);
183         assert(rvalue);
184         assert(u);
185
186         k = unit_full_printf(u, rvalue);
187         if (!k)
188                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
189                            "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
190
191         return config_parse_path(unit, filename, line, section, lvalue, ltype,
192                                  k ? k : rvalue, data, userdata);
193 }
194
195 int config_parse_socket_listen(const char *unit,
196                                const char *filename,
197                                unsigned line,
198                                const char *section,
199                                const char *lvalue,
200                                int ltype,
201                                const char *rvalue,
202                                void *data,
203                                void *userdata) {
204
205         SocketPort *p, *tail;
206         Socket *s;
207
208         assert(filename);
209         assert(lvalue);
210         assert(rvalue);
211         assert(data);
212
213         s = SOCKET(data);
214
215         if (isempty(rvalue)) {
216                 /* An empty assignment removes all ports */
217                 socket_free_ports(s);
218                 return 0;
219         }
220
221         p = new0(SocketPort, 1);
222         if (!p)
223                 return log_oom();
224
225         if (ltype != SOCKET_SOCKET) {
226
227                 p->type = ltype;
228                 p->path = unit_full_printf(UNIT(s), rvalue);
229                 if (!p->path) {
230                         p->path = strdup(rvalue);
231                         if (!p->path) {
232                                 free(p);
233                                 return log_oom();
234                         } else
235                                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
236                                            "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
237                 }
238
239                 path_kill_slashes(p->path);
240
241         } else if (streq(lvalue, "ListenNetlink")) {
242                 _cleanup_free_ char  *k = NULL;
243                 int r;
244
245                 p->type = SOCKET_SOCKET;
246                 k = unit_full_printf(UNIT(s), rvalue);
247                 if (!k)
248                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
249                                    "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
250
251                 r = socket_address_parse_netlink(&p->address, k ? k : rvalue);
252                 if (r < 0) {
253                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
254                                    "Failed to parse address value, ignoring: %s", rvalue);
255                         free(p);
256                         return 0;
257                 }
258
259         } else {
260                 _cleanup_free_ char *k = NULL;
261                 int r;
262
263                 p->type = SOCKET_SOCKET;
264                 k = unit_full_printf(UNIT(s), rvalue);
265                 if (!k)
266                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
267                                    "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
268
269                 r = socket_address_parse(&p->address, k ? k : rvalue);
270                 if (r < 0) {
271                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
272                                    "Failed to parse address value, ignoring: %s", rvalue);
273                         free(p);
274                         return 0;
275                 }
276
277                 if (streq(lvalue, "ListenStream"))
278                         p->address.type = SOCK_STREAM;
279                 else if (streq(lvalue, "ListenDatagram"))
280                         p->address.type = SOCK_DGRAM;
281                 else {
282                         assert(streq(lvalue, "ListenSequentialPacket"));
283                         p->address.type = SOCK_SEQPACKET;
284                 }
285
286                 if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
287                         log_syntax(unit, LOG_ERR, filename, line, ENOTSUP,
288                                    "Address family not supported, ignoring: %s", rvalue);
289                         free(p);
290                         return 0;
291                 }
292         }
293
294         p->fd = -1;
295
296         if (s->ports) {
297                 LIST_FIND_TAIL(SocketPort, port, s->ports, tail);
298                 LIST_INSERT_AFTER(SocketPort, port, s->ports, tail, p);
299         } else
300                 LIST_PREPEND(SocketPort, port, s->ports, p);
301
302         return 0;
303 }
304
305 int config_parse_socket_bind(const char *unit,
306                              const char *filename,
307                              unsigned line,
308                              const char *section,
309                              const char *lvalue,
310                              int ltype,
311                              const char *rvalue,
312                              void *data,
313                              void *userdata) {
314
315         Socket *s;
316         SocketAddressBindIPv6Only b;
317
318         assert(filename);
319         assert(lvalue);
320         assert(rvalue);
321         assert(data);
322
323         s = SOCKET(data);
324
325         b = socket_address_bind_ipv6_only_from_string(rvalue);
326         if (b < 0) {
327                 int r;
328
329                 r = parse_boolean(rvalue);
330                 if (r < 0) {
331                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
332                                    "Failed to parse bind IPv6 only value, ignoring: %s", rvalue);
333                         return 0;
334                 }
335
336                 s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
337         } else
338                 s->bind_ipv6_only = b;
339
340         return 0;
341 }
342
343 int config_parse_exec_nice(const char *unit,
344                            const char *filename,
345                            unsigned line,
346                            const char *section,
347                            const char *lvalue,
348                            int ltype,
349                            const char *rvalue,
350                            void *data,
351                            void *userdata) {
352
353         ExecContext *c = data;
354         int priority, r;
355
356         assert(filename);
357         assert(lvalue);
358         assert(rvalue);
359         assert(data);
360
361         r = safe_atoi(rvalue, &priority);
362         if (r < 0) {
363                 log_syntax(unit, LOG_ERR, filename, line, -r,
364                            "Failed to parse nice priority, ignoring: %s. ", rvalue);
365                 return 0;
366         }
367
368         if (priority < PRIO_MIN || priority >= PRIO_MAX) {
369                 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
370                            "Nice priority out of range, ignoring: %s", rvalue);
371                 return 0;
372         }
373
374         c->nice = priority;
375         c->nice_set = true;
376
377         return 0;
378 }
379
380 int config_parse_exec_oom_score_adjust(const char* unit,
381                                        const char *filename,
382                                        unsigned line,
383                                        const char *section,
384                                        const char *lvalue,
385                                        int ltype,
386                                        const char *rvalue,
387                                        void *data,
388                                        void *userdata) {
389
390         ExecContext *c = data;
391         int oa, r;
392
393         assert(filename);
394         assert(lvalue);
395         assert(rvalue);
396         assert(data);
397
398         r = safe_atoi(rvalue, &oa);
399         if (r < 0) {
400                 log_syntax(unit, LOG_ERR, filename, line, -r,
401                            "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
402                 return 0;
403         }
404
405         if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
406                 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
407                            "OOM score adjust value out of range, ignoring: %s", rvalue);
408                 return 0;
409         }
410
411         c->oom_score_adjust = oa;
412         c->oom_score_adjust_set = true;
413
414         return 0;
415 }
416
417 int config_parse_exec(const char *unit,
418                       const char *filename,
419                       unsigned line,
420                       const char *section,
421                       const char *lvalue,
422                       int ltype,
423                       const char *rvalue,
424                       void *data,
425                       void *userdata) {
426
427         ExecCommand **e = data, *nce;
428         char *path, **n;
429         unsigned k;
430         int r;
431
432         assert(filename);
433         assert(lvalue);
434         assert(rvalue);
435         assert(e);
436
437         e += ltype;
438
439         if (isempty(rvalue)) {
440                 /* An empty assignment resets the list */
441                 exec_command_free_list(*e);
442                 *e = NULL;
443                 return 0;
444         }
445
446         /* We accept an absolute path as first argument, or
447          * alternatively an absolute prefixed with @ to allow
448          * overriding of argv[0]. */
449         for (;;) {
450                 int i;
451                 char *w;
452                 size_t l;
453                 char *state;
454                 bool honour_argv0 = false, ignore = false;
455
456                 path = NULL;
457                 nce = NULL;
458                 n = NULL;
459
460                 rvalue += strspn(rvalue, WHITESPACE);
461
462                 if (rvalue[0] == 0)
463                         break;
464
465                 for (i = 0; i < 2; i++) {
466                         if (rvalue[0] == '-' && !ignore) {
467                                 ignore = true;
468                                 rvalue ++;
469                         }
470
471                         if (rvalue[0] == '@' && !honour_argv0) {
472                                 honour_argv0 = true;
473                                 rvalue ++;
474                         }
475                 }
476
477                 if (*rvalue != '/') {
478                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
479                                    "Executable path is not absolute, ignoring: %s", rvalue);
480                         return 0;
481                 }
482
483                 k = 0;
484                 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
485                         if (strneq(w, ";", MAX(l, 1U)))
486                                 break;
487
488                         k++;
489                 }
490
491                 n = new(char*, k + !honour_argv0);
492                 if (!n)
493                         return log_oom();
494
495                 k = 0;
496                 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
497                         if (strneq(w, ";", MAX(l, 1U)))
498                                 break;
499                         else if (strneq(w, "\\;", MAX(l, 1U)))
500                                 w ++;
501
502                         if (honour_argv0 && w == rvalue) {
503                                 assert(!path);
504
505                                 path = strndup(w, l);
506                                 if (!path) {
507                                         r = log_oom();
508                                         goto fail;
509                                 }
510
511                                 if (!utf8_is_valid(path)) {
512                                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
513                                                    "Path is not UTF-8 clean, ignoring assignment: %s",
514                                                    rvalue);
515                                         r = 0;
516                                         goto fail;
517                                 }
518
519                         } else {
520                                 char *c;
521
522                                 c = n[k++] = cunescape_length(w, l);
523                                 if (!c) {
524                                         r = log_oom();
525                                         goto fail;
526                                 }
527
528                                 if (!utf8_is_valid(c)) {
529                                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
530                                                    "Path is not UTF-8 clean, ignoring assignment: %s",
531                                                    rvalue);
532                                         r = 0;
533                                         goto fail;
534                                 }
535                         }
536                 }
537
538                 n[k] = NULL;
539
540                 if (!n[0]) {
541                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
542                                    "Invalid command line, ignoring: %s", rvalue);
543                         r = 0;
544                         goto fail;
545                 }
546
547                 if (!path) {
548                         path = strdup(n[0]);
549                         if (!path) {
550                                 r = log_oom();
551                                 goto fail;
552                         }
553                 }
554
555                 assert(path_is_absolute(path));
556
557                 nce = new0(ExecCommand, 1);
558                 if (!nce) {
559                         r = log_oom();
560                         goto fail;
561                 }
562
563                 nce->argv = n;
564                 nce->path = path;
565                 nce->ignore = ignore;
566
567                 path_kill_slashes(nce->path);
568
569                 exec_command_append_list(e, nce);
570
571                 rvalue = state;
572         }
573
574         return 0;
575
576 fail:
577         n[k] = NULL;
578         strv_free(n);
579         free(path);
580         free(nce);
581
582         return r;
583 }
584
585 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
586 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
587
588 int config_parse_socket_bindtodevice(const char* unit,
589                                      const char *filename,
590                                      unsigned line,
591                                      const char *section,
592                                      const char *lvalue,
593                                      int ltype,
594                                      const char *rvalue,
595                                      void *data,
596                                      void *userdata) {
597
598         Socket *s = data;
599         char *n;
600
601         assert(filename);
602         assert(lvalue);
603         assert(rvalue);
604         assert(data);
605
606         if (rvalue[0] && !streq(rvalue, "*")) {
607                 n = strdup(rvalue);
608                 if (!n)
609                         return log_oom();
610         } else
611                 n = NULL;
612
613         free(s->bind_to_device);
614         s->bind_to_device = n;
615
616         return 0;
617 }
618
619 DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
620 DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
621
622 int config_parse_exec_io_class(const char *unit,
623                                const char *filename,
624                                unsigned line,
625                                const char *section,
626                                const char *lvalue,
627                                int ltype,
628                                const char *rvalue,
629                                void *data,
630                                void *userdata) {
631
632         ExecContext *c = data;
633         int x;
634
635         assert(filename);
636         assert(lvalue);
637         assert(rvalue);
638         assert(data);
639
640         x = ioprio_class_from_string(rvalue);
641         if (x < 0) {
642                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
643                            "Failed to parse IO scheduling class, ignoring: %s", rvalue);
644                 return 0;
645         }
646
647         c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
648         c->ioprio_set = true;
649
650         return 0;
651 }
652
653 int config_parse_exec_io_priority(const char *unit,
654                                   const char *filename,
655                                   unsigned line,
656                                   const char *section,
657                                   const char *lvalue,
658                                   int ltype,
659                                   const char *rvalue,
660                                   void *data,
661                                   void *userdata) {
662
663         ExecContext *c = data;
664         int i, r;
665
666         assert(filename);
667         assert(lvalue);
668         assert(rvalue);
669         assert(data);
670
671         r = safe_atoi(rvalue, &i);
672         if (r < 0 || i < 0 || i >= IOPRIO_BE_NR) {
673                 log_syntax(unit, LOG_ERR, filename, line, -r,
674                            "Failed to parse IO priority, ignoring: %s", rvalue);
675                 return 0;
676         }
677
678         c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
679         c->ioprio_set = true;
680
681         return 0;
682 }
683
684 int config_parse_exec_cpu_sched_policy(const char *unit,
685                                        const char *filename,
686                                        unsigned line,
687                                        const char *section,
688                                        const char *lvalue,
689                                        int ltype,
690                                        const char *rvalue,
691                                        void *data,
692                                        void *userdata) {
693
694
695         ExecContext *c = data;
696         int x;
697
698         assert(filename);
699         assert(lvalue);
700         assert(rvalue);
701         assert(data);
702
703         x = sched_policy_from_string(rvalue);
704         if (x < 0) {
705                 log_syntax(unit, LOG_ERR, filename, line, -x,
706                            "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
707                 return 0;
708         }
709
710         c->cpu_sched_policy = x;
711         /* Moving to or from real-time policy? We need to adjust the priority */
712         c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x));
713         c->cpu_sched_set = true;
714
715         return 0;
716 }
717
718 int config_parse_exec_cpu_sched_prio(const char *unit,
719                                      const char *filename,
720                                      unsigned line,
721                                      const char *section,
722                                      const char *lvalue,
723                                      int ltype,
724                                      const char *rvalue,
725                                      void *data,
726                                      void *userdata) {
727
728         ExecContext *c = data;
729         int i, min, max, r;
730
731         assert(filename);
732         assert(lvalue);
733         assert(rvalue);
734         assert(data);
735
736         r = safe_atoi(rvalue, &i);
737         if (r < 0) {
738                 log_syntax(unit, LOG_ERR, filename, line, -r,
739                            "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
740                 return 0;
741         }
742
743         /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
744         min = sched_get_priority_min(c->cpu_sched_policy);
745         max = sched_get_priority_max(c->cpu_sched_policy);
746
747         if (i < min || i > max) {
748                 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
749                            "CPU scheduling priority is out of range, ignoring: %s", rvalue);
750                 return 0;
751         }
752
753         c->cpu_sched_priority = i;
754         c->cpu_sched_set = true;
755
756         return 0;
757 }
758
759 int config_parse_exec_cpu_affinity(const char *unit,
760                                    const char *filename,
761                                    unsigned line,
762                                    const char *section,
763                                    const char *lvalue,
764                                    int ltype,
765                                    const char *rvalue,
766                                    void *data,
767                                    void *userdata) {
768
769         ExecContext *c = data;
770         char *w;
771         size_t l;
772         char *state;
773
774         assert(filename);
775         assert(lvalue);
776         assert(rvalue);
777         assert(data);
778
779         if (isempty(rvalue)) {
780                 /* An empty assignment resets the CPU list */
781                 if (c->cpuset)
782                         CPU_FREE(c->cpuset);
783                 c->cpuset = NULL;
784                 return 0;
785         }
786
787         FOREACH_WORD_QUOTED(w, l, rvalue, state) {
788                 _cleanup_free_ char *t = NULL;
789                 int r;
790                 unsigned cpu;
791
792                 t = strndup(w, l);
793                 if (!t)
794                         return log_oom();
795
796                 r = safe_atou(t, &cpu);
797
798                 if (!c->cpuset) {
799                         c->cpuset = cpu_set_malloc(&c->cpuset_ncpus);
800                         if (!c->cpuset)
801                                 return log_oom();
802                 }
803
804                 if (r < 0 || cpu >= c->cpuset_ncpus) {
805                         log_syntax(unit, LOG_ERR, filename, line, ERANGE,
806                                    "Failed to parse CPU affinity '%s', ignoring: %s", t, rvalue);
807                         return 0;
808                 }
809
810                 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
811         }
812
813         return 0;
814 }
815
816 int config_parse_exec_capabilities(const char *unit,
817                                    const char *filename,
818                                    unsigned line,
819                                    const char *section,
820                                    const char *lvalue,
821                                    int ltype,
822                                    const char *rvalue,
823                                    void *data,
824                                    void *userdata) {
825
826         ExecContext *c = data;
827         cap_t cap;
828
829         assert(filename);
830         assert(lvalue);
831         assert(rvalue);
832         assert(data);
833
834         cap = cap_from_text(rvalue);
835         if (!cap) {
836                 log_syntax(unit, LOG_ERR, filename, line, errno,
837                            "Failed to parse capabilities, ignoring: %s", rvalue);
838                 return 0;
839         }
840
841         if (c->capabilities)
842                 cap_free(c->capabilities);
843         c->capabilities = cap;
844
845         return 0;
846 }
847
848 int config_parse_exec_secure_bits(const char *unit,
849                                   const char *filename,
850                                   unsigned line,
851                                   const char *section,
852                                   const char *lvalue,
853                                   int ltype,
854                                   const char *rvalue,
855                                   void *data,
856                                   void *userdata) {
857
858         ExecContext *c = data;
859         char *w;
860         size_t l;
861         char *state;
862
863         assert(filename);
864         assert(lvalue);
865         assert(rvalue);
866         assert(data);
867
868         if (isempty(rvalue)) {
869                 /* An empty assignment resets the field */
870                 c->secure_bits = 0;
871                 return 0;
872         }
873
874         FOREACH_WORD_QUOTED(w, l, rvalue, state) {
875                 if (first_word(w, "keep-caps"))
876                         c->secure_bits |= 1<<SECURE_KEEP_CAPS;
877                 else if (first_word(w, "keep-caps-locked"))
878                         c->secure_bits |= 1<<SECURE_KEEP_CAPS_LOCKED;
879                 else if (first_word(w, "no-setuid-fixup"))
880                         c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP;
881                 else if (first_word(w, "no-setuid-fixup-locked"))
882                         c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP_LOCKED;
883                 else if (first_word(w, "noroot"))
884                         c->secure_bits |= 1<<SECURE_NOROOT;
885                 else if (first_word(w, "noroot-locked"))
886                         c->secure_bits |= 1<<SECURE_NOROOT_LOCKED;
887                 else {
888                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
889                                    "Failed to parse secure bits, ignoring: %s", rvalue);
890                         return 0;
891                 }
892         }
893
894         return 0;
895 }
896
897 int config_parse_bounding_set(const char *unit,
898                               const char *filename,
899                               unsigned line,
900                               const char *section,
901                               const char *lvalue,
902                               int ltype,
903                               const char *rvalue,
904                               void *data,
905                               void *userdata) {
906
907         uint64_t *capability_bounding_set_drop = data;
908         char *w;
909         size_t l;
910         char *state;
911         bool invert = false;
912         uint64_t sum = 0;
913
914         assert(filename);
915         assert(lvalue);
916         assert(rvalue);
917         assert(data);
918
919         if (rvalue[0] == '~') {
920                 invert = true;
921                 rvalue++;
922         }
923
924         /* Note that we store this inverted internally, since the
925          * kernel wants it like this. But we actually expose it
926          * non-inverted everywhere to have a fully normalized
927          * interface. */
928
929         FOREACH_WORD_QUOTED(w, l, rvalue, state) {
930                 _cleanup_free_ char *t = NULL;
931                 int r;
932                 cap_value_t cap;
933
934                 t = strndup(w, l);
935                 if (!t)
936                         return log_oom();
937
938                 r = cap_from_name(t, &cap);
939                 if (r < 0) {
940                         log_syntax(unit, LOG_ERR, filename, line, errno,
941                                    "Failed to parse capability in bounding set, ignoring: %s", t);
942                         continue;
943                 }
944
945                 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
946         }
947
948         if (invert)
949                 *capability_bounding_set_drop |= sum;
950         else
951                 *capability_bounding_set_drop |= ~sum;
952
953         return 0;
954 }
955
956 int config_parse_limit(const char *unit,
957                        const char *filename,
958                        unsigned line,
959                        const char *section,
960                        const char *lvalue,
961                        int ltype,
962                        const char *rvalue,
963                        void *data,
964                        void *userdata) {
965
966         struct rlimit **rl = data;
967         unsigned long long u;
968
969         assert(filename);
970         assert(lvalue);
971         assert(rvalue);
972         assert(data);
973
974         rl += ltype;
975
976         if (streq(rvalue, "infinity"))
977                 u = (unsigned long long) RLIM_INFINITY;
978         else {
979                 int r;
980
981                 r = safe_atollu(rvalue, &u);
982                 if (r < 0) {
983                         log_syntax(unit, LOG_ERR, filename, line, -r,
984                                    "Failed to parse resource value, ignoring: %s", rvalue);
985                         return 0;
986                 }
987         }
988
989         if (!*rl) {
990                 *rl = new(struct rlimit, 1);
991                 if (!*rl)
992                         return log_oom();
993         }
994
995         (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
996         return 0;
997 }
998
999 int config_parse_unit_cgroup(const char *unit,
1000                              const char *filename,
1001                              unsigned line,
1002                              const char *section,
1003                              const char *lvalue,
1004                              int ltype,
1005                              const char *rvalue,
1006                              void *data,
1007                              void *userdata) {
1008
1009         Unit *u = userdata;
1010         char *w;
1011         size_t l;
1012         char *state;
1013
1014         if (isempty(rvalue)) {
1015                 /* An empty assignment resets the list */
1016                 cgroup_bonding_free_list(u->cgroup_bondings, false);
1017                 u->cgroup_bondings = NULL;
1018                 return 0;
1019         }
1020
1021         FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1022                 _cleanup_free_ char *t = NULL, *k = NULL, *ku = NULL;
1023                 int r;
1024
1025                 t = strndup(w, l);
1026                 if (!t)
1027                         return log_oom();
1028
1029                 k = unit_full_printf(u, t);
1030                 if (!k)
1031                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1032                                    "Failed to resolve unit specifiers on %s. Ignoring.",
1033                                    t);
1034
1035                 ku = cunescape(k ? k : t);
1036                 if (!ku)
1037                         return log_oom();
1038
1039                 r = unit_add_cgroup_from_text(u, ku, true, NULL);
1040                 if (r < 0) {
1041                         log_syntax(unit, LOG_ERR, filename, line, -r,
1042                                    "Failed to parse cgroup value %s, ignoring: %s",
1043                                    k, rvalue);
1044                         return 0;
1045                 }
1046         }
1047
1048         return 0;
1049 }
1050
1051 #ifdef HAVE_SYSV_COMPAT
1052 int config_parse_sysv_priority(const char *unit,
1053                                const char *filename,
1054                                unsigned line,
1055                                const char *section,
1056                                const char *lvalue,
1057                                int ltype,
1058                                const char *rvalue,
1059                                void *data,
1060                                void *userdata) {
1061
1062         int *priority = data;
1063         int i, r;
1064
1065         assert(filename);
1066         assert(lvalue);
1067         assert(rvalue);
1068         assert(data);
1069
1070         r = safe_atoi(rvalue, &i);
1071         if (r < 0 || i < 0) {
1072                 log_syntax(unit, LOG_ERR, filename, line, -r,
1073                            "Failed to parse SysV start priority, ignoring: %s", rvalue);
1074                 return 0;
1075         }
1076
1077         *priority = (int) i;
1078         return 0;
1079 }
1080 #endif
1081
1082 int config_parse_fsck_passno(const char *unit,
1083                              const char *filename,
1084                              unsigned line,
1085                              const char *section,
1086                              const char *lvalue,
1087                              int ltype,
1088                              const char *rvalue,
1089                              void *data,
1090                              void *userdata) {
1091
1092         int *passno = data;
1093         int i, r;
1094
1095         assert(filename);
1096         assert(lvalue);
1097         assert(rvalue);
1098         assert(data);
1099
1100         r = safe_atoi(rvalue, &i);
1101         if (r || i < 0) {
1102                 log_syntax(unit, LOG_ERR, filename, line, -r,
1103                            "Failed to parse fsck pass number, ignoring: %s", rvalue);
1104                 return 0;
1105         }
1106
1107         *passno = (int) i;
1108         return 0;
1109 }
1110
1111 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
1112
1113 int config_parse_kill_signal(const char *unit,
1114                              const char *filename,
1115                              unsigned line,
1116                              const char *section,
1117                              const char *lvalue,
1118                              int ltype,
1119                              const char *rvalue,
1120                              void *data,
1121                              void *userdata) {
1122
1123         int *sig = data;
1124         int r;
1125
1126         assert(filename);
1127         assert(lvalue);
1128         assert(rvalue);
1129         assert(sig);
1130
1131         r = signal_from_string_try_harder(rvalue);
1132         if (r <= 0) {
1133                 log_syntax(unit, LOG_ERR, filename, line, -r,
1134                            "Failed to parse kill signal, ignoring: %s", rvalue);
1135                 return 0;
1136         }
1137
1138         *sig = r;
1139         return 0;
1140 }
1141
1142 int config_parse_exec_mount_flags(const char *unit,
1143                                   const char *filename,
1144                                   unsigned line,
1145                                   const char *section,
1146                                   const char *lvalue,
1147                                   int ltype,
1148                                   const char *rvalue,
1149                                   void *data,
1150                                   void *userdata) {
1151
1152         ExecContext *c = data;
1153         char *w;
1154         size_t l;
1155         char *state;
1156         unsigned long flags = 0;
1157
1158         assert(filename);
1159         assert(lvalue);
1160         assert(rvalue);
1161         assert(data);
1162
1163         FOREACH_WORD_SEPARATOR(w, l, rvalue, ", ", state) {
1164                 _cleanup_free_ char *t;
1165
1166                 t = strndup(w, l);
1167                 if (!t)
1168                         return log_oom();
1169
1170                 if (streq(t, "shared"))
1171                         flags |= MS_SHARED;
1172                 else if (streq(t, "slave"))
1173                         flags |= MS_SLAVE;
1174                 else if (streq(w, "private"))
1175                         flags |= MS_PRIVATE;
1176                 else {
1177                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1178                                    "Failed to parse mount flag %s, ignoring: %s",
1179                                    t, rvalue);
1180                         return 0;
1181                 }
1182         }
1183
1184         c->mount_flags = flags;
1185         return 0;
1186 }
1187
1188 int config_parse_timer(const char *unit,
1189                        const char *filename,
1190                        unsigned line,
1191                        const char *section,
1192                        const char *lvalue,
1193                        int ltype,
1194                        const char *rvalue,
1195                        void *data,
1196                        void *userdata) {
1197
1198         Timer *t = data;
1199         usec_t u = 0;
1200         TimerValue *v;
1201         TimerBase b;
1202         CalendarSpec *c = NULL;
1203         clockid_t id;
1204
1205         assert(filename);
1206         assert(lvalue);
1207         assert(rvalue);
1208         assert(data);
1209
1210         if (isempty(rvalue)) {
1211                 /* Empty assignment resets list */
1212                 timer_free_values(t);
1213                 return 0;
1214         }
1215
1216         b = timer_base_from_string(lvalue);
1217         if (b < 0) {
1218                 log_syntax(unit, LOG_ERR, filename, line, -b,
1219                            "Failed to parse timer base, ignoring: %s", lvalue);
1220                 return 0;
1221         }
1222
1223         if (b == TIMER_CALENDAR) {
1224                 if (calendar_spec_from_string(rvalue, &c) < 0) {
1225                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1226                                    "Failed to parse calendar specification, ignoring: %s",
1227                                    rvalue);
1228                         return 0;
1229                 }
1230
1231                 id = CLOCK_REALTIME;
1232         } else {
1233                 if (parse_sec(rvalue, &u) < 0) {
1234                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1235                                    "Failed to parse timer value, ignoring: %s",
1236                                    rvalue);
1237                         return 0;
1238                 }
1239
1240                 id = CLOCK_MONOTONIC;
1241         }
1242
1243         v = new0(TimerValue, 1);
1244         if (!v)
1245                 return log_oom();
1246
1247         v->base = b;
1248         v->clock_id = id;
1249         v->value = u;
1250         v->calendar_spec = c;
1251
1252         LIST_PREPEND(TimerValue, value, t->values, v);
1253
1254         return 0;
1255 }
1256
1257 int config_parse_trigger_unit(
1258                 const char *unit,
1259                 const char *filename,
1260                 unsigned line,
1261                 const char *section,
1262                 const char *lvalue,
1263                 int ltype,
1264                 const char *rvalue,
1265                 void *data,
1266                 void *userdata) {
1267
1268         _cleanup_free_ char *p = NULL;
1269         Unit *u = data;
1270         UnitType type;
1271         int r;
1272
1273         assert(filename);
1274         assert(lvalue);
1275         assert(rvalue);
1276         assert(data);
1277
1278         if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
1279                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1280                            "Multiple units to trigger specified, ignoring: %s", rvalue);
1281                 return 0;
1282         }
1283
1284         p = unit_name_printf(u, rvalue);
1285         if (!p)
1286                 return log_oom();
1287
1288         type = unit_name_to_type(p);
1289         if (type < 0) {
1290                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1291                            "Unit type not valid, ignoring: %s", rvalue);
1292                 return 0;
1293         }
1294
1295         if (type == u->type) {
1296                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1297                            "Trigger cannot be of same type, ignoring: %s", rvalue);
1298                 return 0;
1299         }
1300
1301         r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p, NULL, true);
1302         if (r < 0) {
1303                 log_syntax(unit, LOG_ERR, filename, line, -r,
1304                            "Failed to add trigger on %s, ignoring: %s", p, strerror(-r));
1305                 return 0;
1306         }
1307
1308         return 0;
1309 }
1310
1311 int config_parse_path_spec(const char *unit,
1312                            const char *filename,
1313                            unsigned line,
1314                            const char *section,
1315                            const char *lvalue,
1316                            int ltype,
1317                            const char *rvalue,
1318                            void *data,
1319                            void *userdata) {
1320
1321         Path *p = data;
1322         PathSpec *s;
1323         PathType b;
1324         _cleanup_free_ char *k = NULL;
1325
1326         assert(filename);
1327         assert(lvalue);
1328         assert(rvalue);
1329         assert(data);
1330
1331         if (isempty(rvalue)) {
1332                 /* Empty assignment clears list */
1333                 path_free_specs(p);
1334                 return 0;
1335         }
1336
1337         b = path_type_from_string(lvalue);
1338         if (b < 0) {
1339                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1340                            "Failed to parse path type, ignoring: %s", lvalue);
1341                 return 0;
1342         }
1343
1344         k = unit_full_printf(UNIT(p), rvalue);
1345         if (!k) {
1346                 k = strdup(rvalue);
1347                 if (!k)
1348                         return log_oom();
1349                 else
1350                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1351                                    "Failed to resolve unit specifiers on %s. Ignoring.",
1352                                    rvalue);
1353         }
1354
1355         if (!path_is_absolute(k)) {
1356                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1357                            "Path is not absolute, ignoring: %s", k);
1358                 return 0;
1359         }
1360
1361         s = new0(PathSpec, 1);
1362         if (!s)
1363                 return log_oom();
1364
1365         s->path = path_kill_slashes(k);
1366         k = NULL;
1367         s->type = b;
1368         s->inotify_fd = -1;
1369
1370         LIST_PREPEND(PathSpec, spec, p->specs, s);
1371
1372         return 0;
1373 }
1374
1375 int config_parse_socket_service(const char *unit,
1376                                 const char *filename,
1377                                 unsigned line,
1378                                 const char *section,
1379                                 const char *lvalue,
1380                                 int ltype,
1381                                 const char *rvalue,
1382                                 void *data,
1383                                 void *userdata) {
1384
1385         Socket *s = data;
1386         int r;
1387         DBusError error;
1388         Unit *x;
1389         _cleanup_free_ char *p = NULL;
1390
1391         assert(filename);
1392         assert(lvalue);
1393         assert(rvalue);
1394         assert(data);
1395
1396         dbus_error_init(&error);
1397
1398         p = unit_name_printf(UNIT(s), rvalue);
1399         if (!p)
1400                 return log_oom();
1401
1402         if (!endswith(p, ".service")) {
1403                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1404                            "Unit must be of type service, ignoring: %s", rvalue);
1405                 return 0;
1406         }
1407
1408         r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
1409         if (r < 0) {
1410                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1411                            "Failed to load unit %s, ignoring: %s",
1412                            rvalue, bus_error(&error, r));
1413                 dbus_error_free(&error);
1414                 return 0;
1415         }
1416
1417         unit_ref_set(&s->service, x);
1418
1419         return 0;
1420 }
1421
1422 int config_parse_service_sockets(const char *unit,
1423                                  const char *filename,
1424                                  unsigned line,
1425                                  const char *section,
1426                                  const char *lvalue,
1427                                  int ltype,
1428                                  const char *rvalue,
1429                                  void *data,
1430                                  void *userdata) {
1431
1432         Service *s = data;
1433         int r;
1434         char *state, *w;
1435         size_t l;
1436
1437         assert(filename);
1438         assert(lvalue);
1439         assert(rvalue);
1440         assert(data);
1441
1442         FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1443                 _cleanup_free_ char *t = NULL, *k = NULL;
1444
1445                 t = strndup(w, l);
1446                 if (!t)
1447                         return log_oom();
1448
1449                 k = unit_name_printf(UNIT(s), t);
1450                 if (!k)
1451                         return log_oom();
1452
1453                 if (!endswith(k, ".socket")) {
1454                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1455                                    "Unit must be of type socket, ignoring: %s", k);
1456                         continue;
1457                 }
1458
1459                 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true);
1460                 if (r < 0)
1461                         log_syntax(unit, LOG_ERR, filename, line, -r,
1462                                    "Failed to add dependency on %s, ignoring: %s",
1463                                    k, strerror(-r));
1464
1465                 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true);
1466                 if (r < 0)
1467                         return r;
1468         }
1469
1470         return 0;
1471 }
1472
1473 int config_parse_service_timeout(const char *unit,
1474                                  const char *filename,
1475                                  unsigned line,
1476                                  const char *section,
1477                                  const char *lvalue,
1478                                  int ltype,
1479                                  const char *rvalue,
1480                                  void *data,
1481                                  void *userdata) {
1482
1483         Service *s = userdata;
1484         int r;
1485
1486         assert(filename);
1487         assert(lvalue);
1488         assert(rvalue);
1489         assert(s);
1490
1491         r = config_parse_sec(unit, filename, line, section, lvalue, ltype,
1492                              rvalue, data, userdata);
1493         if (r < 0)
1494                 return r;
1495
1496         if (streq(lvalue, "TimeoutSec")) {
1497                 s->start_timeout_defined = true;
1498                 s->timeout_stop_usec = s->timeout_start_usec;
1499         } else if (streq(lvalue, "TimeoutStartSec"))
1500                 s->start_timeout_defined = true;
1501
1502         return 0;
1503 }
1504
1505 int config_parse_unit_env_file(const char *unit,
1506                                const char *filename,
1507                                unsigned line,
1508                                const char *section,
1509                                const char *lvalue,
1510                                int ltype,
1511                                const char *rvalue,
1512                                void *data,
1513                                void *userdata) {
1514
1515         char ***env = data;
1516         Unit *u = userdata;
1517         _cleanup_free_ char *s = NULL;
1518         int r;
1519
1520         assert(filename);
1521         assert(lvalue);
1522         assert(rvalue);
1523         assert(data);
1524
1525         if (isempty(rvalue)) {
1526                 /* Empty assignment frees the list */
1527                 strv_free(*env);
1528                 *env = NULL;
1529                 return 0;
1530         }
1531
1532         s = unit_full_printf(u, rvalue);
1533         if (!s)
1534                 return log_oom();
1535
1536         if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1537                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1538                            "Path '%s' is not absolute, ignoring.", s);
1539                 return 0;
1540         }
1541
1542         r = strv_extend(env, s);
1543         if (r < 0)
1544                 return log_oom();
1545
1546         return 0;
1547 }
1548
1549 int config_parse_environ(const char *unit,
1550                          const char *filename,
1551                          unsigned line,
1552                          const char *section,
1553                          const char *lvalue,
1554                          int ltype,
1555                          const char *rvalue,
1556                          void *data,
1557                          void *userdata) {
1558
1559         Unit *u = userdata;
1560         char*** env = data, *w, *state;
1561         size_t l;
1562         _cleanup_free_ char *k = NULL;
1563
1564         assert(filename);
1565         assert(lvalue);
1566         assert(rvalue);
1567         assert(u);
1568
1569         if (isempty(rvalue)) {
1570                 /* Empty assignment resets the list */
1571                 strv_free(*env);
1572                 *env = NULL;
1573                 return 0;
1574         }
1575
1576         k = unit_full_printf(u, rvalue);
1577         if (!k)
1578                 return log_oom();
1579
1580         FOREACH_WORD_QUOTED(w, l, k, state) {
1581                 _cleanup_free_ char *n;
1582                 char **x;
1583
1584                 n = cunescape_length(w, l);
1585                 if (!n)
1586                         return log_oom();
1587
1588                 if (!env_assignment_is_valid(n)) {
1589                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1590                                    "Invalid environment assignment, ignoring: %s", rvalue);
1591                         continue;
1592                 }
1593
1594                 x = strv_env_set(*env, n);
1595                 if (!x)
1596                         return log_oom();
1597
1598                 strv_free(*env);
1599                 *env = x;
1600         }
1601
1602         return 0;
1603 }
1604
1605 int config_parse_ip_tos(const char *unit,
1606                         const char *filename,
1607                         unsigned line,
1608                         const char *section,
1609                         const char *lvalue,
1610                         int ltype,
1611                         const char *rvalue,
1612                         void *data,
1613                         void *userdata) {
1614
1615         int *ip_tos = data, x;
1616
1617         assert(filename);
1618         assert(lvalue);
1619         assert(rvalue);
1620         assert(data);
1621
1622         x = ip_tos_from_string(rvalue);
1623         if (x < 0) {
1624                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1625                            "Failed to parse IP TOS value, ignoring: %s", rvalue);
1626                 return 0;
1627         }
1628
1629         *ip_tos = x;
1630         return 0;
1631 }
1632
1633 int config_parse_unit_condition_path(const char *unit,
1634                                      const char *filename,
1635                                      unsigned line,
1636                                      const char *section,
1637                                      const char *lvalue,
1638                                      int ltype,
1639                                      const char *rvalue,
1640                                      void *data,
1641                                      void *userdata) {
1642
1643         ConditionType cond = ltype;
1644         Unit *u = data;
1645         bool trigger, negate;
1646         Condition *c;
1647         _cleanup_free_ char *p = NULL;
1648
1649         assert(filename);
1650         assert(lvalue);
1651         assert(rvalue);
1652         assert(data);
1653
1654         if (isempty(rvalue)) {
1655                 /* Empty assignment resets the list */
1656                 condition_free_list(u->conditions);
1657                 u->conditions = NULL;
1658                 return 0;
1659         }
1660
1661         trigger = rvalue[0] == '|';
1662         if (trigger)
1663                 rvalue++;
1664
1665         negate = rvalue[0] == '!';
1666         if (negate)
1667                 rvalue++;
1668
1669         p = unit_full_printf(u, rvalue);
1670         if (!p)
1671                 return log_oom();
1672
1673         if (!path_is_absolute(p)) {
1674                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1675                            "Path in condition not absolute, ignoring: %s", p);
1676                 return 0;
1677         }
1678
1679         c = condition_new(cond, p, trigger, negate);
1680         if (!c)
1681                 return log_oom();
1682
1683         LIST_PREPEND(Condition, conditions, u->conditions, c);
1684         return 0;
1685 }
1686
1687 int config_parse_unit_condition_string(const char *unit,
1688                                        const char *filename,
1689                                        unsigned line,
1690                                        const char *section,
1691                                        const char *lvalue,
1692                                        int ltype,
1693                                        const char *rvalue,
1694                                        void *data,
1695                                        void *userdata) {
1696
1697         ConditionType cond = ltype;
1698         Unit *u = data;
1699         bool trigger, negate;
1700         Condition *c;
1701         _cleanup_free_ char *s = NULL;
1702
1703         assert(filename);
1704         assert(lvalue);
1705         assert(rvalue);
1706         assert(data);
1707
1708         if (isempty(rvalue)) {
1709                 /* Empty assignment resets the list */
1710                 condition_free_list(u->conditions);
1711                 u->conditions = NULL;
1712                 return 0;
1713         }
1714
1715         trigger = rvalue[0] == '|';
1716         if (trigger)
1717                 rvalue++;
1718
1719         negate = rvalue[0] == '!';
1720         if (negate)
1721                 rvalue++;
1722
1723         s = unit_full_printf(u, rvalue);
1724         if (!s)
1725                 return log_oom();
1726
1727         c = condition_new(cond, s, trigger, negate);
1728         if (!c)
1729                 return log_oom();
1730
1731         LIST_PREPEND(Condition, conditions, u->conditions, c);
1732         return 0;
1733 }
1734
1735 int config_parse_unit_condition_null(const char *unit,
1736                                      const char *filename,
1737                                      unsigned line,
1738                                      const char *section,
1739                                      const char *lvalue,
1740                                      int ltype,
1741                                      const char *rvalue,
1742                                      void *data,
1743                                      void *userdata) {
1744
1745         Unit *u = data;
1746         Condition *c;
1747         bool trigger, negate;
1748         int b;
1749
1750         assert(filename);
1751         assert(lvalue);
1752         assert(rvalue);
1753         assert(data);
1754
1755         if (isempty(rvalue)) {
1756                 /* Empty assignment resets the list */
1757                 condition_free_list(u->conditions);
1758                 u->conditions = NULL;
1759                 return 0;
1760         }
1761
1762         trigger = rvalue[0] == '|';
1763         if (trigger)
1764                 rvalue++;
1765
1766         negate = rvalue[0] == '!';
1767         if (negate)
1768                 rvalue++;
1769
1770         b = parse_boolean(rvalue);
1771         if (b < 0) {
1772                 log_syntax(unit, LOG_ERR, filename, line, -b,
1773                            "Failed to parse boolean value in condition, ignoring: %s",
1774                            rvalue);
1775                 return 0;
1776         }
1777
1778         if (!b)
1779                 negate = !negate;
1780
1781         c = condition_new(CONDITION_NULL, NULL, trigger, negate);
1782         if (!c)
1783                 return log_oom();
1784
1785         LIST_PREPEND(Condition, conditions, u->conditions, c);
1786         return 0;
1787 }
1788
1789 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
1790 DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
1791
1792 int config_parse_unit_cgroup_attr(const char *unit,
1793                                   const char *filename,
1794                                   unsigned line,
1795                                   const char *section,
1796                                   const char *lvalue,
1797                                   int ltype,
1798                                   const char *rvalue,
1799                                   void *data,
1800                                   void *userdata) {
1801
1802         Unit *u = data;
1803         size_t a, b;
1804         _cleanup_free_ char *n = NULL, *v = NULL;
1805         const CGroupSemantics *s;
1806         int r;
1807
1808         assert(filename);
1809         assert(lvalue);
1810         assert(rvalue);
1811         assert(data);
1812
1813         if (isempty(rvalue)) {
1814                 /* Empty assignment clears the list */
1815                 cgroup_attribute_free_list(u->cgroup_attributes);
1816                 u->cgroup_attributes = NULL;
1817                 return 0;
1818         }
1819
1820         a = strcspn(rvalue, WHITESPACE);
1821         b = strspn(rvalue + a, WHITESPACE);
1822         if (a <= 0 || b <= 0) {
1823                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1824                            "Failed to parse cgroup attribute value, ignoring: %s",
1825                            rvalue);
1826                 return 0;
1827         }
1828
1829         n = strndup(rvalue, a);
1830         if (!n)
1831                 return log_oom();
1832
1833         r = cgroup_semantics_find(NULL, n, rvalue + a + b, &v, &s);
1834         if (r < 0) {
1835                 log_syntax(unit, LOG_ERR, filename, line, -r,
1836                            "Failed to parse cgroup attribute value, ignoring: %s",
1837                            rvalue);
1838                 return 0;
1839         }
1840
1841         r = unit_add_cgroup_attribute(u, s, NULL, n, v ? v : rvalue + a + b, NULL);
1842         if (r < 0) {
1843                 log_syntax(unit, LOG_ERR, filename, line, -r,
1844                            "Failed to add cgroup attribute value, ignoring: %s", rvalue);
1845                 return 0;
1846         }
1847
1848         return 0;
1849 }
1850
1851 int config_parse_unit_cgroup_attr_pretty(const char *unit,
1852                                          const char *filename,
1853                                          unsigned line,
1854                                          const char *section,
1855                                          const char *lvalue,
1856                                          int ltype,
1857                                          const char *rvalue,
1858                                          void *data,
1859                                          void *userdata) {
1860
1861         Unit *u = data;
1862         _cleanup_free_ char *v = NULL;
1863         const CGroupSemantics *s;
1864         int r;
1865
1866         assert(filename);
1867         assert(lvalue);
1868         assert(rvalue);
1869         assert(data);
1870
1871         r = cgroup_semantics_find(NULL, lvalue, rvalue, &v, &s);
1872         if (r < 0) {
1873                 log_syntax(unit, LOG_ERR, filename, line, -r,
1874                            "Failed to parse cgroup attribute value, ignoring: %s",
1875                            rvalue);
1876                 return 0;
1877         } else if (r == 0) {
1878                 log_syntax(unit, LOG_ERR, filename, line, ENOTSUP,
1879                            "Unknown or unsupported cgroup attribute %s, ignoring: %s",
1880                            lvalue, rvalue);
1881                 return 0;
1882         }
1883
1884         r = unit_add_cgroup_attribute(u, s, NULL, NULL, v, NULL);
1885         if (r < 0) {
1886                 log_syntax(unit, LOG_ERR, filename, line, -r,
1887                            "Failed to add cgroup attribute value, ignoring: %s", rvalue);
1888                 return 0;
1889         }
1890
1891         return 0;
1892 }
1893
1894 int config_parse_unit_requires_mounts_for(const char *unit,
1895                                           const char *filename,
1896                                           unsigned line,
1897                                           const char *section,
1898                                           const char *lvalue,
1899                                           int ltype,
1900                                           const char *rvalue,
1901                                           void *data,
1902                                           void *userdata) {
1903
1904         Unit *u = userdata;
1905         int r;
1906         bool empty_before;
1907
1908         assert(filename);
1909         assert(lvalue);
1910         assert(rvalue);
1911         assert(data);
1912
1913         empty_before = !u->requires_mounts_for;
1914
1915         r = config_parse_path_strv(unit, filename, line, section, lvalue, ltype,
1916                                    rvalue, data, userdata);
1917
1918         /* Make it easy to find units with requires_mounts set */
1919         if (empty_before && u->requires_mounts_for)
1920                 LIST_PREPEND(Unit, has_requires_mounts_for, u->manager->has_requires_mounts_for, u);
1921
1922         return r;
1923 }
1924
1925 int config_parse_documentation(const char *unit,
1926                                const char *filename,
1927                                unsigned line,
1928                                const char *section,
1929                                const char *lvalue,
1930                                int ltype,
1931                                const char *rvalue,
1932                                void *data,
1933                                void *userdata) {
1934
1935         Unit *u = userdata;
1936         int r;
1937         char **a, **b;
1938
1939         assert(filename);
1940         assert(lvalue);
1941         assert(rvalue);
1942         assert(u);
1943
1944         if (isempty(rvalue)) {
1945                 /* Empty assignment resets the list */
1946                 strv_free(u->documentation);
1947                 u->documentation = NULL;
1948                 return 0;
1949         }
1950
1951         r = config_parse_unit_strv_printf(unit, filename, line, section, lvalue, ltype,
1952                                           rvalue, data, userdata);
1953         if (r < 0)
1954                 return r;
1955
1956         for (a = b = u->documentation; a && *a; a++) {
1957
1958                 if (is_valid_documentation_url(*a))
1959                         *(b++) = *a;
1960                 else {
1961                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1962                                    "Invalid URL, ignoring: %s", *a);
1963                         free(*a);
1964                 }
1965         }
1966         *b = NULL;
1967
1968         return r;
1969 }
1970
1971 static void syscall_set(uint32_t *p, int nr) {
1972         nr = SYSCALL_TO_INDEX(nr);
1973         p[nr >> 4] |= 1 << (nr & 31);
1974 }
1975
1976 static void syscall_unset(uint32_t *p, int nr) {
1977         nr = SYSCALL_TO_INDEX(nr);
1978         p[nr >> 4] &= ~(1 << (nr & 31));
1979 }
1980
1981 int config_parse_syscall_filter(const char *unit,
1982                                 const char *filename,
1983                                 unsigned line,
1984                                 const char *section,
1985                                 const char *lvalue,
1986                                 int ltype,
1987                                 const char *rvalue,
1988                                 void *data,
1989                                 void *userdata) {
1990
1991         ExecContext *c = data;
1992         Unit *u = userdata;
1993         bool invert = false;
1994         char *w;
1995         size_t l;
1996         char *state;
1997
1998         assert(filename);
1999         assert(lvalue);
2000         assert(rvalue);
2001         assert(u);
2002
2003         if (isempty(rvalue)) {
2004                 /* Empty assignment resets the list */
2005                 free(c->syscall_filter);
2006                 c->syscall_filter = NULL;
2007                 return 0;
2008         }
2009
2010         if (rvalue[0] == '~') {
2011                 invert = true;
2012                 rvalue++;
2013         }
2014
2015         if (!c->syscall_filter) {
2016                 size_t n;
2017
2018                 n = (syscall_max() + 31) >> 4;
2019                 c->syscall_filter = new(uint32_t, n);
2020                 if (!c->syscall_filter)
2021                         return log_oom();
2022
2023                 memset(c->syscall_filter, invert ? 0xFF : 0, n * sizeof(uint32_t));
2024
2025                 /* Add these by default */
2026                 syscall_set(c->syscall_filter, __NR_execve);
2027                 syscall_set(c->syscall_filter, __NR_rt_sigreturn);
2028 #ifdef __NR_sigreturn
2029                 syscall_set(c->syscall_filter, __NR_sigreturn);
2030 #endif
2031                 syscall_set(c->syscall_filter, __NR_exit_group);
2032                 syscall_set(c->syscall_filter, __NR_exit);
2033         }
2034
2035         FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2036                 int id;
2037                 _cleanup_free_ char *t = NULL;
2038
2039                 t = strndup(w, l);
2040                 if (!t)
2041                         return log_oom();
2042
2043                 id = syscall_from_name(t);
2044                 if (id < 0)  {
2045                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2046                                    "Failed to parse syscall, ignoring: %s", t);
2047                         continue;
2048                 }
2049
2050                 if (invert)
2051                         syscall_unset(c->syscall_filter, id);
2052                 else
2053                         syscall_set(c->syscall_filter, id);
2054         }
2055
2056         c->no_new_privileges = true;
2057
2058         return 0;
2059 }
2060
2061 #define FOLLOW_MAX 8
2062
2063 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
2064         unsigned c = 0;
2065         int fd, r;
2066         FILE *f;
2067         char *id = NULL;
2068
2069         assert(filename);
2070         assert(*filename);
2071         assert(_f);
2072         assert(names);
2073
2074         /* This will update the filename pointer if the loaded file is
2075          * reached by a symlink. The old string will be freed. */
2076
2077         for (;;) {
2078                 char *target, *name;
2079
2080                 if (c++ >= FOLLOW_MAX)
2081                         return -ELOOP;
2082
2083                 path_kill_slashes(*filename);
2084
2085                 /* Add the file name we are currently looking at to
2086                  * the names of this unit, but only if it is a valid
2087                  * unit name. */
2088                 name = path_get_file_name(*filename);
2089
2090                 if (unit_name_is_valid(name, true)) {
2091
2092                         id = set_get(names, name);
2093                         if (!id) {
2094                                 id = strdup(name);
2095                                 if (!id)
2096                                         return -ENOMEM;
2097
2098                                 r = set_put(names, id);
2099                                 if (r < 0) {
2100                                         free(id);
2101                                         return r;
2102                                 }
2103                         }
2104                 }
2105
2106                 /* Try to open the file name, but don't if its a symlink */
2107                 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
2108                 if (fd >= 0)
2109                         break;
2110
2111                 if (errno != ELOOP)
2112                         return -errno;
2113
2114                 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
2115                 r = readlink_and_make_absolute(*filename, &target);
2116                 if (r < 0)
2117                         return r;
2118
2119                 free(*filename);
2120                 *filename = target;
2121         }
2122
2123         f = fdopen(fd, "re");
2124         if (!f) {
2125                 r = -errno;
2126                 close_nointr_nofail(fd);
2127                 return r;
2128         }
2129
2130         *_f = f;
2131         *_final = id;
2132         return 0;
2133 }
2134
2135 static int merge_by_names(Unit **u, Set *names, const char *id) {
2136         char *k;
2137         int r;
2138
2139         assert(u);
2140         assert(*u);
2141         assert(names);
2142
2143         /* Let's try to add in all symlink names we found */
2144         while ((k = set_steal_first(names))) {
2145
2146                 /* First try to merge in the other name into our
2147                  * unit */
2148                 r = unit_merge_by_name(*u, k);
2149                 if (r < 0) {
2150                         Unit *other;
2151
2152                         /* Hmm, we couldn't merge the other unit into
2153                          * ours? Then let's try it the other way
2154                          * round */
2155
2156                         other = manager_get_unit((*u)->manager, k);
2157                         free(k);
2158
2159                         if (other) {
2160                                 r = unit_merge(other, *u);
2161                                 if (r >= 0) {
2162                                         *u = other;
2163                                         return merge_by_names(u, names, NULL);
2164                                 }
2165                         }
2166
2167                         return r;
2168                 }
2169
2170                 if (id == k)
2171                         unit_choose_id(*u, id);
2172
2173                 free(k);
2174         }
2175
2176         return 0;
2177 }
2178
2179 static int load_from_path(Unit *u, const char *path) {
2180         int r;
2181         Set *symlink_names;
2182         FILE *f = NULL;
2183         char *filename = NULL, *id = NULL;
2184         Unit *merged;
2185         struct stat st;
2186
2187         assert(u);
2188         assert(path);
2189
2190         symlink_names = set_new(string_hash_func, string_compare_func);
2191         if (!symlink_names)
2192                 return -ENOMEM;
2193
2194         if (path_is_absolute(path)) {
2195
2196                 filename = strdup(path);
2197                 if (!filename) {
2198                         r = -ENOMEM;
2199                         goto finish;
2200                 }
2201
2202                 r = open_follow(&filename, &f, symlink_names, &id);
2203                 if (r < 0) {
2204                         free(filename);
2205                         filename = NULL;
2206
2207                         if (r != -ENOENT)
2208                                 goto finish;
2209                 }
2210
2211         } else  {
2212                 char **p;
2213
2214                 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
2215
2216                         /* Instead of opening the path right away, we manually
2217                          * follow all symlinks and add their name to our unit
2218                          * name set while doing so */
2219                         filename = path_make_absolute(path, *p);
2220                         if (!filename) {
2221                                 r = -ENOMEM;
2222                                 goto finish;
2223                         }
2224
2225                         if (u->manager->unit_path_cache &&
2226                             !set_get(u->manager->unit_path_cache, filename))
2227                                 r = -ENOENT;
2228                         else
2229                                 r = open_follow(&filename, &f, symlink_names, &id);
2230
2231                         if (r < 0) {
2232                                 free(filename);
2233                                 filename = NULL;
2234
2235                                 if (r != -ENOENT)
2236                                         goto finish;
2237
2238                                 /* Empty the symlink names for the next run */
2239                                 set_clear_free(symlink_names);
2240                                 continue;
2241                         }
2242
2243                         break;
2244                 }
2245         }
2246
2247         if (!filename) {
2248                 /* Hmm, no suitable file found? */
2249                 r = 0;
2250                 goto finish;
2251         }
2252
2253         merged = u;
2254         r = merge_by_names(&merged, symlink_names, id);
2255         if (r < 0)
2256                 goto finish;
2257
2258         if (merged != u) {
2259                 u->load_state = UNIT_MERGED;
2260                 r = 0;
2261                 goto finish;
2262         }
2263
2264         if (fstat(fileno(f), &st) < 0) {
2265                 r = -errno;
2266                 goto finish;
2267         }
2268
2269         if (null_or_empty(&st))
2270                 u->load_state = UNIT_MASKED;
2271         else {
2272                 /* Now, parse the file contents */
2273                 r = config_parse(u->id, filename, f, UNIT_VTABLE(u)->sections,
2274                                  config_item_perf_lookup,
2275                                  (void*) load_fragment_gperf_lookup, false, u);
2276                 if (r < 0)
2277                         goto finish;
2278
2279                 u->load_state = UNIT_LOADED;
2280         }
2281
2282         free(u->fragment_path);
2283         u->fragment_path = filename;
2284         filename = NULL;
2285
2286         u->fragment_mtime = timespec_load(&st.st_mtim);
2287
2288         if (u->source_path) {
2289                 if (stat(u->source_path, &st) >= 0)
2290                         u->source_mtime = timespec_load(&st.st_mtim);
2291                 else
2292                         u->source_mtime = 0;
2293         }
2294
2295         r = 0;
2296
2297 finish:
2298         set_free_free(symlink_names);
2299         free(filename);
2300
2301         if (f)
2302                 fclose(f);
2303
2304         return r;
2305 }
2306
2307 int unit_load_fragment(Unit *u) {
2308         int r;
2309         Iterator i;
2310         const char *t;
2311
2312         assert(u);
2313         assert(u->load_state == UNIT_STUB);
2314         assert(u->id);
2315
2316         /* First, try to find the unit under its id. We always look
2317          * for unit files in the default directories, to make it easy
2318          * to override things by placing things in /etc/systemd/system */
2319         r = load_from_path(u, u->id);
2320         if (r < 0)
2321                 return r;
2322
2323         /* Try to find an alias we can load this with */
2324         if (u->load_state == UNIT_STUB)
2325                 SET_FOREACH(t, u->names, i) {
2326
2327                         if (t == u->id)
2328                                 continue;
2329
2330                         r = load_from_path(u, t);
2331                         if (r < 0)
2332                                 return r;
2333
2334                         if (u->load_state != UNIT_STUB)
2335                                 break;
2336                 }
2337
2338         /* And now, try looking for it under the suggested (originally linked) path */
2339         if (u->load_state == UNIT_STUB && u->fragment_path) {
2340
2341                 r = load_from_path(u, u->fragment_path);
2342                 if (r < 0)
2343                         return r;
2344
2345                 if (u->load_state == UNIT_STUB) {
2346                         /* Hmm, this didn't work? Then let's get rid
2347                          * of the fragment path stored for us, so that
2348                          * we don't point to an invalid location. */
2349                         free(u->fragment_path);
2350                         u->fragment_path = NULL;
2351                 }
2352         }
2353
2354         /* Look for a template */
2355         if (u->load_state == UNIT_STUB && u->instance) {
2356                 char *k;
2357
2358                 k = unit_name_template(u->id);
2359                 if (!k)
2360                         return -ENOMEM;
2361
2362                 r = load_from_path(u, k);
2363                 free(k);
2364
2365                 if (r < 0)
2366                         return r;
2367
2368                 if (u->load_state == UNIT_STUB)
2369                         SET_FOREACH(t, u->names, i) {
2370
2371                                 if (t == u->id)
2372                                         continue;
2373
2374                                 k = unit_name_template(t);
2375                                 if (!k)
2376                                         return -ENOMEM;
2377
2378                                 r = load_from_path(u, k);
2379                                 free(k);
2380
2381                                 if (r < 0)
2382                                         return r;
2383
2384                                 if (u->load_state != UNIT_STUB)
2385                                         break;
2386                         }
2387         }
2388
2389         return 0;
2390 }
2391
2392 void unit_dump_config_items(FILE *f) {
2393         static const struct {
2394                 const ConfigParserCallback callback;
2395                 const char *rvalue;
2396         } table[] = {
2397                 { config_parse_int,                   "INTEGER" },
2398                 { config_parse_unsigned,              "UNSIGNED" },
2399                 { config_parse_bytes_size,            "SIZE" },
2400                 { config_parse_bool,                  "BOOLEAN" },
2401                 { config_parse_string,                "STRING" },
2402                 { config_parse_path,                  "PATH" },
2403                 { config_parse_unit_path_printf,      "PATH" },
2404                 { config_parse_strv,                  "STRING [...]" },
2405                 { config_parse_exec_nice,             "NICE" },
2406                 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
2407                 { config_parse_exec_io_class,         "IOCLASS" },
2408                 { config_parse_exec_io_priority,      "IOPRIORITY" },
2409                 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
2410                 { config_parse_exec_cpu_sched_prio,   "CPUSCHEDPRIO" },
2411                 { config_parse_exec_cpu_affinity,     "CPUAFFINITY" },
2412                 { config_parse_mode,                  "MODE" },
2413                 { config_parse_unit_env_file,         "FILE" },
2414                 { config_parse_output,                "OUTPUT" },
2415                 { config_parse_input,                 "INPUT" },
2416                 { config_parse_facility,              "FACILITY" },
2417                 { config_parse_level,                 "LEVEL" },
2418                 { config_parse_exec_capabilities,     "CAPABILITIES" },
2419                 { config_parse_exec_secure_bits,      "SECUREBITS" },
2420                 { config_parse_bounding_set,          "BOUNDINGSET" },
2421                 { config_parse_limit,                 "LIMIT" },
2422                 { config_parse_unit_cgroup,           "CGROUP [...]" },
2423                 { config_parse_unit_deps,             "UNIT [...]" },
2424                 { config_parse_exec,                  "PATH [ARGUMENT [...]]" },
2425                 { config_parse_service_type,          "SERVICETYPE" },
2426                 { config_parse_service_restart,       "SERVICERESTART" },
2427 #ifdef HAVE_SYSV_COMPAT
2428                 { config_parse_sysv_priority,         "SYSVPRIORITY" },
2429 #else
2430                 { config_parse_warn_compat,           "NOTSUPPORTED" },
2431 #endif
2432                 { config_parse_kill_mode,             "KILLMODE" },
2433                 { config_parse_kill_signal,           "SIGNAL" },
2434                 { config_parse_socket_listen,         "SOCKET [...]" },
2435                 { config_parse_socket_bind,           "SOCKETBIND" },
2436                 { config_parse_socket_bindtodevice,   "NETWORKINTERFACE" },
2437                 { config_parse_sec,                   "SECONDS" },
2438                 { config_parse_nsec,                  "NANOSECONDS" },
2439                 { config_parse_path_strv,             "PATH [...]" },
2440                 { config_parse_unit_requires_mounts_for, "PATH [...]" },
2441                 { config_parse_exec_mount_flags,      "MOUNTFLAG [...]" },
2442                 { config_parse_unit_string_printf,    "STRING" },
2443                 { config_parse_trigger_unit,          "UNIT" },
2444                 { config_parse_timer,                 "TIMER" },
2445                 { config_parse_path_spec,             "PATH" },
2446                 { config_parse_notify_access,         "ACCESS" },
2447                 { config_parse_ip_tos,                "TOS" },
2448                 { config_parse_unit_condition_path,   "CONDITION" },
2449                 { config_parse_unit_condition_string, "CONDITION" },
2450                 { config_parse_unit_condition_null,   "CONDITION" },
2451         };
2452
2453         const char *prev = NULL;
2454         const char *i;
2455
2456         assert(f);
2457
2458         NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
2459                 const char *rvalue = "OTHER", *lvalue;
2460                 unsigned j;
2461                 size_t prefix_len;
2462                 const char *dot;
2463                 const ConfigPerfItem *p;
2464
2465                 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
2466
2467                 dot = strchr(i, '.');
2468                 lvalue = dot ? dot + 1 : i;
2469                 prefix_len = dot-i;
2470
2471                 if (dot)
2472                         if (!prev || !strneq(prev, i, prefix_len+1)) {
2473                                 if (prev)
2474                                         fputc('\n', f);
2475
2476                                 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
2477                         }
2478
2479                 for (j = 0; j < ELEMENTSOF(table); j++)
2480                         if (p->parse == table[j].callback) {
2481                                 rvalue = table[j].rvalue;
2482                                 break;
2483                         }
2484
2485                 fprintf(f, "%s=%s\n", lvalue, rvalue);
2486                 prev = i;
2487         }
2488 }