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