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