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