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