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