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