chiark / gitweb /
15fabe860e7e47b903f0a0fad3e4f4e9902237df
[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(data);
1568
1569         if (isempty(rvalue)) {
1570                 /* Empty assignment resets the list */
1571                 strv_free(*env);
1572                 *env = NULL;
1573                 return 0;
1574         }
1575
1576         if (u)
1577                 k = unit_full_printf(u, rvalue);
1578         else
1579                 k = strdup(rvalue);
1580
1581         if (!k)
1582                 return log_oom();
1583
1584         FOREACH_WORD_QUOTED(w, l, k, state) {
1585                 _cleanup_free_ char *n;
1586                 char **x;
1587
1588                 n = cunescape_length(w, l);
1589                 if (!n)
1590                         return log_oom();
1591
1592                 if (!env_assignment_is_valid(n)) {
1593                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1594                                    "Invalid environment assignment, ignoring: %s", rvalue);
1595                         continue;
1596                 }
1597
1598                 x = strv_env_set(*env, n);
1599                 if (!x)
1600                         return log_oom();
1601
1602                 strv_free(*env);
1603                 *env = x;
1604         }
1605
1606         return 0;
1607 }
1608
1609 int config_parse_ip_tos(const char *unit,
1610                         const char *filename,
1611                         unsigned line,
1612                         const char *section,
1613                         const char *lvalue,
1614                         int ltype,
1615                         const char *rvalue,
1616                         void *data,
1617                         void *userdata) {
1618
1619         int *ip_tos = data, x;
1620
1621         assert(filename);
1622         assert(lvalue);
1623         assert(rvalue);
1624         assert(data);
1625
1626         x = ip_tos_from_string(rvalue);
1627         if (x < 0) {
1628                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1629                            "Failed to parse IP TOS value, ignoring: %s", rvalue);
1630                 return 0;
1631         }
1632
1633         *ip_tos = x;
1634         return 0;
1635 }
1636
1637 int config_parse_unit_condition_path(const char *unit,
1638                                      const char *filename,
1639                                      unsigned line,
1640                                      const char *section,
1641                                      const char *lvalue,
1642                                      int ltype,
1643                                      const char *rvalue,
1644                                      void *data,
1645                                      void *userdata) {
1646
1647         ConditionType cond = ltype;
1648         Unit *u = data;
1649         bool trigger, negate;
1650         Condition *c;
1651         _cleanup_free_ char *p = NULL;
1652
1653         assert(filename);
1654         assert(lvalue);
1655         assert(rvalue);
1656         assert(data);
1657
1658         if (isempty(rvalue)) {
1659                 /* Empty assignment resets the list */
1660                 condition_free_list(u->conditions);
1661                 u->conditions = NULL;
1662                 return 0;
1663         }
1664
1665         trigger = rvalue[0] == '|';
1666         if (trigger)
1667                 rvalue++;
1668
1669         negate = rvalue[0] == '!';
1670         if (negate)
1671                 rvalue++;
1672
1673         p = unit_full_printf(u, rvalue);
1674         if (!p)
1675                 return log_oom();
1676
1677         if (!path_is_absolute(p)) {
1678                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1679                            "Path in condition not absolute, ignoring: %s", p);
1680                 return 0;
1681         }
1682
1683         c = condition_new(cond, p, trigger, negate);
1684         if (!c)
1685                 return log_oom();
1686
1687         LIST_PREPEND(Condition, conditions, u->conditions, c);
1688         return 0;
1689 }
1690
1691 int config_parse_unit_condition_string(const char *unit,
1692                                        const char *filename,
1693                                        unsigned line,
1694                                        const char *section,
1695                                        const char *lvalue,
1696                                        int ltype,
1697                                        const char *rvalue,
1698                                        void *data,
1699                                        void *userdata) {
1700
1701         ConditionType cond = ltype;
1702         Unit *u = data;
1703         bool trigger, negate;
1704         Condition *c;
1705         _cleanup_free_ char *s = NULL;
1706
1707         assert(filename);
1708         assert(lvalue);
1709         assert(rvalue);
1710         assert(data);
1711
1712         if (isempty(rvalue)) {
1713                 /* Empty assignment resets the list */
1714                 condition_free_list(u->conditions);
1715                 u->conditions = NULL;
1716                 return 0;
1717         }
1718
1719         trigger = rvalue[0] == '|';
1720         if (trigger)
1721                 rvalue++;
1722
1723         negate = rvalue[0] == '!';
1724         if (negate)
1725                 rvalue++;
1726
1727         s = unit_full_printf(u, rvalue);
1728         if (!s)
1729                 return log_oom();
1730
1731         c = condition_new(cond, s, trigger, negate);
1732         if (!c)
1733                 return log_oom();
1734
1735         LIST_PREPEND(Condition, conditions, u->conditions, c);
1736         return 0;
1737 }
1738
1739 int config_parse_unit_condition_null(const char *unit,
1740                                      const char *filename,
1741                                      unsigned line,
1742                                      const char *section,
1743                                      const char *lvalue,
1744                                      int ltype,
1745                                      const char *rvalue,
1746                                      void *data,
1747                                      void *userdata) {
1748
1749         Unit *u = data;
1750         Condition *c;
1751         bool trigger, negate;
1752         int b;
1753
1754         assert(filename);
1755         assert(lvalue);
1756         assert(rvalue);
1757         assert(data);
1758
1759         if (isempty(rvalue)) {
1760                 /* Empty assignment resets the list */
1761                 condition_free_list(u->conditions);
1762                 u->conditions = NULL;
1763                 return 0;
1764         }
1765
1766         trigger = rvalue[0] == '|';
1767         if (trigger)
1768                 rvalue++;
1769
1770         negate = rvalue[0] == '!';
1771         if (negate)
1772                 rvalue++;
1773
1774         b = parse_boolean(rvalue);
1775         if (b < 0) {
1776                 log_syntax(unit, LOG_ERR, filename, line, -b,
1777                            "Failed to parse boolean value in condition, ignoring: %s",
1778                            rvalue);
1779                 return 0;
1780         }
1781
1782         if (!b)
1783                 negate = !negate;
1784
1785         c = condition_new(CONDITION_NULL, NULL, trigger, negate);
1786         if (!c)
1787                 return log_oom();
1788
1789         LIST_PREPEND(Condition, conditions, u->conditions, c);
1790         return 0;
1791 }
1792
1793 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
1794 DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
1795
1796 int config_parse_unit_cgroup_attr(const char *unit,
1797                                   const char *filename,
1798                                   unsigned line,
1799                                   const char *section,
1800                                   const char *lvalue,
1801                                   int ltype,
1802                                   const char *rvalue,
1803                                   void *data,
1804                                   void *userdata) {
1805
1806         Unit *u = data;
1807         size_t a, b;
1808         _cleanup_free_ char *n = NULL, *v = NULL;
1809         const CGroupSemantics *s;
1810         int r;
1811
1812         assert(filename);
1813         assert(lvalue);
1814         assert(rvalue);
1815         assert(data);
1816
1817         if (isempty(rvalue)) {
1818                 /* Empty assignment clears the list */
1819                 cgroup_attribute_free_list(u->cgroup_attributes);
1820                 u->cgroup_attributes = NULL;
1821                 return 0;
1822         }
1823
1824         a = strcspn(rvalue, WHITESPACE);
1825         b = strspn(rvalue + a, WHITESPACE);
1826         if (a <= 0 || b <= 0) {
1827                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1828                            "Failed to parse cgroup attribute value, ignoring: %s",
1829                            rvalue);
1830                 return 0;
1831         }
1832
1833         n = strndup(rvalue, a);
1834         if (!n)
1835                 return log_oom();
1836
1837         r = cgroup_semantics_find(NULL, n, rvalue + a + b, &v, &s);
1838         if (r < 0) {
1839                 log_syntax(unit, LOG_ERR, filename, line, -r,
1840                            "Failed to parse cgroup attribute value, ignoring: %s",
1841                            rvalue);
1842                 return 0;
1843         }
1844
1845         r = unit_add_cgroup_attribute(u, s, NULL, n, v ? v : rvalue + a + b, NULL);
1846         if (r < 0) {
1847                 log_syntax(unit, LOG_ERR, filename, line, -r,
1848                            "Failed to add cgroup attribute value, ignoring: %s", rvalue);
1849                 return 0;
1850         }
1851
1852         return 0;
1853 }
1854
1855 int config_parse_unit_cgroup_attr_pretty(const char *unit,
1856                                          const char *filename,
1857                                          unsigned line,
1858                                          const char *section,
1859                                          const char *lvalue,
1860                                          int ltype,
1861                                          const char *rvalue,
1862                                          void *data,
1863                                          void *userdata) {
1864
1865         Unit *u = data;
1866         _cleanup_free_ char *v = NULL;
1867         const CGroupSemantics *s;
1868         int r;
1869
1870         assert(filename);
1871         assert(lvalue);
1872         assert(rvalue);
1873         assert(data);
1874
1875         r = cgroup_semantics_find(NULL, lvalue, rvalue, &v, &s);
1876         if (r < 0) {
1877                 log_syntax(unit, LOG_ERR, filename, line, -r,
1878                            "Failed to parse cgroup attribute value, ignoring: %s",
1879                            rvalue);
1880                 return 0;
1881         } else if (r == 0) {
1882                 log_syntax(unit, LOG_ERR, filename, line, ENOTSUP,
1883                            "Unknown or unsupported cgroup attribute %s, ignoring: %s",
1884                            lvalue, rvalue);
1885                 return 0;
1886         }
1887
1888         r = unit_add_cgroup_attribute(u, s, NULL, NULL, v, NULL);
1889         if (r < 0) {
1890                 log_syntax(unit, LOG_ERR, filename, line, -r,
1891                            "Failed to add cgroup attribute value, ignoring: %s", rvalue);
1892                 return 0;
1893         }
1894
1895         return 0;
1896 }
1897
1898 int config_parse_unit_requires_mounts_for(const char *unit,
1899                                           const char *filename,
1900                                           unsigned line,
1901                                           const char *section,
1902                                           const char *lvalue,
1903                                           int ltype,
1904                                           const char *rvalue,
1905                                           void *data,
1906                                           void *userdata) {
1907
1908         Unit *u = userdata;
1909         int r;
1910         bool empty_before;
1911
1912         assert(filename);
1913         assert(lvalue);
1914         assert(rvalue);
1915         assert(data);
1916
1917         empty_before = !u->requires_mounts_for;
1918
1919         r = config_parse_path_strv(unit, filename, line, section, lvalue, ltype,
1920                                    rvalue, data, userdata);
1921
1922         /* Make it easy to find units with requires_mounts set */
1923         if (empty_before && u->requires_mounts_for)
1924                 LIST_PREPEND(Unit, has_requires_mounts_for, u->manager->has_requires_mounts_for, u);
1925
1926         return r;
1927 }
1928
1929 int config_parse_documentation(const char *unit,
1930                                const char *filename,
1931                                unsigned line,
1932                                const char *section,
1933                                const char *lvalue,
1934                                int ltype,
1935                                const char *rvalue,
1936                                void *data,
1937                                void *userdata) {
1938
1939         Unit *u = userdata;
1940         int r;
1941         char **a, **b;
1942
1943         assert(filename);
1944         assert(lvalue);
1945         assert(rvalue);
1946         assert(u);
1947
1948         if (isempty(rvalue)) {
1949                 /* Empty assignment resets the list */
1950                 strv_free(u->documentation);
1951                 u->documentation = NULL;
1952                 return 0;
1953         }
1954
1955         r = config_parse_unit_strv_printf(unit, filename, line, section, lvalue, ltype,
1956                                           rvalue, data, userdata);
1957         if (r < 0)
1958                 return r;
1959
1960         for (a = b = u->documentation; a && *a; a++) {
1961
1962                 if (is_valid_documentation_url(*a))
1963                         *(b++) = *a;
1964                 else {
1965                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1966                                    "Invalid URL, ignoring: %s", *a);
1967                         free(*a);
1968                 }
1969         }
1970         *b = NULL;
1971
1972         return r;
1973 }
1974
1975 static void syscall_set(uint32_t *p, int nr) {
1976         nr = SYSCALL_TO_INDEX(nr);
1977         p[nr >> 4] |= 1 << (nr & 31);
1978 }
1979
1980 static void syscall_unset(uint32_t *p, int nr) {
1981         nr = SYSCALL_TO_INDEX(nr);
1982         p[nr >> 4] &= ~(1 << (nr & 31));
1983 }
1984
1985 int config_parse_syscall_filter(const char *unit,
1986                                 const char *filename,
1987                                 unsigned line,
1988                                 const char *section,
1989                                 const char *lvalue,
1990                                 int ltype,
1991                                 const char *rvalue,
1992                                 void *data,
1993                                 void *userdata) {
1994
1995         ExecContext *c = data;
1996         Unit *u = userdata;
1997         bool invert = false;
1998         char *w;
1999         size_t l;
2000         char *state;
2001
2002         assert(filename);
2003         assert(lvalue);
2004         assert(rvalue);
2005         assert(u);
2006
2007         if (isempty(rvalue)) {
2008                 /* Empty assignment resets the list */
2009                 free(c->syscall_filter);
2010                 c->syscall_filter = NULL;
2011                 return 0;
2012         }
2013
2014         if (rvalue[0] == '~') {
2015                 invert = true;
2016                 rvalue++;
2017         }
2018
2019         if (!c->syscall_filter) {
2020                 size_t n;
2021
2022                 n = (syscall_max() + 31) >> 4;
2023                 c->syscall_filter = new(uint32_t, n);
2024                 if (!c->syscall_filter)
2025                         return log_oom();
2026
2027                 memset(c->syscall_filter, invert ? 0xFF : 0, n * sizeof(uint32_t));
2028
2029                 /* Add these by default */
2030                 syscall_set(c->syscall_filter, __NR_execve);
2031                 syscall_set(c->syscall_filter, __NR_rt_sigreturn);
2032 #ifdef __NR_sigreturn
2033                 syscall_set(c->syscall_filter, __NR_sigreturn);
2034 #endif
2035                 syscall_set(c->syscall_filter, __NR_exit_group);
2036                 syscall_set(c->syscall_filter, __NR_exit);
2037         }
2038
2039         FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2040                 int id;
2041                 _cleanup_free_ char *t = NULL;
2042
2043                 t = strndup(w, l);
2044                 if (!t)
2045                         return log_oom();
2046
2047                 id = syscall_from_name(t);
2048                 if (id < 0)  {
2049                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2050                                    "Failed to parse syscall, ignoring: %s", t);
2051                         continue;
2052                 }
2053
2054                 if (invert)
2055                         syscall_unset(c->syscall_filter, id);
2056                 else
2057                         syscall_set(c->syscall_filter, id);
2058         }
2059
2060         c->no_new_privileges = true;
2061
2062         return 0;
2063 }
2064
2065 int config_parse_unit_slice(
2066                 const char *unit,
2067                 const char *filename,
2068                 unsigned line,
2069                 const char *section,
2070                 const char *lvalue,
2071                 int ltype,
2072                 const char *rvalue,
2073                 void *data,
2074                 void *userdata) {
2075
2076         _cleanup_free_ char *k = NULL;
2077         Unit *u = userdata, *slice;
2078         int r;
2079
2080         assert(filename);
2081         assert(lvalue);
2082         assert(rvalue);
2083         assert(u);
2084
2085         k = unit_name_printf(u, rvalue);
2086         if (!k)
2087                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2088                            "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
2089
2090         r = manager_load_unit(u->manager, k ? k : rvalue, NULL, NULL, &slice);
2091         if (r < 0) {
2092                 log_syntax(unit, LOG_ERR, filename, line, -r,
2093                            "Failed to load slice unit %s. Ignoring.", k ? k : rvalue);
2094                 return 0;
2095         }
2096
2097         if (slice->type != UNIT_SLICE) {
2098                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2099                            "Slice unit %s is not a slice. Ignoring.", k ? k : rvalue);
2100                 return 0;
2101         }
2102
2103         unit_ref_set(&u->slice, slice);
2104         return 0;
2105 }
2106
2107 #define FOLLOW_MAX 8
2108
2109 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
2110         unsigned c = 0;
2111         int fd, r;
2112         FILE *f;
2113         char *id = NULL;
2114
2115         assert(filename);
2116         assert(*filename);
2117         assert(_f);
2118         assert(names);
2119
2120         /* This will update the filename pointer if the loaded file is
2121          * reached by a symlink. The old string will be freed. */
2122
2123         for (;;) {
2124                 char *target, *name;
2125
2126                 if (c++ >= FOLLOW_MAX)
2127                         return -ELOOP;
2128
2129                 path_kill_slashes(*filename);
2130
2131                 /* Add the file name we are currently looking at to
2132                  * the names of this unit, but only if it is a valid
2133                  * unit name. */
2134                 name = path_get_file_name(*filename);
2135
2136                 if (unit_name_is_valid(name, true)) {
2137
2138                         id = set_get(names, name);
2139                         if (!id) {
2140                                 id = strdup(name);
2141                                 if (!id)
2142                                         return -ENOMEM;
2143
2144                                 r = set_consume(names, id);
2145                                 if (r < 0)
2146                                         return r;
2147                         }
2148                 }
2149
2150                 /* Try to open the file name, but don't if its a symlink */
2151                 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
2152                 if (fd >= 0)
2153                         break;
2154
2155                 if (errno != ELOOP)
2156                         return -errno;
2157
2158                 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
2159                 r = readlink_and_make_absolute(*filename, &target);
2160                 if (r < 0)
2161                         return r;
2162
2163                 free(*filename);
2164                 *filename = target;
2165         }
2166
2167         f = fdopen(fd, "re");
2168         if (!f) {
2169                 r = -errno;
2170                 close_nointr_nofail(fd);
2171                 return r;
2172         }
2173
2174         *_f = f;
2175         *_final = id;
2176         return 0;
2177 }
2178
2179 static int merge_by_names(Unit **u, Set *names, const char *id) {
2180         char *k;
2181         int r;
2182
2183         assert(u);
2184         assert(*u);
2185         assert(names);
2186
2187         /* Let's try to add in all symlink names we found */
2188         while ((k = set_steal_first(names))) {
2189
2190                 /* First try to merge in the other name into our
2191                  * unit */
2192                 r = unit_merge_by_name(*u, k);
2193                 if (r < 0) {
2194                         Unit *other;
2195
2196                         /* Hmm, we couldn't merge the other unit into
2197                          * ours? Then let's try it the other way
2198                          * round */
2199
2200                         other = manager_get_unit((*u)->manager, k);
2201                         free(k);
2202
2203                         if (other) {
2204                                 r = unit_merge(other, *u);
2205                                 if (r >= 0) {
2206                                         *u = other;
2207                                         return merge_by_names(u, names, NULL);
2208                                 }
2209                         }
2210
2211                         return r;
2212                 }
2213
2214                 if (id == k)
2215                         unit_choose_id(*u, id);
2216
2217                 free(k);
2218         }
2219
2220         return 0;
2221 }
2222
2223 static int load_from_path(Unit *u, const char *path) {
2224         int r;
2225         Set *symlink_names;
2226         FILE *f = NULL;
2227         char *filename = NULL, *id = NULL;
2228         Unit *merged;
2229         struct stat st;
2230
2231         assert(u);
2232         assert(path);
2233
2234         symlink_names = set_new(string_hash_func, string_compare_func);
2235         if (!symlink_names)
2236                 return -ENOMEM;
2237
2238         if (path_is_absolute(path)) {
2239
2240                 filename = strdup(path);
2241                 if (!filename) {
2242                         r = -ENOMEM;
2243                         goto finish;
2244                 }
2245
2246                 r = open_follow(&filename, &f, symlink_names, &id);
2247                 if (r < 0) {
2248                         free(filename);
2249                         filename = NULL;
2250
2251                         if (r != -ENOENT)
2252                                 goto finish;
2253                 }
2254
2255         } else  {
2256                 char **p;
2257
2258                 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
2259
2260                         /* Instead of opening the path right away, we manually
2261                          * follow all symlinks and add their name to our unit
2262                          * name set while doing so */
2263                         filename = path_make_absolute(path, *p);
2264                         if (!filename) {
2265                                 r = -ENOMEM;
2266                                 goto finish;
2267                         }
2268
2269                         if (u->manager->unit_path_cache &&
2270                             !set_get(u->manager->unit_path_cache, filename))
2271                                 r = -ENOENT;
2272                         else
2273                                 r = open_follow(&filename, &f, symlink_names, &id);
2274
2275                         if (r < 0) {
2276                                 free(filename);
2277                                 filename = NULL;
2278
2279                                 if (r != -ENOENT)
2280                                         goto finish;
2281
2282                                 /* Empty the symlink names for the next run */
2283                                 set_clear_free(symlink_names);
2284                                 continue;
2285                         }
2286
2287                         break;
2288                 }
2289         }
2290
2291         if (!filename) {
2292                 /* Hmm, no suitable file found? */
2293                 r = 0;
2294                 goto finish;
2295         }
2296
2297         merged = u;
2298         r = merge_by_names(&merged, symlink_names, id);
2299         if (r < 0)
2300                 goto finish;
2301
2302         if (merged != u) {
2303                 u->load_state = UNIT_MERGED;
2304                 r = 0;
2305                 goto finish;
2306         }
2307
2308         if (fstat(fileno(f), &st) < 0) {
2309                 r = -errno;
2310                 goto finish;
2311         }
2312
2313         if (null_or_empty(&st))
2314                 u->load_state = UNIT_MASKED;
2315         else {
2316                 /* Now, parse the file contents */
2317                 r = config_parse(u->id, filename, f, UNIT_VTABLE(u)->sections,
2318                                  config_item_perf_lookup,
2319                                  (void*) load_fragment_gperf_lookup, false, true, u);
2320                 if (r < 0)
2321                         goto finish;
2322
2323                 u->load_state = UNIT_LOADED;
2324         }
2325
2326         free(u->fragment_path);
2327         u->fragment_path = filename;
2328         filename = NULL;
2329
2330         u->fragment_mtime = timespec_load(&st.st_mtim);
2331
2332         if (u->source_path) {
2333                 if (stat(u->source_path, &st) >= 0)
2334                         u->source_mtime = timespec_load(&st.st_mtim);
2335                 else
2336                         u->source_mtime = 0;
2337         }
2338
2339         r = 0;
2340
2341 finish:
2342         set_free_free(symlink_names);
2343         free(filename);
2344
2345         if (f)
2346                 fclose(f);
2347
2348         return r;
2349 }
2350
2351 int unit_load_fragment(Unit *u) {
2352         int r;
2353         Iterator i;
2354         const char *t;
2355
2356         assert(u);
2357         assert(u->load_state == UNIT_STUB);
2358         assert(u->id);
2359
2360         /* First, try to find the unit under its id. We always look
2361          * for unit files in the default directories, to make it easy
2362          * to override things by placing things in /etc/systemd/system */
2363         r = load_from_path(u, u->id);
2364         if (r < 0)
2365                 return r;
2366
2367         /* Try to find an alias we can load this with */
2368         if (u->load_state == UNIT_STUB)
2369                 SET_FOREACH(t, u->names, i) {
2370
2371                         if (t == u->id)
2372                                 continue;
2373
2374                         r = load_from_path(u, t);
2375                         if (r < 0)
2376                                 return r;
2377
2378                         if (u->load_state != UNIT_STUB)
2379                                 break;
2380                 }
2381
2382         /* And now, try looking for it under the suggested (originally linked) path */
2383         if (u->load_state == UNIT_STUB && u->fragment_path) {
2384
2385                 r = load_from_path(u, u->fragment_path);
2386                 if (r < 0)
2387                         return r;
2388
2389                 if (u->load_state == UNIT_STUB) {
2390                         /* Hmm, this didn't work? Then let's get rid
2391                          * of the fragment path stored for us, so that
2392                          * we don't point to an invalid location. */
2393                         free(u->fragment_path);
2394                         u->fragment_path = NULL;
2395                 }
2396         }
2397
2398         /* Look for a template */
2399         if (u->load_state == UNIT_STUB && u->instance) {
2400                 char *k;
2401
2402                 k = unit_name_template(u->id);
2403                 if (!k)
2404                         return -ENOMEM;
2405
2406                 r = load_from_path(u, k);
2407                 free(k);
2408
2409                 if (r < 0)
2410                         return r;
2411
2412                 if (u->load_state == UNIT_STUB)
2413                         SET_FOREACH(t, u->names, i) {
2414
2415                                 if (t == u->id)
2416                                         continue;
2417
2418                                 k = unit_name_template(t);
2419                                 if (!k)
2420                                         return -ENOMEM;
2421
2422                                 r = load_from_path(u, k);
2423                                 free(k);
2424
2425                                 if (r < 0)
2426                                         return r;
2427
2428                                 if (u->load_state != UNIT_STUB)
2429                                         break;
2430                         }
2431         }
2432
2433         return 0;
2434 }
2435
2436 void unit_dump_config_items(FILE *f) {
2437         static const struct {
2438                 const ConfigParserCallback callback;
2439                 const char *rvalue;
2440         } table[] = {
2441                 { config_parse_int,                   "INTEGER" },
2442                 { config_parse_unsigned,              "UNSIGNED" },
2443                 { config_parse_bytes_size,            "SIZE" },
2444                 { config_parse_bool,                  "BOOLEAN" },
2445                 { config_parse_string,                "STRING" },
2446                 { config_parse_path,                  "PATH" },
2447                 { config_parse_unit_path_printf,      "PATH" },
2448                 { config_parse_strv,                  "STRING [...]" },
2449                 { config_parse_exec_nice,             "NICE" },
2450                 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
2451                 { config_parse_exec_io_class,         "IOCLASS" },
2452                 { config_parse_exec_io_priority,      "IOPRIORITY" },
2453                 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
2454                 { config_parse_exec_cpu_sched_prio,   "CPUSCHEDPRIO" },
2455                 { config_parse_exec_cpu_affinity,     "CPUAFFINITY" },
2456                 { config_parse_mode,                  "MODE" },
2457                 { config_parse_unit_env_file,         "FILE" },
2458                 { config_parse_output,                "OUTPUT" },
2459                 { config_parse_input,                 "INPUT" },
2460                 { config_parse_facility,              "FACILITY" },
2461                 { config_parse_level,                 "LEVEL" },
2462                 { config_parse_exec_capabilities,     "CAPABILITIES" },
2463                 { config_parse_exec_secure_bits,      "SECUREBITS" },
2464                 { config_parse_bounding_set,          "BOUNDINGSET" },
2465                 { config_parse_limit,                 "LIMIT" },
2466                 { config_parse_unit_cgroup,           "CGROUP [...]" },
2467                 { config_parse_unit_deps,             "UNIT [...]" },
2468                 { config_parse_exec,                  "PATH [ARGUMENT [...]]" },
2469                 { config_parse_service_type,          "SERVICETYPE" },
2470                 { config_parse_service_restart,       "SERVICERESTART" },
2471 #ifdef HAVE_SYSV_COMPAT
2472                 { config_parse_sysv_priority,         "SYSVPRIORITY" },
2473 #else
2474                 { config_parse_warn_compat,           "NOTSUPPORTED" },
2475 #endif
2476                 { config_parse_kill_mode,             "KILLMODE" },
2477                 { config_parse_kill_signal,           "SIGNAL" },
2478                 { config_parse_socket_listen,         "SOCKET [...]" },
2479                 { config_parse_socket_bind,           "SOCKETBIND" },
2480                 { config_parse_socket_bindtodevice,   "NETWORKINTERFACE" },
2481                 { config_parse_sec,                   "SECONDS" },
2482                 { config_parse_nsec,                  "NANOSECONDS" },
2483                 { config_parse_path_strv,             "PATH [...]" },
2484                 { config_parse_unit_requires_mounts_for, "PATH [...]" },
2485                 { config_parse_exec_mount_flags,      "MOUNTFLAG [...]" },
2486                 { config_parse_unit_string_printf,    "STRING" },
2487                 { config_parse_trigger_unit,          "UNIT" },
2488                 { config_parse_timer,                 "TIMER" },
2489                 { config_parse_path_spec,             "PATH" },
2490                 { config_parse_notify_access,         "ACCESS" },
2491                 { config_parse_ip_tos,                "TOS" },
2492                 { config_parse_unit_condition_path,   "CONDITION" },
2493                 { config_parse_unit_condition_string, "CONDITION" },
2494                 { config_parse_unit_condition_null,   "CONDITION" },
2495                 { config_parse_unit_slice,            "SLICE" },
2496         };
2497
2498         const char *prev = NULL;
2499         const char *i;
2500
2501         assert(f);
2502
2503         NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
2504                 const char *rvalue = "OTHER", *lvalue;
2505                 unsigned j;
2506                 size_t prefix_len;
2507                 const char *dot;
2508                 const ConfigPerfItem *p;
2509
2510                 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
2511
2512                 dot = strchr(i, '.');
2513                 lvalue = dot ? dot + 1 : i;
2514                 prefix_len = dot-i;
2515
2516                 if (dot)
2517                         if (!prev || !strneq(prev, i, prefix_len+1)) {
2518                                 if (prev)
2519                                         fputc('\n', f);
2520
2521                                 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
2522                         }
2523
2524                 for (j = 0; j < ELEMENTSOF(table); j++)
2525                         if (p->parse == table[j].callback) {
2526                                 rvalue = table[j].rvalue;
2527                                 break;
2528                         }
2529
2530                 fprintf(f, "%s=%s\n", lvalue, rvalue);
2531                 prev = i;
2532         }
2533 }