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