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