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