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