chiark / gitweb /
6933e1a21ecca04111e39ddcb08cbb764a45b03f
[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 _cleanup_free_ *t = NULL, *k = NULL;
90                 int r;
91
92                 t = strndup(w, l);
93                 if (!t)
94                         return -ENOMEM;
95
96                 k = unit_name_printf(u, 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",
103                                   filename, line, k, strerror(-r));
104         }
105
106         return 0;
107 }
108
109 int config_parse_unit_string_printf(
110                 const char *filename,
111                 unsigned line,
112                 const char *section,
113                 const char *lvalue,
114                 int ltype,
115                 const char *rvalue,
116                 void *data,
117                 void *userdata) {
118
119         Unit *u = userdata;
120         char *k;
121         int r;
122
123         assert(filename);
124         assert(lvalue);
125         assert(rvalue);
126         assert(u);
127
128         k = unit_full_printf(u, rvalue);
129         if (!k)
130                 return -ENOMEM;
131
132         r = config_parse_string(filename, line, section, lvalue, ltype, k, data, userdata);
133         free (k);
134
135         return r;
136 }
137
138 int config_parse_unit_strv_printf(
139                 const char *filename,
140                 unsigned line,
141                 const char *section,
142                 const char *lvalue,
143                 int ltype,
144                 const char *rvalue,
145                 void *data,
146                 void *userdata) {
147
148         Unit *u = userdata;
149         char *k;
150         int r;
151
152         assert(filename);
153         assert(lvalue);
154         assert(rvalue);
155         assert(u);
156
157         k = unit_full_printf(u, rvalue);
158         if (!k)
159                 return -ENOMEM;
160
161         r = config_parse_strv(filename, line, section, lvalue, ltype, k, data, userdata);
162         free(k);
163
164         return r;
165 }
166
167 int config_parse_unit_path_printf(
168                 const char *filename,
169                 unsigned line,
170                 const char *section,
171                 const char *lvalue,
172                 int ltype,
173                 const char *rvalue,
174                 void *data,
175                 void *userdata) {
176
177         Unit *u = userdata;
178         char *k;
179         int r;
180
181         assert(filename);
182         assert(lvalue);
183         assert(rvalue);
184         assert(u);
185
186         k = unit_full_printf(u, rvalue);
187         if (!k)
188                 return log_oom();
189
190         r = config_parse_path(filename, line, section, lvalue, ltype, k, data, userdata);
191         free(k);
192
193         return r;
194 }
195
196 int config_parse_socket_listen(
197                 const char *filename,
198                 unsigned line,
199                 const char *section,
200                 const char *lvalue,
201                 int ltype,
202                 const char *rvalue,
203                 void *data,
204                 void *userdata) {
205
206         SocketPort *p, *tail;
207         Socket *s;
208
209         assert(filename);
210         assert(lvalue);
211         assert(rvalue);
212         assert(data);
213
214         s = SOCKET(data);
215
216         p = new0(SocketPort, 1);
217         if (!p)
218                 return -ENOMEM;
219
220         if (streq(lvalue, "ListenFIFO")) {
221                 p->type = SOCKET_FIFO;
222
223                 if (!(p->path = unit_full_printf(UNIT(s), rvalue))) {
224                         free(p);
225                         return -ENOMEM;
226                 }
227
228                 path_kill_slashes(p->path);
229
230         } else if (streq(lvalue, "ListenSpecial")) {
231                 p->type = SOCKET_SPECIAL;
232
233                 if (!(p->path = unit_full_printf(UNIT(s), rvalue))) {
234                         free(p);
235                         return -ENOMEM;
236                 }
237
238                 path_kill_slashes(p->path);
239
240         } else if (streq(lvalue, "ListenMessageQueue")) {
241
242                 p->type = SOCKET_MQUEUE;
243
244                 if (!(p->path = unit_full_printf(UNIT(s), rvalue))) {
245                         free(p);
246                         return -ENOMEM;
247                 }
248
249                 path_kill_slashes(p->path);
250
251         } else if (streq(lvalue, "ListenNetlink")) {
252                 char  *k;
253                 int r;
254
255                 p->type = SOCKET_SOCKET;
256                 k = unit_full_printf(UNIT(s), rvalue);
257                 r = socket_address_parse_netlink(&p->address, k);
258                 free(k);
259
260                 if (r < 0) {
261                         log_error("[%s:%u] Failed to parse address value, ignoring: %s", filename, line, rvalue);
262                         free(p);
263                         return 0;
264                 }
265
266         } else {
267                 char *k;
268                 int r;
269
270                 p->type = SOCKET_SOCKET;
271                 k = unit_full_printf(UNIT(s), rvalue);
272                 r = socket_address_parse(&p->address, k);
273                 free(k);
274
275                 if (r < 0) {
276                         log_error("[%s:%u] Failed to parse address value, ignoring: %s", filename, line, rvalue);
277                         free(p);
278                         return 0;
279                 }
280
281                 if (streq(lvalue, "ListenStream"))
282                         p->address.type = SOCK_STREAM;
283                 else if (streq(lvalue, "ListenDatagram"))
284                         p->address.type = SOCK_DGRAM;
285                 else {
286                         assert(streq(lvalue, "ListenSequentialPacket"));
287                         p->address.type = SOCK_SEQPACKET;
288                 }
289
290                 if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
291                         log_error("[%s:%u] Address family not supported, ignoring: %s", filename, line, rvalue);
292                         free(p);
293                         return 0;
294                 }
295         }
296
297         p->fd = -1;
298
299         if (s->ports) {
300                 LIST_FIND_TAIL(SocketPort, port, s->ports, tail);
301                 LIST_INSERT_AFTER(SocketPort, port, s->ports, tail, p);
302         } else
303                 LIST_PREPEND(SocketPort, port, s->ports, p);
304
305         return 0;
306 }
307
308 int config_parse_socket_bind(
309                 const char *filename,
310                 unsigned line,
311                 const char *section,
312                 const char *lvalue,
313                 int ltype,
314                 const char *rvalue,
315                 void *data,
316                 void *userdata) {
317
318         Socket *s;
319         SocketAddressBindIPv6Only b;
320
321         assert(filename);
322         assert(lvalue);
323         assert(rvalue);
324         assert(data);
325
326         s = SOCKET(data);
327
328         b = socket_address_bind_ipv6_only_from_string(rvalue);
329         if (b < 0) {
330                 int r;
331
332                 r = parse_boolean(rvalue);
333                 if (r < 0) {
334                         log_error("[%s:%u] Failed to parse bind IPv6 only value, ignoring: %s", filename, line, rvalue);
335                         return 0;
336                 }
337
338                 s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
339         } else
340                 s->bind_ipv6_only = b;
341
342         return 0;
343 }
344
345 int config_parse_exec_nice(
346                 const char *filename,
347                 unsigned line,
348                 const char *section,
349                 const char *lvalue,
350                 int ltype,
351                 const char *rvalue,
352                 void *data,
353                 void *userdata) {
354
355         ExecContext *c = data;
356         int priority;
357
358         assert(filename);
359         assert(lvalue);
360         assert(rvalue);
361         assert(data);
362
363         if (safe_atoi(rvalue, &priority) < 0) {
364                 log_error("[%s:%u] Failed to parse nice priority, ignoring: %s. ", filename, line, rvalue);
365                 return 0;
366         }
367
368         if (priority < PRIO_MIN || priority >= PRIO_MAX) {
369                 log_error("[%s:%u] Nice priority out of range, ignoring: %s", filename, line, rvalue);
370                 return 0;
371         }
372
373         c->nice = priority;
374         c->nice_set = true;
375
376         return 0;
377 }
378
379 int config_parse_exec_oom_score_adjust(
380                 const char *filename,
381                 unsigned line,
382                 const char *section,
383                 const char *lvalue,
384                 int ltype,
385                 const char *rvalue,
386                 void *data,
387                 void *userdata) {
388
389         ExecContext *c = data;
390         int oa;
391
392         assert(filename);
393         assert(lvalue);
394         assert(rvalue);
395         assert(data);
396
397         if (safe_atoi(rvalue, &oa) < 0) {
398                 log_error("[%s:%u] Failed to parse the OOM score adjust value, ignoring: %s", filename, line, rvalue);
399                 return 0;
400         }
401
402         if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
403                 log_error("[%s:%u] OOM score adjust value out of range, ignoring: %s", filename, line, rvalue);
404                 return 0;
405         }
406
407         c->oom_score_adjust = oa;
408         c->oom_score_adjust_set = true;
409
410         return 0;
411 }
412
413 int config_parse_exec(
414                 const char *filename,
415                 unsigned line,
416                 const char *section,
417                 const char *lvalue,
418                 int ltype,
419                 const char *rvalue,
420                 void *data,
421                 void *userdata) {
422
423         ExecCommand **e = data, *nce;
424         char *path, **n;
425         unsigned k;
426         int r;
427
428         assert(filename);
429         assert(lvalue);
430         assert(rvalue);
431         assert(e);
432
433         /* We accept an absolute path as first argument, or
434          * alternatively an absolute prefixed with @ to allow
435          * overriding of argv[0]. */
436
437         e += ltype;
438
439         for (;;) {
440                 int i;
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                 for (i = 0; i < 2; i++) {
456                         if (rvalue[0] == '-' && !ignore) {
457                                 ignore = true;
458                                 rvalue ++;
459                         }
460
461                         if (rvalue[0] == '@' && !honour_argv0) {
462                                 honour_argv0 = true;
463                                 rvalue ++;
464                         }
465                 }
466
467                 if (*rvalue != '/') {
468                         log_error("[%s:%u] Executable path is not absolute, ignoring: %s",
469                                   filename, line, rvalue);
470                         return 0;
471                 }
472
473                 k = 0;
474                 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
475                         if (strncmp(w, ";", MAX(l, 1U)) == 0)
476                                 break;
477
478                         k++;
479                 }
480
481                 n = new(char*, k + !honour_argv0);
482                 if (!n)
483                         return -ENOMEM;
484
485                 k = 0;
486                 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
487                         if (strncmp(w, ";", MAX(l, 1U)) == 0)
488                                 break;
489                         else if (strncmp(w, "\\;", MAX(l, 1U)) == 0)
490                                 w ++;
491
492                         if (honour_argv0 && w == rvalue) {
493                                 assert(!path);
494
495                                 path = strndup(w, l);
496                                 if (!path) {
497                                         r = -ENOMEM;
498                                         goto fail;
499                                 }
500
501                                 if (!utf8_is_valid(path)) {
502                                         log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
503                                         r = 0;
504                                         goto fail;
505                                 }
506
507                         } else {
508                                 char *c;
509
510                                 c = n[k++] = cunescape_length(w, l);
511                                 if (!c) {
512                                         r = -ENOMEM;
513                                         goto fail;
514                                 }
515
516                                 if (!utf8_is_valid(c)) {
517                                         log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
518                                         r = 0;
519                                         goto fail;
520                                 }
521                         }
522                 }
523
524                 n[k] = NULL;
525
526                 if (!n[0]) {
527                         log_error("[%s:%u] Invalid command line, ignoring: %s", filename, line, rvalue);
528                         r = 0;
529                         goto fail;
530                 }
531
532                 if (!path) {
533                         path = strdup(n[0]);
534                         if (!path) {
535                                 r = -ENOMEM;
536                                 goto fail;
537                         }
538                 }
539
540                 assert(path_is_absolute(path));
541
542                 nce = new0(ExecCommand, 1);
543                 if (!nce) {
544                         r = -ENOMEM;
545                         goto fail;
546                 }
547
548                 nce->argv = n;
549                 nce->path = path;
550                 nce->ignore = ignore;
551
552                 path_kill_slashes(nce->path);
553
554                 exec_command_append_list(e, nce);
555
556                 rvalue = state;
557         }
558
559         return 0;
560
561 fail:
562         n[k] = NULL;
563         strv_free(n);
564         free(path);
565         free(nce);
566
567         return r;
568 }
569
570 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
571 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
572
573 int config_parse_socket_bindtodevice(
574                 const char *filename,
575                 unsigned line,
576                 const char *section,
577                 const char *lvalue,
578                 int ltype,
579                 const char *rvalue,
580                 void *data,
581                 void *userdata) {
582
583         Socket *s = data;
584         char *n;
585
586         assert(filename);
587         assert(lvalue);
588         assert(rvalue);
589         assert(data);
590
591         if (rvalue[0] && !streq(rvalue, "*")) {
592                 if (!(n = strdup(rvalue)))
593                         return -ENOMEM;
594         } else
595                 n = NULL;
596
597         free(s->bind_to_device);
598         s->bind_to_device = n;
599
600         return 0;
601 }
602
603 DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
604 DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
605
606 int config_parse_exec_io_class(
607                 const char *filename,
608                 unsigned line,
609                 const char *section,
610                 const char *lvalue,
611                 int ltype,
612                 const char *rvalue,
613                 void *data,
614                 void *userdata) {
615
616         ExecContext *c = data;
617         int x;
618
619         assert(filename);
620         assert(lvalue);
621         assert(rvalue);
622         assert(data);
623
624         x = ioprio_class_from_string(rvalue);
625         if (x < 0) {
626                 log_error("[%s:%u] Failed to parse IO scheduling class, ignoring: %s", filename, line, rvalue);
627                 return 0;
628         }
629
630         c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
631         c->ioprio_set = true;
632
633         return 0;
634 }
635
636 int config_parse_exec_io_priority(
637                 const char *filename,
638                 unsigned line,
639                 const char *section,
640                 const char *lvalue,
641                 int ltype,
642                 const char *rvalue,
643                 void *data,
644                 void *userdata) {
645
646         ExecContext *c = data;
647         int i;
648
649         assert(filename);
650         assert(lvalue);
651         assert(rvalue);
652         assert(data);
653
654         if (safe_atoi(rvalue, &i) < 0 || i < 0 || i >= IOPRIO_BE_NR) {
655                 log_error("[%s:%u] Failed to parse io priority, ignoring: %s", filename, line, rvalue);
656                 return 0;
657         }
658
659         c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
660         c->ioprio_set = true;
661
662         return 0;
663 }
664
665 int config_parse_exec_cpu_sched_policy(
666                 const char *filename,
667                 unsigned line,
668                 const char *section,
669                 const char *lvalue,
670                 int ltype,
671                 const char *rvalue,
672                 void *data,
673                 void *userdata) {
674
675
676         ExecContext *c = data;
677         int x;
678
679         assert(filename);
680         assert(lvalue);
681         assert(rvalue);
682         assert(data);
683
684         x = sched_policy_from_string(rvalue);
685         if (x < 0) {
686                 log_error("[%s:%u] Failed to parse CPU scheduling policy, ignoring: %s", filename, line, rvalue);
687                 return 0;
688         }
689
690         c->cpu_sched_policy = x;
691         /* Moving to or from real-time policy? We need to adjust the priority */
692         c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x));
693         c->cpu_sched_set = true;
694
695         return 0;
696 }
697
698 int config_parse_exec_cpu_sched_prio(
699                 const char *filename,
700                 unsigned line,
701                 const char *section,
702                 const char *lvalue,
703                 int ltype,
704                 const char *rvalue,
705                 void *data,
706                 void *userdata) {
707
708         ExecContext *c = data;
709         int i, min, max;
710
711         assert(filename);
712         assert(lvalue);
713         assert(rvalue);
714         assert(data);
715
716         if (safe_atoi(rvalue, &i) < 0) {
717                 log_error("[%s:%u] Failed to parse CPU scheduling priority, ignoring: %s", filename, line, rvalue);
718                 return 0;
719         }
720
721
722         /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
723         min = sched_get_priority_min(c->cpu_sched_policy);
724         max = sched_get_priority_max(c->cpu_sched_policy);
725
726         if (i < min || i > max) {
727                 log_error("[%s:%u] CPU scheduling priority is out of range, ignoring: %s", filename, line, rvalue);
728                 return 0;
729         }
730
731         c->cpu_sched_priority = i;
732         c->cpu_sched_set = true;
733
734         return 0;
735 }
736
737 int config_parse_exec_cpu_affinity(
738                 const char *filename,
739                 unsigned line,
740                 const char *section,
741                 const char *lvalue,
742                 int ltype,
743                 const char *rvalue,
744                 void *data,
745                 void *userdata) {
746
747         ExecContext *c = data;
748         char *w;
749         size_t l;
750         char *state;
751
752         assert(filename);
753         assert(lvalue);
754         assert(rvalue);
755         assert(data);
756
757         FOREACH_WORD_QUOTED(w, l, rvalue, state) {
758                 char _cleanup_free_ *t = NULL;
759                 int r;
760                 unsigned cpu;
761
762                 t = strndup(w, l);
763                 if (!t)
764                         return -ENOMEM;
765
766                 r = safe_atou(t, &cpu);
767
768                 if (!c->cpuset) {
769                         c->cpuset = cpu_set_malloc(&c->cpuset_ncpus);
770                         if (!c->cpuset)
771                                 return -ENOMEM;
772                 }
773
774                 if (r < 0 || cpu >= c->cpuset_ncpus) {
775                         log_error("[%s:%u] Failed to parse CPU affinity %s, ignoring: %s",
776                                   filename, line, t, rvalue);
777                         return 0;
778                 }
779
780                 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
781         }
782
783         return 0;
784 }
785
786 int config_parse_exec_capabilities(
787                 const char *filename,
788                 unsigned line,
789                 const char *section,
790                 const char *lvalue,
791                 int ltype,
792                 const char *rvalue,
793                 void *data,
794                 void *userdata) {
795
796         ExecContext *c = data;
797         cap_t cap;
798
799         assert(filename);
800         assert(lvalue);
801         assert(rvalue);
802         assert(data);
803
804         if (!(cap = cap_from_text(rvalue))) {
805                 if (errno == ENOMEM)
806                         return -ENOMEM;
807
808                 log_error("[%s:%u] Failed to parse capabilities, ignoring: %s", filename, line, rvalue);
809                 return 0;
810         }
811
812         if (c->capabilities)
813                 cap_free(c->capabilities);
814         c->capabilities = cap;
815
816         return 0;
817 }
818
819 int config_parse_exec_secure_bits(
820                 const char *filename,
821                 unsigned line,
822                 const char *section,
823                 const char *lvalue,
824                 int ltype,
825                 const char *rvalue,
826                 void *data,
827                 void *userdata) {
828
829         ExecContext *c = data;
830         char *w;
831         size_t l;
832         char *state;
833
834         assert(filename);
835         assert(lvalue);
836         assert(rvalue);
837         assert(data);
838
839         FOREACH_WORD_QUOTED(w, l, rvalue, state) {
840                 if (first_word(w, "keep-caps"))
841                         c->secure_bits |= SECURE_KEEP_CAPS;
842                 else if (first_word(w, "keep-caps-locked"))
843                         c->secure_bits |= SECURE_KEEP_CAPS_LOCKED;
844                 else if (first_word(w, "no-setuid-fixup"))
845                         c->secure_bits |= SECURE_NO_SETUID_FIXUP;
846                 else if (first_word(w, "no-setuid-fixup-locked"))
847                         c->secure_bits |= SECURE_NO_SETUID_FIXUP_LOCKED;
848                 else if (first_word(w, "noroot"))
849                         c->secure_bits |= SECURE_NOROOT;
850                 else if (first_word(w, "noroot-locked"))
851                         c->secure_bits |= SECURE_NOROOT_LOCKED;
852                 else {
853                         log_error("[%s:%u] Failed to parse secure bits, ignoring: %s",
854                                   filename, line, rvalue);
855                         return 0;
856                 }
857         }
858
859         return 0;
860 }
861
862 int config_parse_bounding_set(
863                 const char *filename,
864                 unsigned line,
865                 const char *section,
866                 const char *lvalue,
867                 int ltype,
868                 const char *rvalue,
869                 void *data,
870                 void *userdata) {
871
872         uint64_t *capability_bounding_set_drop = data;
873         char *w;
874         size_t l;
875         char *state;
876         bool invert = false;
877         uint64_t sum = 0;
878
879         assert(filename);
880         assert(lvalue);
881         assert(rvalue);
882         assert(data);
883
884         if (rvalue[0] == '~') {
885                 invert = true;
886                 rvalue++;
887         }
888
889         /* Note that we store this inverted internally, since the
890          * kernel wants it like this. But we actually expose it
891          * non-inverted everywhere to have a fully normalized
892          * interface. */
893
894         FOREACH_WORD_QUOTED(w, l, rvalue, state) {
895                 char _cleanup_free_ *t = NULL;
896                 int r;
897                 cap_value_t cap;
898
899                 t = strndup(w, l);
900                 if (!t)
901                         return -ENOMEM;
902
903                 r = cap_from_name(t, &cap);
904                 if (r < 0) {
905                         log_error("[%s:%u] Failed to parse capability in bounding set, ignoring: %s",
906                                   filename, line, t);
907                         continue;
908                 }
909
910                 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
911         }
912
913         if (invert)
914                 *capability_bounding_set_drop |= sum;
915         else
916                 *capability_bounding_set_drop |= ~sum;
917
918         return 0;
919 }
920
921 int config_parse_limit(
922                 const char *filename,
923                 unsigned line,
924                 const char *section,
925                 const char *lvalue,
926                 int ltype,
927                 const char *rvalue,
928                 void *data,
929                 void *userdata) {
930
931         struct rlimit **rl = data;
932         unsigned long long u;
933
934         assert(filename);
935         assert(lvalue);
936         assert(rvalue);
937         assert(data);
938
939         rl += ltype;
940
941         if (streq(rvalue, "infinity"))
942                 u = (unsigned long long) RLIM_INFINITY;
943         else if (safe_atollu(rvalue, &u) < 0) {
944                 log_error("[%s:%u] Failed to parse resource value, ignoring: %s", filename, line, rvalue);
945                 return 0;
946         }
947
948         if (!*rl)
949                 if (!(*rl = new(struct rlimit, 1)))
950                         return -ENOMEM;
951
952         (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
953         return 0;
954 }
955
956 int config_parse_unit_cgroup(
957                 const char *filename,
958                 unsigned line,
959                 const char *section,
960                 const char *lvalue,
961                 int ltype,
962                 const char *rvalue,
963                 void *data,
964                 void *userdata) {
965
966         Unit *u = userdata;
967         char *w;
968         size_t l;
969         char *state;
970
971         FOREACH_WORD_QUOTED(w, l, rvalue, state) {
972                 char _cleanup_free_ *t = NULL, *k = NULL, *ku = NULL;
973                 int r;
974
975                 t = strndup(w, l);
976                 if (!t)
977                         return -ENOMEM;
978
979                 k = unit_full_printf(u, t);
980                 if (!k)
981                         return -ENOMEM;
982
983                 ku = cunescape(k);
984                 if (!ku)
985                         return -ENOMEM;
986
987                 r = unit_add_cgroup_from_text(u, ku);
988                 if (r < 0) {
989                         log_error("[%s:%u] Failed to parse cgroup value %s, ignoring: %s",
990                                   filename, line, k, rvalue);
991                         return 0;
992                 }
993         }
994
995         return 0;
996 }
997
998 #ifdef HAVE_SYSV_COMPAT
999 int config_parse_sysv_priority(
1000                 const char *filename,
1001                 unsigned line,
1002                 const char *section,
1003                 const char *lvalue,
1004                 int ltype,
1005                 const char *rvalue,
1006                 void *data,
1007                 void *userdata) {
1008
1009         int *priority = data;
1010         int i;
1011
1012         assert(filename);
1013         assert(lvalue);
1014         assert(rvalue);
1015         assert(data);
1016
1017         if (safe_atoi(rvalue, &i) < 0 || i < 0) {
1018                 log_error("[%s:%u] Failed to parse SysV start priority, ignoring: %s", filename, line, rvalue);
1019                 return 0;
1020         }
1021
1022         *priority = (int) i;
1023         return 0;
1024 }
1025 #endif
1026
1027 int config_parse_fsck_passno(
1028                 const char *filename,
1029                 unsigned line,
1030                 const char *section,
1031                 const char *lvalue,
1032                 int ltype,
1033                 const char *rvalue,
1034                 void *data,
1035                 void *userdata) {
1036
1037         int *passno = data;
1038         int i;
1039
1040         assert(filename);
1041         assert(lvalue);
1042         assert(rvalue);
1043         assert(data);
1044
1045         if (safe_atoi(rvalue, &i) || i < 0) {
1046                 log_error("[%s:%u] Failed to parse fsck pass number, ignoring: %s", filename, line, rvalue);
1047                 return 0;
1048         }
1049
1050         *passno = (int) i;
1051         return 0;
1052 }
1053
1054 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
1055
1056 int config_parse_kill_signal(
1057                 const char *filename,
1058                 unsigned line,
1059                 const char *section,
1060                 const char *lvalue,
1061                 int ltype,
1062                 const char *rvalue,
1063                 void *data,
1064                 void *userdata) {
1065
1066         int *sig = data;
1067         int r;
1068
1069         assert(filename);
1070         assert(lvalue);
1071         assert(rvalue);
1072         assert(sig);
1073
1074         if ((r = signal_from_string_try_harder(rvalue)) <= 0) {
1075                 log_error("[%s:%u] Failed to parse kill signal, ignoring: %s", filename, line, rvalue);
1076                 return 0;
1077         }
1078
1079         *sig = r;
1080         return 0;
1081 }
1082
1083 int config_parse_exec_mount_flags(
1084                 const char *filename,
1085                 unsigned line,
1086                 const char *section,
1087                 const char *lvalue,
1088                 int ltype,
1089                 const char *rvalue,
1090                 void *data,
1091                 void *userdata) {
1092
1093         ExecContext *c = data;
1094         char *w;
1095         size_t l;
1096         char *state;
1097         unsigned long flags = 0;
1098
1099         assert(filename);
1100         assert(lvalue);
1101         assert(rvalue);
1102         assert(data);
1103
1104         FOREACH_WORD_SEPARATOR(w, l, rvalue, ", ", state) {
1105                 char _cleanup_free_ *t;
1106
1107                 t = strndup(w, l);
1108                 if (!t)
1109                         return -ENOMEM;
1110
1111                 if (streq(t, "shared"))
1112                         flags |= MS_SHARED;
1113                 else if (streq(t, "slave"))
1114                         flags |= MS_SLAVE;
1115                 else if (streq(w, "private"))
1116                         flags |= MS_PRIVATE;
1117                 else {
1118                         log_error("[%s:%u] Failed to parse mount flag %s, ignoring: %s",
1119                                   filename, line, t, rvalue);
1120                         return 0;
1121                 }
1122         }
1123
1124         c->mount_flags = flags;
1125         return 0;
1126 }
1127
1128 int config_parse_timer(
1129                 const char *filename,
1130                 unsigned line,
1131                 const char *section,
1132                 const char *lvalue,
1133                 int ltype,
1134                 const char *rvalue,
1135                 void *data,
1136                 void *userdata) {
1137
1138         Timer *t = data;
1139         usec_t u;
1140         TimerValue *v;
1141         TimerBase b;
1142
1143         assert(filename);
1144         assert(lvalue);
1145         assert(rvalue);
1146         assert(data);
1147
1148         if ((b = timer_base_from_string(lvalue)) < 0) {
1149                 log_error("[%s:%u] Failed to parse timer base, ignoring: %s", filename, line, lvalue);
1150                 return 0;
1151         }
1152
1153         if (parse_usec(rvalue, &u) < 0) {
1154                 log_error("[%s:%u] Failed to parse timer value, ignoring: %s", filename, line, rvalue);
1155                 return 0;
1156         }
1157
1158         if (!(v = new0(TimerValue, 1)))
1159                 return -ENOMEM;
1160
1161         v->base = b;
1162         v->value = u;
1163
1164         LIST_PREPEND(TimerValue, value, t->values, v);
1165
1166         return 0;
1167 }
1168
1169 int config_parse_timer_unit(
1170                 const char *filename,
1171                 unsigned line,
1172                 const char *section,
1173                 const char *lvalue,
1174                 int ltype,
1175                 const char *rvalue,
1176                 void *data,
1177                 void *userdata) {
1178
1179         Timer *t = data;
1180         int r;
1181         DBusError error;
1182         Unit *u;
1183
1184         assert(filename);
1185         assert(lvalue);
1186         assert(rvalue);
1187         assert(data);
1188
1189         dbus_error_init(&error);
1190
1191         if (endswith(rvalue, ".timer")) {
1192                 log_error("[%s:%u] Unit cannot be of type timer, ignoring: %s", filename, line, rvalue);
1193                 return 0;
1194         }
1195
1196         r = manager_load_unit(UNIT(t)->manager, rvalue, NULL, NULL, &u);
1197         if (r < 0) {
1198                 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1199                 dbus_error_free(&error);
1200                 return 0;
1201         }
1202
1203         unit_ref_set(&t->unit, u);
1204
1205         return 0;
1206 }
1207
1208 int config_parse_path_spec(
1209                 const char *filename,
1210                 unsigned line,
1211                 const char *section,
1212                 const char *lvalue,
1213                 int ltype,
1214                 const char *rvalue,
1215                 void *data,
1216                 void *userdata) {
1217
1218         Path *p = data;
1219         PathSpec *s;
1220         PathType b;
1221         char *k;
1222
1223         assert(filename);
1224         assert(lvalue);
1225         assert(rvalue);
1226         assert(data);
1227
1228         b = path_type_from_string(lvalue);
1229         if (b < 0) {
1230                 log_error("[%s:%u] Failed to parse path type, ignoring: %s", filename, line, lvalue);
1231                 return 0;
1232         }
1233
1234         k = unit_full_printf(UNIT(p), rvalue);
1235         if (!k)
1236                 return log_oom();
1237
1238         if (!path_is_absolute(k)) {
1239                 log_error("[%s:%u] Path is not absolute, ignoring: %s", filename, line, k);
1240                 free(k);
1241                 return 0;
1242         }
1243
1244         s = new0(PathSpec, 1);
1245         if (!s) {
1246                 free(k);
1247                 return log_oom();
1248         }
1249
1250         s->path = path_kill_slashes(k);
1251         s->type = b;
1252         s->inotify_fd = -1;
1253
1254         LIST_PREPEND(PathSpec, spec, p->specs, s);
1255
1256         return 0;
1257 }
1258
1259 int config_parse_path_unit(
1260                 const char *filename,
1261                 unsigned line,
1262                 const char *section,
1263                 const char *lvalue,
1264                 int ltype,
1265                 const char *rvalue,
1266                 void *data,
1267                 void *userdata) {
1268
1269         Path *t = data;
1270         int r;
1271         DBusError error;
1272         Unit *u;
1273
1274         assert(filename);
1275         assert(lvalue);
1276         assert(rvalue);
1277         assert(data);
1278
1279         dbus_error_init(&error);
1280
1281         if (endswith(rvalue, ".path")) {
1282                 log_error("[%s:%u] Unit cannot be of type path, ignoring: %s", filename, line, rvalue);
1283                 return 0;
1284         }
1285
1286         if ((r = manager_load_unit(UNIT(t)->manager, rvalue, NULL, &error, &u)) < 0) {
1287                 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1288                 dbus_error_free(&error);
1289                 return 0;
1290         }
1291
1292         unit_ref_set(&t->unit, u);
1293
1294         return 0;
1295 }
1296
1297 int config_parse_socket_service(
1298                 const char *filename,
1299                 unsigned line,
1300                 const char *section,
1301                 const char *lvalue,
1302                 int ltype,
1303                 const char *rvalue,
1304                 void *data,
1305                 void *userdata) {
1306
1307         Socket *s = data;
1308         int r;
1309         DBusError error;
1310         Unit *x;
1311
1312         assert(filename);
1313         assert(lvalue);
1314         assert(rvalue);
1315         assert(data);
1316
1317         dbus_error_init(&error);
1318
1319         if (!endswith(rvalue, ".service")) {
1320                 log_error("[%s:%u] Unit must be of type service, ignoring: %s", filename, line, rvalue);
1321                 return 0;
1322         }
1323
1324         r = manager_load_unit(UNIT(s)->manager, rvalue, NULL, &error, &x);
1325         if (r < 0) {
1326                 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1327                 dbus_error_free(&error);
1328                 return 0;
1329         }
1330
1331         unit_ref_set(&s->service, x);
1332
1333         return 0;
1334 }
1335
1336 int config_parse_service_sockets(
1337                 const char *filename,
1338                 unsigned line,
1339                 const char *section,
1340                 const char *lvalue,
1341                 int ltype,
1342                 const char *rvalue,
1343                 void *data,
1344                 void *userdata) {
1345
1346         Service *s = data;
1347         int r;
1348         char *state, *w;
1349         size_t l;
1350
1351         assert(filename);
1352         assert(lvalue);
1353         assert(rvalue);
1354         assert(data);
1355
1356         FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1357                 char _cleanup_free_ *t = NULL, *k = NULL;
1358
1359                 t = strndup(w, l);
1360                 if (!t)
1361                         return -ENOMEM;
1362
1363                 k = unit_name_printf(UNIT(s), t);
1364                 if (!k)
1365                         return -ENOMEM;
1366
1367                 if (!endswith(k, ".socket")) {
1368                         log_error("[%s:%u] Unit must be of type socket, ignoring: %s",
1369                                   filename, line, k);
1370                         continue;
1371                 }
1372
1373                 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true);
1374                 if (r < 0)
1375                         log_error("[%s:%u] Failed to add dependency on %s, ignoring: %s",
1376                                   filename, line, k, strerror(-r));
1377
1378                 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true);
1379                 if (r < 0)
1380                         return r;
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 _cleanup_free_ *t = NULL;
2109
2110                 t = strndup(w, l);
2111                 if (!t)
2112                         return -ENOMEM;
2113
2114                 id = syscall_from_name(t);
2115
2116                 if (id < 0)  {
2117                         log_error("[%s:%u] Failed to parse syscall, ignoring: %s",
2118                                   filename, line, t);
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 }