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