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