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