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