chiark / gitweb /
Move bus_error to dbus-common and remove bus_error_message_or_strerror
[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                 char _cleanup_free_ *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                 char _cleanup_free_ *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                 char _cleanup_free_ *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                 char _cleanup_free_ *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                 char _cleanup_free_ *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_timer_unit(const char *unit,
1258                             const char *filename,
1259                             unsigned line,
1260                             const char *section,
1261                             const char *lvalue,
1262                             int ltype,
1263                             const char *rvalue,
1264                             void *data,
1265                             void *userdata) {
1266
1267         Timer *t = data;
1268         int r;
1269         DBusError error;
1270         Unit *u;
1271         _cleanup_free_ char *p = NULL;
1272
1273         assert(filename);
1274         assert(lvalue);
1275         assert(rvalue);
1276         assert(data);
1277
1278         dbus_error_init(&error);
1279
1280         p = unit_name_printf(UNIT(t), rvalue);
1281         if (!p)
1282                 return log_oom();
1283
1284         if (endswith(p, ".timer")) {
1285                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1286                            "Unit cannot be of type timer, ignoring: %s", rvalue);
1287                 return 0;
1288         }
1289
1290         r = manager_load_unit(UNIT(t)->manager, p, NULL, NULL, &u);
1291         if (r < 0) {
1292                 log_syntax(unit, LOG_ERR, filename, line, -r,
1293                            "Failed to load unit %s, ignoring: %s",
1294                            rvalue, bus_error(&error, r));
1295                 dbus_error_free(&error);
1296                 return 0;
1297         }
1298
1299         unit_ref_set(&t->unit, u);
1300
1301         return 0;
1302 }
1303
1304 int config_parse_path_spec(const char *unit,
1305                            const char *filename,
1306                            unsigned line,
1307                            const char *section,
1308                            const char *lvalue,
1309                            int ltype,
1310                            const char *rvalue,
1311                            void *data,
1312                            void *userdata) {
1313
1314         Path *p = data;
1315         PathSpec *s;
1316         PathType b;
1317         char _cleanup_free_ *k = NULL;
1318
1319         assert(filename);
1320         assert(lvalue);
1321         assert(rvalue);
1322         assert(data);
1323
1324         if (isempty(rvalue)) {
1325                 /* Empty assignment clears list */
1326                 path_free_specs(p);
1327                 return 0;
1328         }
1329
1330         b = path_type_from_string(lvalue);
1331         if (b < 0) {
1332                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1333                            "Failed to parse path type, ignoring: %s", lvalue);
1334                 return 0;
1335         }
1336
1337         k = unit_full_printf(UNIT(p), rvalue);
1338         if (!k) {
1339                 k = strdup(rvalue);
1340                 if (!k)
1341                         return log_oom();
1342                 else
1343                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1344                                    "Failed to resolve unit specifiers on %s. Ignoring.",
1345                                    rvalue);
1346         }
1347
1348         if (!path_is_absolute(k)) {
1349                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1350                            "Path is not absolute, ignoring: %s", k);
1351                 return 0;
1352         }
1353
1354         s = new0(PathSpec, 1);
1355         if (!s)
1356                 return log_oom();
1357
1358         s->path = path_kill_slashes(k);
1359         k = NULL;
1360         s->type = b;
1361         s->inotify_fd = -1;
1362
1363         LIST_PREPEND(PathSpec, spec, p->specs, s);
1364
1365         return 0;
1366 }
1367
1368 int config_parse_path_unit(const char *unit,
1369                            const char *filename,
1370                            unsigned line,
1371                            const char *section,
1372                            const char *lvalue,
1373                            int ltype,
1374                            const char *rvalue,
1375                            void *data,
1376                            void *userdata) {
1377
1378         Path *t = data;
1379         int r;
1380         DBusError error;
1381         Unit *u;
1382         _cleanup_free_ char *p = NULL;
1383
1384         assert(filename);
1385         assert(lvalue);
1386         assert(rvalue);
1387         assert(data);
1388
1389         dbus_error_init(&error);
1390
1391         p = unit_name_printf(UNIT(t), rvalue);
1392         if (!p)
1393                 return log_oom();
1394
1395         if (endswith(p, ".path")) {
1396                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1397                            "Unit cannot be of type path, ignoring: %s", p);
1398                 return 0;
1399         }
1400
1401         r = manager_load_unit(UNIT(t)->manager, p, NULL, &error, &u);
1402         if (r < 0) {
1403                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1404                            "Failed to load unit %s, ignoring: %s",
1405                            p, bus_error(&error, r));
1406                 dbus_error_free(&error);
1407                 return 0;
1408         }
1409
1410         unit_ref_set(&t->unit, u);
1411
1412         return 0;
1413 }
1414
1415 int config_parse_socket_service(const char *unit,
1416                                 const char *filename,
1417                                 unsigned line,
1418                                 const char *section,
1419                                 const char *lvalue,
1420                                 int ltype,
1421                                 const char *rvalue,
1422                                 void *data,
1423                                 void *userdata) {
1424
1425         Socket *s = data;
1426         int r;
1427         DBusError error;
1428         Unit *x;
1429         _cleanup_free_ char *p = NULL;
1430
1431         assert(filename);
1432         assert(lvalue);
1433         assert(rvalue);
1434         assert(data);
1435
1436         dbus_error_init(&error);
1437
1438         p = unit_name_printf(UNIT(s), rvalue);
1439         if (!p)
1440                 return log_oom();
1441
1442         if (!endswith(p, ".service")) {
1443                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1444                            "Unit must be of type service, ignoring: %s", rvalue);
1445                 return 0;
1446         }
1447
1448         r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
1449         if (r < 0) {
1450                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1451                            "Failed to load unit %s, ignoring: %s",
1452                            rvalue, bus_error(&error, r));
1453                 dbus_error_free(&error);
1454                 return 0;
1455         }
1456
1457         unit_ref_set(&s->service, x);
1458
1459         return 0;
1460 }
1461
1462 int config_parse_service_sockets(const char *unit,
1463                                  const char *filename,
1464                                  unsigned line,
1465                                  const char *section,
1466                                  const char *lvalue,
1467                                  int ltype,
1468                                  const char *rvalue,
1469                                  void *data,
1470                                  void *userdata) {
1471
1472         Service *s = data;
1473         int r;
1474         char *state, *w;
1475         size_t l;
1476
1477         assert(filename);
1478         assert(lvalue);
1479         assert(rvalue);
1480         assert(data);
1481
1482         FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1483                 char _cleanup_free_ *t = NULL, *k = NULL;
1484
1485                 t = strndup(w, l);
1486                 if (!t)
1487                         return log_oom();
1488
1489                 k = unit_name_printf(UNIT(s), t);
1490                 if (!k)
1491                         return log_oom();
1492
1493                 if (!endswith(k, ".socket")) {
1494                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1495                                    "Unit must be of type socket, ignoring: %s", k);
1496                         continue;
1497                 }
1498
1499                 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true);
1500                 if (r < 0)
1501                         log_syntax(unit, LOG_ERR, filename, line, -r,
1502                                    "Failed to add dependency on %s, ignoring: %s",
1503                                    k, strerror(-r));
1504
1505                 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true);
1506                 if (r < 0)
1507                         return r;
1508         }
1509
1510         return 0;
1511 }
1512
1513 int config_parse_service_timeout(const char *unit,
1514                                  const char *filename,
1515                                  unsigned line,
1516                                  const char *section,
1517                                  const char *lvalue,
1518                                  int ltype,
1519                                  const char *rvalue,
1520                                  void *data,
1521                                  void *userdata) {
1522
1523         Service *s = userdata;
1524         int r;
1525
1526         assert(filename);
1527         assert(lvalue);
1528         assert(rvalue);
1529         assert(s);
1530
1531         r = config_parse_sec(unit, filename, line, section, lvalue, ltype,
1532                              rvalue, data, userdata);
1533         if (r < 0)
1534                 return r;
1535
1536         if (streq(lvalue, "TimeoutSec")) {
1537                 s->start_timeout_defined = true;
1538                 s->timeout_stop_usec = s->timeout_start_usec;
1539         } else if (streq(lvalue, "TimeoutStartSec"))
1540                 s->start_timeout_defined = true;
1541
1542         return 0;
1543 }
1544
1545 int config_parse_unit_env_file(const char *unit,
1546                                const char *filename,
1547                                unsigned line,
1548                                const char *section,
1549                                const char *lvalue,
1550                                int ltype,
1551                                const char *rvalue,
1552                                void *data,
1553                                void *userdata) {
1554
1555         char ***env = data;
1556         Unit *u = userdata;
1557         _cleanup_free_ char *s = NULL;
1558         int r;
1559
1560         assert(filename);
1561         assert(lvalue);
1562         assert(rvalue);
1563         assert(data);
1564
1565         if (isempty(rvalue)) {
1566                 /* Empty assignment frees the list */
1567                 strv_free(*env);
1568                 *env = NULL;
1569                 return 0;
1570         }
1571
1572         s = unit_full_printf(u, rvalue);
1573         if (!s)
1574                 return log_oom();
1575
1576         if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1577                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1578                            "Path '%s' is not absolute, ignoring.", s);
1579                 return 0;
1580         }
1581
1582         r = strv_extend(env, s);
1583         if (r < 0)
1584                 return log_oom();
1585
1586         return 0;
1587 }
1588
1589 int config_parse_environ(const char *unit,
1590                          const char *filename,
1591                          unsigned line,
1592                          const char *section,
1593                          const char *lvalue,
1594                          int ltype,
1595                          const char *rvalue,
1596                          void *data,
1597                          void *userdata) {
1598
1599         Unit *u = userdata;
1600         char*** env = data, *w, *state;
1601         size_t l;
1602         _cleanup_free_ char *k = NULL;
1603
1604         assert(filename);
1605         assert(lvalue);
1606         assert(rvalue);
1607         assert(u);
1608
1609         if (isempty(rvalue)) {
1610                 /* Empty assignment resets the list */
1611                 strv_free(*env);
1612                 *env = NULL;
1613                 return 0;
1614         }
1615
1616         k = unit_full_printf(u, rvalue);
1617         if (!k)
1618                 return log_oom();
1619
1620         FOREACH_WORD_QUOTED(w, l, k, state) {
1621                 _cleanup_free_ char *n;
1622                 char **x;
1623
1624                 n = cunescape_length(w, l);
1625                 if (!n)
1626                         return log_oom();
1627
1628                 if (!env_assignment_is_valid(n)) {
1629                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1630                                    "Invalid environment assignment, ignoring: %s", rvalue);
1631                         continue;
1632                 }
1633
1634                 x = strv_env_set(*env, n);
1635                 if (!x)
1636                         return log_oom();
1637
1638                 strv_free(*env);
1639                 *env = x;
1640         }
1641
1642         return 0;
1643 }
1644
1645 int config_parse_ip_tos(const char *unit,
1646                         const char *filename,
1647                         unsigned line,
1648                         const char *section,
1649                         const char *lvalue,
1650                         int ltype,
1651                         const char *rvalue,
1652                         void *data,
1653                         void *userdata) {
1654
1655         int *ip_tos = data, x;
1656
1657         assert(filename);
1658         assert(lvalue);
1659         assert(rvalue);
1660         assert(data);
1661
1662         x = ip_tos_from_string(rvalue);
1663         if (x < 0) {
1664                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1665                            "Failed to parse IP TOS value, ignoring: %s", rvalue);
1666                 return 0;
1667         }
1668
1669         *ip_tos = x;
1670         return 0;
1671 }
1672
1673 int config_parse_unit_condition_path(const char *unit,
1674                                      const char *filename,
1675                                      unsigned line,
1676                                      const char *section,
1677                                      const char *lvalue,
1678                                      int ltype,
1679                                      const char *rvalue,
1680                                      void *data,
1681                                      void *userdata) {
1682
1683         ConditionType cond = ltype;
1684         Unit *u = data;
1685         bool trigger, negate;
1686         Condition *c;
1687         _cleanup_free_ char *p = NULL;
1688
1689         assert(filename);
1690         assert(lvalue);
1691         assert(rvalue);
1692         assert(data);
1693
1694         if (isempty(rvalue)) {
1695                 /* Empty assignment resets the list */
1696                 condition_free_list(u->conditions);
1697                 u->conditions = NULL;
1698                 return 0;
1699         }
1700
1701         trigger = rvalue[0] == '|';
1702         if (trigger)
1703                 rvalue++;
1704
1705         negate = rvalue[0] == '!';
1706         if (negate)
1707                 rvalue++;
1708
1709         p = unit_full_printf(u, rvalue);
1710         if (!p)
1711                 return log_oom();
1712
1713         if (!path_is_absolute(p)) {
1714                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1715                            "Path in condition not absolute, ignoring: %s", p);
1716                 return 0;
1717         }
1718
1719         c = condition_new(cond, p, trigger, negate);
1720         if (!c)
1721                 return log_oom();
1722
1723         LIST_PREPEND(Condition, conditions, u->conditions, c);
1724         return 0;
1725 }
1726
1727 int config_parse_unit_condition_string(const char *unit,
1728                                        const char *filename,
1729                                        unsigned line,
1730                                        const char *section,
1731                                        const char *lvalue,
1732                                        int ltype,
1733                                        const char *rvalue,
1734                                        void *data,
1735                                        void *userdata) {
1736
1737         ConditionType cond = ltype;
1738         Unit *u = data;
1739         bool trigger, negate;
1740         Condition *c;
1741         _cleanup_free_ char *s = NULL;
1742
1743         assert(filename);
1744         assert(lvalue);
1745         assert(rvalue);
1746         assert(data);
1747
1748         if (isempty(rvalue)) {
1749                 /* Empty assignment resets the list */
1750                 condition_free_list(u->conditions);
1751                 u->conditions = NULL;
1752                 return 0;
1753         }
1754
1755         trigger = rvalue[0] == '|';
1756         if (trigger)
1757                 rvalue++;
1758
1759         negate = rvalue[0] == '!';
1760         if (negate)
1761                 rvalue++;
1762
1763         s = unit_full_printf(u, rvalue);
1764         if (!s)
1765                 return log_oom();
1766
1767         c = condition_new(cond, s, trigger, negate);
1768         if (!c)
1769                 return log_oom();
1770
1771         LIST_PREPEND(Condition, conditions, u->conditions, c);
1772         return 0;
1773 }
1774
1775 int config_parse_unit_condition_null(const char *unit,
1776                                      const char *filename,
1777                                      unsigned line,
1778                                      const char *section,
1779                                      const char *lvalue,
1780                                      int ltype,
1781                                      const char *rvalue,
1782                                      void *data,
1783                                      void *userdata) {
1784
1785         Unit *u = data;
1786         Condition *c;
1787         bool trigger, negate;
1788         int b;
1789
1790         assert(filename);
1791         assert(lvalue);
1792         assert(rvalue);
1793         assert(data);
1794
1795         if (isempty(rvalue)) {
1796                 /* Empty assignment resets the list */
1797                 condition_free_list(u->conditions);
1798                 u->conditions = NULL;
1799                 return 0;
1800         }
1801
1802         trigger = rvalue[0] == '|';
1803         if (trigger)
1804                 rvalue++;
1805
1806         negate = rvalue[0] == '!';
1807         if (negate)
1808                 rvalue++;
1809
1810         b = parse_boolean(rvalue);
1811         if (b < 0) {
1812                 log_syntax(unit, LOG_ERR, filename, line, -b,
1813                            "Failed to parse boolean value in condition, ignoring: %s",
1814                            rvalue);
1815                 return 0;
1816         }
1817
1818         if (!b)
1819                 negate = !negate;
1820
1821         c = condition_new(CONDITION_NULL, NULL, trigger, negate);
1822         if (!c)
1823                 return log_oom();
1824
1825         LIST_PREPEND(Condition, conditions, u->conditions, c);
1826         return 0;
1827 }
1828
1829 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
1830 DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
1831
1832 int config_parse_unit_cgroup_attr(const char *unit,
1833                                   const char *filename,
1834                                   unsigned line,
1835                                   const char *section,
1836                                   const char *lvalue,
1837                                   int ltype,
1838                                   const char *rvalue,
1839                                   void *data,
1840                                   void *userdata) {
1841
1842         Unit *u = data;
1843         size_t a, b;
1844         _cleanup_free_ char *n = NULL, *v = NULL;
1845         const CGroupSemantics *s;
1846         int r;
1847
1848         assert(filename);
1849         assert(lvalue);
1850         assert(rvalue);
1851         assert(data);
1852
1853         if (isempty(rvalue)) {
1854                 /* Empty assignment clears the list */
1855                 cgroup_attribute_free_list(u->cgroup_attributes);
1856                 u->cgroup_attributes = NULL;
1857                 return 0;
1858         }
1859
1860         a = strcspn(rvalue, WHITESPACE);
1861         b = strspn(rvalue + a, WHITESPACE);
1862         if (a <= 0 || b <= 0) {
1863                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1864                            "Failed to parse cgroup attribute value, ignoring: %s",
1865                            rvalue);
1866                 return 0;
1867         }
1868
1869         n = strndup(rvalue, a);
1870         if (!n)
1871                 return log_oom();
1872
1873         r = cgroup_semantics_find(NULL, n, rvalue + a + b, &v, &s);
1874         if (r < 0) {
1875                 log_syntax(unit, LOG_ERR, filename, line, -r,
1876                            "Failed to parse cgroup attribute value, ignoring: %s",
1877                            rvalue);
1878                 return 0;
1879         }
1880
1881         r = unit_add_cgroup_attribute(u, s, NULL, n, v ? v : rvalue + a + b, NULL);
1882         if (r < 0) {
1883                 log_syntax(unit, LOG_ERR, filename, line, -r,
1884                            "Failed to add cgroup attribute value, ignoring: %s", rvalue);
1885                 return 0;
1886         }
1887
1888         return 0;
1889 }
1890
1891 int config_parse_unit_cgroup_attr_pretty(const char *unit,
1892                                          const char *filename,
1893                                          unsigned line,
1894                                          const char *section,
1895                                          const char *lvalue,
1896                                          int ltype,
1897                                          const char *rvalue,
1898                                          void *data,
1899                                          void *userdata) {
1900
1901         Unit *u = data;
1902         _cleanup_free_ char *v = NULL;
1903         const CGroupSemantics *s;
1904         int r;
1905
1906         assert(filename);
1907         assert(lvalue);
1908         assert(rvalue);
1909         assert(data);
1910
1911         r = cgroup_semantics_find(NULL, lvalue, rvalue, &v, &s);
1912         if (r < 0) {
1913                 log_syntax(unit, LOG_ERR, filename, line, -r,
1914                            "Failed to parse cgroup attribute value, ignoring: %s",
1915                            rvalue);
1916                 return 0;
1917         } else if (r == 0) {
1918                 log_syntax(unit, LOG_ERR, filename, line, ENOTSUP,
1919                            "Unknown or unsupported cgroup attribute %s, ignoring: %s",
1920                            lvalue, rvalue);
1921                 return 0;
1922         }
1923
1924         r = unit_add_cgroup_attribute(u, s, NULL, NULL, v, NULL);
1925         if (r < 0) {
1926                 log_syntax(unit, LOG_ERR, filename, line, -r,
1927                            "Failed to add cgroup attribute value, ignoring: %s", rvalue);
1928                 return 0;
1929         }
1930
1931         return 0;
1932 }
1933
1934 int config_parse_unit_requires_mounts_for(const char *unit,
1935                                           const char *filename,
1936                                           unsigned line,
1937                                           const char *section,
1938                                           const char *lvalue,
1939                                           int ltype,
1940                                           const char *rvalue,
1941                                           void *data,
1942                                           void *userdata) {
1943
1944         Unit *u = userdata;
1945         int r;
1946         bool empty_before;
1947
1948         assert(filename);
1949         assert(lvalue);
1950         assert(rvalue);
1951         assert(data);
1952
1953         empty_before = !u->requires_mounts_for;
1954
1955         r = config_parse_path_strv(unit, filename, line, section, lvalue, ltype,
1956                                    rvalue, data, userdata);
1957
1958         /* Make it easy to find units with requires_mounts set */
1959         if (empty_before && u->requires_mounts_for)
1960                 LIST_PREPEND(Unit, has_requires_mounts_for, u->manager->has_requires_mounts_for, u);
1961
1962         return r;
1963 }
1964
1965 int config_parse_documentation(const char *unit,
1966                                const char *filename,
1967                                unsigned line,
1968                                const char *section,
1969                                const char *lvalue,
1970                                int ltype,
1971                                const char *rvalue,
1972                                void *data,
1973                                void *userdata) {
1974
1975         Unit *u = userdata;
1976         int r;
1977         char **a, **b;
1978
1979         assert(filename);
1980         assert(lvalue);
1981         assert(rvalue);
1982         assert(u);
1983
1984         if (isempty(rvalue)) {
1985                 /* Empty assignment resets the list */
1986                 strv_free(u->documentation);
1987                 u->documentation = NULL;
1988                 return 0;
1989         }
1990
1991         r = config_parse_unit_strv_printf(unit, filename, line, section, lvalue, ltype,
1992                                           rvalue, data, userdata);
1993         if (r < 0)
1994                 return r;
1995
1996         for (a = b = u->documentation; a && *a; a++) {
1997
1998                 if (is_valid_documentation_url(*a))
1999                         *(b++) = *a;
2000                 else {
2001                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2002                                    "Invalid URL, ignoring: %s", *a);
2003                         free(*a);
2004                 }
2005         }
2006         *b = NULL;
2007
2008         return r;
2009 }
2010
2011 static void syscall_set(uint32_t *p, int nr) {
2012         nr = SYSCALL_TO_INDEX(nr);
2013         p[nr >> 4] |= 1 << (nr & 31);
2014 }
2015
2016 static void syscall_unset(uint32_t *p, int nr) {
2017         nr = SYSCALL_TO_INDEX(nr);
2018         p[nr >> 4] &= ~(1 << (nr & 31));
2019 }
2020
2021 int config_parse_syscall_filter(const char *unit,
2022                                 const char *filename,
2023                                 unsigned line,
2024                                 const char *section,
2025                                 const char *lvalue,
2026                                 int ltype,
2027                                 const char *rvalue,
2028                                 void *data,
2029                                 void *userdata) {
2030
2031         ExecContext *c = data;
2032         Unit *u = userdata;
2033         bool invert = false;
2034         char *w;
2035         size_t l;
2036         char *state;
2037
2038         assert(filename);
2039         assert(lvalue);
2040         assert(rvalue);
2041         assert(u);
2042
2043         if (isempty(rvalue)) {
2044                 /* Empty assignment resets the list */
2045                 free(c->syscall_filter);
2046                 c->syscall_filter = NULL;
2047                 return 0;
2048         }
2049
2050         if (rvalue[0] == '~') {
2051                 invert = true;
2052                 rvalue++;
2053         }
2054
2055         if (!c->syscall_filter) {
2056                 size_t n;
2057
2058                 n = (syscall_max() + 31) >> 4;
2059                 c->syscall_filter = new(uint32_t, n);
2060                 if (!c->syscall_filter)
2061                         return log_oom();
2062
2063                 memset(c->syscall_filter, invert ? 0xFF : 0, n * sizeof(uint32_t));
2064
2065                 /* Add these by default */
2066                 syscall_set(c->syscall_filter, __NR_execve);
2067                 syscall_set(c->syscall_filter, __NR_rt_sigreturn);
2068 #ifdef __NR_sigreturn
2069                 syscall_set(c->syscall_filter, __NR_sigreturn);
2070 #endif
2071                 syscall_set(c->syscall_filter, __NR_exit_group);
2072                 syscall_set(c->syscall_filter, __NR_exit);
2073         }
2074
2075         FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2076                 int id;
2077                 char _cleanup_free_ *t = NULL;
2078
2079                 t = strndup(w, l);
2080                 if (!t)
2081                         return log_oom();
2082
2083                 id = syscall_from_name(t);
2084                 if (id < 0)  {
2085                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2086                                    "Failed to parse syscall, ignoring: %s", t);
2087                         continue;
2088                 }
2089
2090                 if (invert)
2091                         syscall_unset(c->syscall_filter, id);
2092                 else
2093                         syscall_set(c->syscall_filter, id);
2094         }
2095
2096         c->no_new_privileges = true;
2097
2098         return 0;
2099 }
2100
2101 #define FOLLOW_MAX 8
2102
2103 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
2104         unsigned c = 0;
2105         int fd, r;
2106         FILE *f;
2107         char *id = NULL;
2108
2109         assert(filename);
2110         assert(*filename);
2111         assert(_f);
2112         assert(names);
2113
2114         /* This will update the filename pointer if the loaded file is
2115          * reached by a symlink. The old string will be freed. */
2116
2117         for (;;) {
2118                 char *target, *name;
2119
2120                 if (c++ >= FOLLOW_MAX)
2121                         return -ELOOP;
2122
2123                 path_kill_slashes(*filename);
2124
2125                 /* Add the file name we are currently looking at to
2126                  * the names of this unit, but only if it is a valid
2127                  * unit name. */
2128                 name = path_get_file_name(*filename);
2129
2130                 if (unit_name_is_valid(name, true)) {
2131
2132                         id = set_get(names, name);
2133                         if (!id) {
2134                                 id = strdup(name);
2135                                 if (!id)
2136                                         return -ENOMEM;
2137
2138                                 r = set_put(names, id);
2139                                 if (r < 0) {
2140                                         free(id);
2141                                         return r;
2142                                 }
2143                         }
2144                 }
2145
2146                 /* Try to open the file name, but don't if its a symlink */
2147                 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
2148                 if (fd >= 0)
2149                         break;
2150
2151                 if (errno != ELOOP)
2152                         return -errno;
2153
2154                 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
2155                 r = readlink_and_make_absolute(*filename, &target);
2156                 if (r < 0)
2157                         return r;
2158
2159                 free(*filename);
2160                 *filename = target;
2161         }
2162
2163         f = fdopen(fd, "re");
2164         if (!f) {
2165                 r = -errno;
2166                 close_nointr_nofail(fd);
2167                 return r;
2168         }
2169
2170         *_f = f;
2171         *_final = id;
2172         return 0;
2173 }
2174
2175 static int merge_by_names(Unit **u, Set *names, const char *id) {
2176         char *k;
2177         int r;
2178
2179         assert(u);
2180         assert(*u);
2181         assert(names);
2182
2183         /* Let's try to add in all symlink names we found */
2184         while ((k = set_steal_first(names))) {
2185
2186                 /* First try to merge in the other name into our
2187                  * unit */
2188                 r = unit_merge_by_name(*u, k);
2189                 if (r < 0) {
2190                         Unit *other;
2191
2192                         /* Hmm, we couldn't merge the other unit into
2193                          * ours? Then let's try it the other way
2194                          * round */
2195
2196                         other = manager_get_unit((*u)->manager, k);
2197                         free(k);
2198
2199                         if (other) {
2200                                 r = unit_merge(other, *u);
2201                                 if (r >= 0) {
2202                                         *u = other;
2203                                         return merge_by_names(u, names, NULL);
2204                                 }
2205                         }
2206
2207                         return r;
2208                 }
2209
2210                 if (id == k)
2211                         unit_choose_id(*u, id);
2212
2213                 free(k);
2214         }
2215
2216         return 0;
2217 }
2218
2219 static int load_from_path(Unit *u, const char *path) {
2220         int r;
2221         Set *symlink_names;
2222         FILE *f = NULL;
2223         char *filename = NULL, *id = NULL;
2224         Unit *merged;
2225         struct stat st;
2226
2227         assert(u);
2228         assert(path);
2229
2230         symlink_names = set_new(string_hash_func, string_compare_func);
2231         if (!symlink_names)
2232                 return -ENOMEM;
2233
2234         if (path_is_absolute(path)) {
2235
2236                 filename = strdup(path);
2237                 if (!filename) {
2238                         r = -ENOMEM;
2239                         goto finish;
2240                 }
2241
2242                 r = open_follow(&filename, &f, symlink_names, &id);
2243                 if (r < 0) {
2244                         free(filename);
2245                         filename = NULL;
2246
2247                         if (r != -ENOENT)
2248                                 goto finish;
2249                 }
2250
2251         } else  {
2252                 char **p;
2253
2254                 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
2255
2256                         /* Instead of opening the path right away, we manually
2257                          * follow all symlinks and add their name to our unit
2258                          * name set while doing so */
2259                         filename = path_make_absolute(path, *p);
2260                         if (!filename) {
2261                                 r = -ENOMEM;
2262                                 goto finish;
2263                         }
2264
2265                         if (u->manager->unit_path_cache &&
2266                             !set_get(u->manager->unit_path_cache, filename))
2267                                 r = -ENOENT;
2268                         else
2269                                 r = open_follow(&filename, &f, symlink_names, &id);
2270
2271                         if (r < 0) {
2272                                 free(filename);
2273                                 filename = NULL;
2274
2275                                 if (r != -ENOENT)
2276                                         goto finish;
2277
2278                                 /* Empty the symlink names for the next run */
2279                                 set_clear_free(symlink_names);
2280                                 continue;
2281                         }
2282
2283                         break;
2284                 }
2285         }
2286
2287         if (!filename) {
2288                 /* Hmm, no suitable file found? */
2289                 r = 0;
2290                 goto finish;
2291         }
2292
2293         merged = u;
2294         r = merge_by_names(&merged, symlink_names, id);
2295         if (r < 0)
2296                 goto finish;
2297
2298         if (merged != u) {
2299                 u->load_state = UNIT_MERGED;
2300                 r = 0;
2301                 goto finish;
2302         }
2303
2304         if (fstat(fileno(f), &st) < 0) {
2305                 r = -errno;
2306                 goto finish;
2307         }
2308
2309         if (null_or_empty(&st))
2310                 u->load_state = UNIT_MASKED;
2311         else {
2312                 /* Now, parse the file contents */
2313                 r = config_parse(u->id, filename, f, UNIT_VTABLE(u)->sections,
2314                                  config_item_perf_lookup,
2315                                  (void*) load_fragment_gperf_lookup, false, u);
2316                 if (r < 0)
2317                         goto finish;
2318
2319                 u->load_state = UNIT_LOADED;
2320         }
2321
2322         free(u->fragment_path);
2323         u->fragment_path = filename;
2324         filename = NULL;
2325
2326         u->fragment_mtime = timespec_load(&st.st_mtim);
2327
2328         if (u->source_path) {
2329                 if (stat(u->source_path, &st) >= 0)
2330                         u->source_mtime = timespec_load(&st.st_mtim);
2331                 else
2332                         u->source_mtime = 0;
2333         }
2334
2335         r = 0;
2336
2337 finish:
2338         set_free_free(symlink_names);
2339         free(filename);
2340
2341         if (f)
2342                 fclose(f);
2343
2344         return r;
2345 }
2346
2347 int unit_load_fragment(Unit *u) {
2348         int r;
2349         Iterator i;
2350         const char *t;
2351
2352         assert(u);
2353         assert(u->load_state == UNIT_STUB);
2354         assert(u->id);
2355
2356         /* First, try to find the unit under its id. We always look
2357          * for unit files in the default directories, to make it easy
2358          * to override things by placing things in /etc/systemd/system */
2359         r = load_from_path(u, u->id);
2360         if (r < 0)
2361                 return r;
2362
2363         /* Try to find an alias we can load this with */
2364         if (u->load_state == UNIT_STUB)
2365                 SET_FOREACH(t, u->names, i) {
2366
2367                         if (t == u->id)
2368                                 continue;
2369
2370                         r = load_from_path(u, t);
2371                         if (r < 0)
2372                                 return r;
2373
2374                         if (u->load_state != UNIT_STUB)
2375                                 break;
2376                 }
2377
2378         /* And now, try looking for it under the suggested (originally linked) path */
2379         if (u->load_state == UNIT_STUB && u->fragment_path) {
2380
2381                 r = load_from_path(u, u->fragment_path);
2382                 if (r < 0)
2383                         return r;
2384
2385                 if (u->load_state == UNIT_STUB) {
2386                         /* Hmm, this didn't work? Then let's get rid
2387                          * of the fragment path stored for us, so that
2388                          * we don't point to an invalid location. */
2389                         free(u->fragment_path);
2390                         u->fragment_path = NULL;
2391                 }
2392         }
2393
2394         /* Look for a template */
2395         if (u->load_state == UNIT_STUB && u->instance) {
2396                 char *k;
2397
2398                 k = unit_name_template(u->id);
2399                 if (!k)
2400                         return -ENOMEM;
2401
2402                 r = load_from_path(u, k);
2403                 free(k);
2404
2405                 if (r < 0)
2406                         return r;
2407
2408                 if (u->load_state == UNIT_STUB)
2409                         SET_FOREACH(t, u->names, i) {
2410
2411                                 if (t == u->id)
2412                                         continue;
2413
2414                                 k = unit_name_template(t);
2415                                 if (!k)
2416                                         return -ENOMEM;
2417
2418                                 r = load_from_path(u, k);
2419                                 free(k);
2420
2421                                 if (r < 0)
2422                                         return r;
2423
2424                                 if (u->load_state != UNIT_STUB)
2425                                         break;
2426                         }
2427         }
2428
2429         return 0;
2430 }
2431
2432 void unit_dump_config_items(FILE *f) {
2433         static const struct {
2434                 const ConfigParserCallback callback;
2435                 const char *rvalue;
2436         } table[] = {
2437                 { config_parse_int,                   "INTEGER" },
2438                 { config_parse_unsigned,              "UNSIGNED" },
2439                 { config_parse_bytes_size,            "SIZE" },
2440                 { config_parse_bool,                  "BOOLEAN" },
2441                 { config_parse_string,                "STRING" },
2442                 { config_parse_path,                  "PATH" },
2443                 { config_parse_unit_path_printf,      "PATH" },
2444                 { config_parse_strv,                  "STRING [...]" },
2445                 { config_parse_exec_nice,             "NICE" },
2446                 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
2447                 { config_parse_exec_io_class,         "IOCLASS" },
2448                 { config_parse_exec_io_priority,      "IOPRIORITY" },
2449                 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
2450                 { config_parse_exec_cpu_sched_prio,   "CPUSCHEDPRIO" },
2451                 { config_parse_exec_cpu_affinity,     "CPUAFFINITY" },
2452                 { config_parse_mode,                  "MODE" },
2453                 { config_parse_unit_env_file,         "FILE" },
2454                 { config_parse_output,                "OUTPUT" },
2455                 { config_parse_input,                 "INPUT" },
2456                 { config_parse_facility,              "FACILITY" },
2457                 { config_parse_level,                 "LEVEL" },
2458                 { config_parse_exec_capabilities,     "CAPABILITIES" },
2459                 { config_parse_exec_secure_bits,      "SECUREBITS" },
2460                 { config_parse_bounding_set,          "BOUNDINGSET" },
2461                 { config_parse_limit,                 "LIMIT" },
2462                 { config_parse_unit_cgroup,           "CGROUP [...]" },
2463                 { config_parse_unit_deps,             "UNIT [...]" },
2464                 { config_parse_exec,                  "PATH [ARGUMENT [...]]" },
2465                 { config_parse_service_type,          "SERVICETYPE" },
2466                 { config_parse_service_restart,       "SERVICERESTART" },
2467 #ifdef HAVE_SYSV_COMPAT
2468                 { config_parse_sysv_priority,         "SYSVPRIORITY" },
2469 #else
2470                 { config_parse_warn_compat,           "NOTSUPPORTED" },
2471 #endif
2472                 { config_parse_kill_mode,             "KILLMODE" },
2473                 { config_parse_kill_signal,           "SIGNAL" },
2474                 { config_parse_socket_listen,         "SOCKET [...]" },
2475                 { config_parse_socket_bind,           "SOCKETBIND" },
2476                 { config_parse_socket_bindtodevice,   "NETWORKINTERFACE" },
2477                 { config_parse_sec,                   "SECONDS" },
2478                 { config_parse_nsec,                  "NANOSECONDS" },
2479                 { config_parse_path_strv,             "PATH [...]" },
2480                 { config_parse_unit_requires_mounts_for, "PATH [...]" },
2481                 { config_parse_exec_mount_flags,      "MOUNTFLAG [...]" },
2482                 { config_parse_unit_string_printf,    "STRING" },
2483                 { config_parse_timer,                 "TIMER" },
2484                 { config_parse_timer_unit,            "NAME" },
2485                 { config_parse_path_spec,             "PATH" },
2486                 { config_parse_path_unit,             "UNIT" },
2487                 { config_parse_notify_access,         "ACCESS" },
2488                 { config_parse_ip_tos,                "TOS" },
2489                 { config_parse_unit_condition_path,   "CONDITION" },
2490                 { config_parse_unit_condition_string, "CONDITION" },
2491                 { config_parse_unit_condition_null,   "CONDITION" },
2492         };
2493
2494         const char *prev = NULL;
2495         const char *i;
2496
2497         assert(f);
2498
2499         NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
2500                 const char *rvalue = "OTHER", *lvalue;
2501                 unsigned j;
2502                 size_t prefix_len;
2503                 const char *dot;
2504                 const ConfigPerfItem *p;
2505
2506                 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
2507
2508                 dot = strchr(i, '.');
2509                 lvalue = dot ? dot + 1 : i;
2510                 prefix_len = dot-i;
2511
2512                 if (dot)
2513                         if (!prev || !strneq(prev, i, prefix_len+1)) {
2514                                 if (prev)
2515                                         fputc('\n', f);
2516
2517                                 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
2518                         }
2519
2520                 for (j = 0; j < ELEMENTSOF(table); j++)
2521                         if (p->parse == table[j].callback) {
2522                                 rvalue = table[j].rvalue;
2523                                 break;
2524                         }
2525
2526                 fprintf(f, "%s=%s\n", lvalue, rvalue);
2527                 prev = i;
2528         }
2529 }