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