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