chiark / gitweb /
Do not print invalid UTF-8 in error messages
[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 #ifdef HAVE_SECCOMP
38 #include <seccomp.h>
39 #endif
40
41 #include "sd-messages.h"
42 #include "unit.h"
43 #include "strv.h"
44 #include "conf-parser.h"
45 #include "load-fragment.h"
46 #include "log.h"
47 #include "ioprio.h"
48 #include "securebits.h"
49 #include "missing.h"
50 #include "unit-name.h"
51 #include "unit-printf.h"
52 #include "utf8.h"
53 #include "path-util.h"
54 #include "env-util.h"
55 #include "cgroup.h"
56 #include "bus-util.h"
57 #include "bus-error.h"
58 #include "errno-list.h"
59 #include "af-list.h"
60
61 #ifdef HAVE_SECCOMP
62 #include "seccomp-util.h"
63 #endif
64
65 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_LIBWRAP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
66 int config_parse_warn_compat(
67                 const char *unit,
68                 const char *filename,
69                 unsigned line,
70                 const char *section,
71                 unsigned section_line,
72                 const char *lvalue,
73                 int ltype,
74                 const char *rvalue,
75                 void *data,
76                 void *userdata) {
77
78         log_syntax(unit, LOG_DEBUG, filename, line, EINVAL,
79                    "Support for option %s= has been disabled at compile time and is ignored",
80                    lvalue);
81         return 0;
82 }
83 #endif
84
85 int config_parse_unit_deps(const char* unit,
86                            const char *filename,
87                            unsigned line,
88                            const char *section,
89                            unsigned section_line,
90                            const char *lvalue,
91                            int ltype,
92                            const char *rvalue,
93                            void *data,
94                            void *userdata) {
95
96         UnitDependency d = ltype;
97         Unit *u = userdata;
98         char *w;
99         size_t l;
100         char *state;
101
102         assert(filename);
103         assert(lvalue);
104         assert(rvalue);
105
106         FOREACH_WORD_QUOTED(w, l, rvalue, state) {
107                 _cleanup_free_ char *t = NULL, *k = NULL;
108                 int r;
109
110                 t = strndup(w, l);
111                 if (!t)
112                         return log_oom();
113
114                 r = unit_name_printf(u, t, &k);
115                 if (r < 0) {
116                         log_syntax(unit, LOG_ERR, filename, line, -r,
117                                    "Failed to resolve specifiers, ignoring: %s", strerror(-r));
118                         continue;
119                 }
120
121                 r = unit_add_dependency_by_name(u, d, k, NULL, true);
122                 if (r < 0)
123                         log_syntax(unit, LOG_ERR, filename, line, -r,
124                                    "Failed to add dependency on %s, ignoring: %s", k, strerror(-r));
125         }
126
127         return 0;
128 }
129
130 int config_parse_unit_string_printf(const char *unit,
131                                     const char *filename,
132                                     unsigned line,
133                                     const char *section,
134                                     unsigned section_line,
135                                     const char *lvalue,
136                                     int ltype,
137                                     const char *rvalue,
138                                     void *data,
139                                     void *userdata) {
140
141         Unit *u = userdata;
142         _cleanup_free_ char *k = NULL;
143         int r;
144
145         assert(filename);
146         assert(lvalue);
147         assert(rvalue);
148         assert(u);
149
150         r = unit_full_printf(u, rvalue, &k);
151         if (r < 0)
152                 log_syntax(unit, LOG_ERR, filename, line, -r,
153                            "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
154
155         return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype,
156                                    k ? k : rvalue, data, userdata);
157 }
158
159 int config_parse_unit_strv_printf(const char *unit,
160                                   const char *filename,
161                                   unsigned line,
162                                   const char *section,
163                                   unsigned section_line,
164                                   const char *lvalue,
165                                   int ltype,
166                                   const char *rvalue,
167                                   void *data,
168                                   void *userdata) {
169
170         Unit *u = userdata;
171         _cleanup_free_ char *k = NULL;
172         int r;
173
174         assert(filename);
175         assert(lvalue);
176         assert(rvalue);
177         assert(u);
178
179         r = unit_full_printf(u, rvalue, &k);
180         if (r < 0)
181                 log_syntax(unit, LOG_ERR, filename, line, -r,
182                            "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
183
184         return config_parse_strv(unit, filename, line, section, section_line, lvalue, ltype,
185                                  k ? k : rvalue, data, userdata);
186 }
187
188 int config_parse_unit_path_printf(const char *unit,
189                                   const char *filename,
190                                   unsigned line,
191                                   const char *section,
192                                   unsigned section_line,
193                                   const char *lvalue,
194                                   int ltype,
195                                   const char *rvalue,
196                                   void *data,
197                                   void *userdata) {
198
199         Unit *u = userdata;
200         _cleanup_free_ char *k = NULL;
201         int r;
202
203         assert(filename);
204         assert(lvalue);
205         assert(rvalue);
206         assert(u);
207
208         r = unit_full_printf(u, rvalue, &k);
209         if (r < 0)
210                 log_syntax(unit, LOG_ERR, filename, line, -r,
211                            "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
212
213         return config_parse_path(unit, filename, line, section, section_line, lvalue, ltype,
214                                  k ? k : rvalue, data, userdata);
215 }
216
217 int config_parse_socket_listen(const char *unit,
218                                const char *filename,
219                                unsigned line,
220                                const char *section,
221                                unsigned section_line,
222                                const char *lvalue,
223                                int ltype,
224                                const char *rvalue,
225                                void *data,
226                                void *userdata) {
227
228         SocketPort *p, *tail;
229         Socket *s;
230         int r;
231
232         assert(filename);
233         assert(lvalue);
234         assert(rvalue);
235         assert(data);
236
237         s = SOCKET(data);
238
239         if (isempty(rvalue)) {
240                 /* An empty assignment removes all ports */
241                 socket_free_ports(s);
242                 return 0;
243         }
244
245         p = new0(SocketPort, 1);
246         if (!p)
247                 return log_oom();
248
249         if (ltype != SOCKET_SOCKET) {
250
251                 p->type = ltype;
252                 r = unit_full_printf(UNIT(s), rvalue, &p->path);
253                 if (r < 0) {
254                         p->path = strdup(rvalue);
255                         if (!p->path) {
256                                 free(p);
257                                 return log_oom();
258                         } else
259                                 log_syntax(unit, LOG_ERR, filename, line, -r,
260                                            "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
261                 }
262
263                 path_kill_slashes(p->path);
264
265         } else if (streq(lvalue, "ListenNetlink")) {
266                 _cleanup_free_ char  *k = NULL;
267
268                 p->type = SOCKET_SOCKET;
269                 r = unit_full_printf(UNIT(s), rvalue, &k);
270                 if (r < 0)
271                         log_syntax(unit, LOG_ERR, filename, line, -r,
272                                    "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
273
274                 r = socket_address_parse_netlink(&p->address, k ? k : rvalue);
275                 if (r < 0) {
276                         log_syntax(unit, LOG_ERR, filename, line, -r,
277                                    "Failed to parse address value, ignoring: %s", rvalue);
278                         free(p);
279                         return 0;
280                 }
281
282         } else {
283                 _cleanup_free_ char *k = NULL;
284
285                 p->type = SOCKET_SOCKET;
286                 r = unit_full_printf(UNIT(s), rvalue, &k);
287                 if (r < 0)
288                         log_syntax(unit, LOG_ERR, filename, line, -r,
289                                    "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
290
291                 r = socket_address_parse(&p->address, k ? k : rvalue);
292                 if (r < 0) {
293                         log_syntax(unit, LOG_ERR, filename, line, -r,
294                                    "Failed to parse address value, ignoring: %s", rvalue);
295                         free(p);
296                         return 0;
297                 }
298
299                 if (streq(lvalue, "ListenStream"))
300                         p->address.type = SOCK_STREAM;
301                 else if (streq(lvalue, "ListenDatagram"))
302                         p->address.type = SOCK_DGRAM;
303                 else {
304                         assert(streq(lvalue, "ListenSequentialPacket"));
305                         p->address.type = SOCK_SEQPACKET;
306                 }
307
308                 if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
309                         log_syntax(unit, LOG_ERR, filename, line, ENOTSUP,
310                                    "Address family not supported, ignoring: %s", rvalue);
311                         free(p);
312                         return 0;
313                 }
314         }
315
316         p->fd = -1;
317         p->socket = s;
318
319         if (s->ports) {
320                 LIST_FIND_TAIL(port, s->ports, tail);
321                 LIST_INSERT_AFTER(port, s->ports, tail, p);
322         } else
323                 LIST_PREPEND(port, s->ports, p);
324
325         return 0;
326 }
327
328 int config_parse_socket_bind(const char *unit,
329                              const char *filename,
330                              unsigned line,
331                              const char *section,
332                              unsigned section_line,
333                              const char *lvalue,
334                              int ltype,
335                              const char *rvalue,
336                              void *data,
337                              void *userdata) {
338
339         Socket *s;
340         SocketAddressBindIPv6Only b;
341
342         assert(filename);
343         assert(lvalue);
344         assert(rvalue);
345         assert(data);
346
347         s = SOCKET(data);
348
349         b = socket_address_bind_ipv6_only_from_string(rvalue);
350         if (b < 0) {
351                 int r;
352
353                 r = parse_boolean(rvalue);
354                 if (r < 0) {
355                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
356                                    "Failed to parse bind IPv6 only value, ignoring: %s", rvalue);
357                         return 0;
358                 }
359
360                 s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
361         } else
362                 s->bind_ipv6_only = b;
363
364         return 0;
365 }
366
367 int config_parse_exec_nice(const char *unit,
368                            const char *filename,
369                            unsigned line,
370                            const char *section,
371                            unsigned section_line,
372                            const char *lvalue,
373                            int ltype,
374                            const char *rvalue,
375                            void *data,
376                            void *userdata) {
377
378         ExecContext *c = data;
379         int priority, r;
380
381         assert(filename);
382         assert(lvalue);
383         assert(rvalue);
384         assert(data);
385
386         r = safe_atoi(rvalue, &priority);
387         if (r < 0) {
388                 log_syntax(unit, LOG_ERR, filename, line, -r,
389                            "Failed to parse nice priority, ignoring: %s. ", rvalue);
390                 return 0;
391         }
392
393         if (priority < PRIO_MIN || priority >= PRIO_MAX) {
394                 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
395                            "Nice priority out of range, ignoring: %s", rvalue);
396                 return 0;
397         }
398
399         c->nice = priority;
400         c->nice_set = true;
401
402         return 0;
403 }
404
405 int config_parse_exec_oom_score_adjust(const char* unit,
406                                        const char *filename,
407                                        unsigned line,
408                                        const char *section,
409                                        unsigned section_line,
410                                        const char *lvalue,
411                                        int ltype,
412                                        const char *rvalue,
413                                        void *data,
414                                        void *userdata) {
415
416         ExecContext *c = data;
417         int oa, r;
418
419         assert(filename);
420         assert(lvalue);
421         assert(rvalue);
422         assert(data);
423
424         r = safe_atoi(rvalue, &oa);
425         if (r < 0) {
426                 log_syntax(unit, LOG_ERR, filename, line, -r,
427                            "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
428                 return 0;
429         }
430
431         if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
432                 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
433                            "OOM score adjust value out of range, ignoring: %s", rvalue);
434                 return 0;
435         }
436
437         c->oom_score_adjust = oa;
438         c->oom_score_adjust_set = true;
439
440         return 0;
441 }
442
443 int config_parse_exec(const char *unit,
444                       const char *filename,
445                       unsigned line,
446                       const char *section,
447                       unsigned section_line,
448                       const char *lvalue,
449                       int ltype,
450                       const char *rvalue,
451                       void *data,
452                       void *userdata) {
453
454         ExecCommand **e = data, *nce;
455         char *path, **n;
456         unsigned k;
457         int r;
458
459         assert(filename);
460         assert(lvalue);
461         assert(rvalue);
462         assert(e);
463
464         e += ltype;
465
466         if (isempty(rvalue)) {
467                 /* An empty assignment resets the list */
468                 exec_command_free_list(*e);
469                 *e = NULL;
470                 return 0;
471         }
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         for (;;) {
477                 int i;
478                 char *w;
479                 size_t l;
480                 char *state;
481                 bool honour_argv0 = false, ignore = false;
482
483                 path = NULL;
484                 nce = NULL;
485                 n = NULL;
486
487                 rvalue += strspn(rvalue, WHITESPACE);
488
489                 if (rvalue[0] == 0)
490                         break;
491
492                 for (i = 0; i < 2; i++) {
493                         if (rvalue[0] == '-' && !ignore) {
494                                 ignore = true;
495                                 rvalue ++;
496                         }
497
498                         if (rvalue[0] == '@' && !honour_argv0) {
499                                 honour_argv0 = true;
500                                 rvalue ++;
501                         }
502                 }
503
504                 if (*rvalue != '/') {
505                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
506                                    "Executable path is not absolute, ignoring: %s", rvalue);
507                         return 0;
508                 }
509
510                 k = 0;
511                 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
512                         if (strneq(w, ";", MAX(l, 1U)))
513                                 break;
514
515                         k++;
516                 }
517
518                 n = new(char*, k + !honour_argv0);
519                 if (!n)
520                         return log_oom();
521
522                 k = 0;
523                 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
524                         if (strneq(w, ";", MAX(l, 1U)))
525                                 break;
526                         else if (strneq(w, "\\;", MAX(l, 1U)))
527                                 w ++;
528
529                         if (honour_argv0 && w == rvalue) {
530                                 assert(!path);
531
532                                 path = strndup(w, l);
533                                 if (!path) {
534                                         r = log_oom();
535                                         goto fail;
536                                 }
537
538                                 if (!utf8_is_valid(path)) {
539                                         log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
540                                         r = 0;
541                                         goto fail;
542                                 }
543
544                         } else {
545                                 char *c;
546
547                                 c = n[k++] = cunescape_length(w, l);
548                                 if (!c) {
549                                         r = log_oom();
550                                         goto fail;
551                                 }
552
553                                 if (!utf8_is_valid(c)) {
554                                         log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
555                                         r = 0;
556                                         goto fail;
557                                 }
558                         }
559                 }
560
561                 n[k] = NULL;
562
563                 if (!n[0]) {
564                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
565                                    "Invalid command line, ignoring: %s", rvalue);
566                         r = 0;
567                         goto fail;
568                 }
569
570                 if (!path) {
571                         path = strdup(n[0]);
572                         if (!path) {
573                                 r = log_oom();
574                                 goto fail;
575                         }
576                 }
577
578                 assert(path_is_absolute(path));
579
580                 nce = new0(ExecCommand, 1);
581                 if (!nce) {
582                         r = log_oom();
583                         goto fail;
584                 }
585
586                 nce->argv = n;
587                 nce->path = path;
588                 nce->ignore = ignore;
589
590                 path_kill_slashes(nce->path);
591
592                 exec_command_append_list(e, nce);
593
594                 rvalue = state;
595         }
596
597         return 0;
598
599 fail:
600         n[k] = NULL;
601         strv_free(n);
602         free(path);
603         free(nce);
604
605         return r;
606 }
607
608 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
609 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
610
611 int config_parse_socket_bindtodevice(const char* unit,
612                                      const char *filename,
613                                      unsigned line,
614                                      const char *section,
615                                      unsigned section_line,
616                                      const char *lvalue,
617                                      int ltype,
618                                      const char *rvalue,
619                                      void *data,
620                                      void *userdata) {
621
622         Socket *s = data;
623         char *n;
624
625         assert(filename);
626         assert(lvalue);
627         assert(rvalue);
628         assert(data);
629
630         if (rvalue[0] && !streq(rvalue, "*")) {
631                 n = strdup(rvalue);
632                 if (!n)
633                         return log_oom();
634         } else
635                 n = NULL;
636
637         free(s->bind_to_device);
638         s->bind_to_device = n;
639
640         return 0;
641 }
642
643 DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
644 DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
645
646 int config_parse_exec_io_class(const char *unit,
647                                const char *filename,
648                                unsigned line,
649                                const char *section,
650                                unsigned section_line,
651                                const char *lvalue,
652                                int ltype,
653                                const char *rvalue,
654                                void *data,
655                                void *userdata) {
656
657         ExecContext *c = data;
658         int x;
659
660         assert(filename);
661         assert(lvalue);
662         assert(rvalue);
663         assert(data);
664
665         x = ioprio_class_from_string(rvalue);
666         if (x < 0) {
667                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
668                            "Failed to parse IO scheduling class, ignoring: %s", rvalue);
669                 return 0;
670         }
671
672         c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
673         c->ioprio_set = true;
674
675         return 0;
676 }
677
678 int config_parse_exec_io_priority(const char *unit,
679                                   const char *filename,
680                                   unsigned line,
681                                   const char *section,
682                                   unsigned section_line,
683                                   const char *lvalue,
684                                   int ltype,
685                                   const char *rvalue,
686                                   void *data,
687                                   void *userdata) {
688
689         ExecContext *c = data;
690         int i, r;
691
692         assert(filename);
693         assert(lvalue);
694         assert(rvalue);
695         assert(data);
696
697         r = safe_atoi(rvalue, &i);
698         if (r < 0 || i < 0 || i >= IOPRIO_BE_NR) {
699                 log_syntax(unit, LOG_ERR, filename, line, -r,
700                            "Failed to parse IO priority, ignoring: %s", rvalue);
701                 return 0;
702         }
703
704         c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
705         c->ioprio_set = true;
706
707         return 0;
708 }
709
710 int config_parse_exec_cpu_sched_policy(const char *unit,
711                                        const char *filename,
712                                        unsigned line,
713                                        const char *section,
714                                        unsigned section_line,
715                                        const char *lvalue,
716                                        int ltype,
717                                        const char *rvalue,
718                                        void *data,
719                                        void *userdata) {
720
721
722         ExecContext *c = data;
723         int x;
724
725         assert(filename);
726         assert(lvalue);
727         assert(rvalue);
728         assert(data);
729
730         x = sched_policy_from_string(rvalue);
731         if (x < 0) {
732                 log_syntax(unit, LOG_ERR, filename, line, -x,
733                            "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
734                 return 0;
735         }
736
737         c->cpu_sched_policy = x;
738         /* Moving to or from real-time policy? We need to adjust the priority */
739         c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x));
740         c->cpu_sched_set = true;
741
742         return 0;
743 }
744
745 int config_parse_exec_cpu_sched_prio(const char *unit,
746                                      const char *filename,
747                                      unsigned line,
748                                      const char *section,
749                                      unsigned section_line,
750                                      const char *lvalue,
751                                      int ltype,
752                                      const char *rvalue,
753                                      void *data,
754                                      void *userdata) {
755
756         ExecContext *c = data;
757         int i, min, max, r;
758
759         assert(filename);
760         assert(lvalue);
761         assert(rvalue);
762         assert(data);
763
764         r = safe_atoi(rvalue, &i);
765         if (r < 0) {
766                 log_syntax(unit, LOG_ERR, filename, line, -r,
767                            "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
768                 return 0;
769         }
770
771         /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
772         min = sched_get_priority_min(c->cpu_sched_policy);
773         max = sched_get_priority_max(c->cpu_sched_policy);
774
775         if (i < min || i > max) {
776                 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
777                            "CPU scheduling priority is out of range, ignoring: %s", rvalue);
778                 return 0;
779         }
780
781         c->cpu_sched_priority = i;
782         c->cpu_sched_set = true;
783
784         return 0;
785 }
786
787 int config_parse_exec_cpu_affinity(const char *unit,
788                                    const char *filename,
789                                    unsigned line,
790                                    const char *section,
791                                    unsigned section_line,
792                                    const char *lvalue,
793                                    int ltype,
794                                    const char *rvalue,
795                                    void *data,
796                                    void *userdata) {
797
798         ExecContext *c = data;
799         char *w;
800         size_t l;
801         char *state;
802
803         assert(filename);
804         assert(lvalue);
805         assert(rvalue);
806         assert(data);
807
808         if (isempty(rvalue)) {
809                 /* An empty assignment resets the CPU list */
810                 if (c->cpuset)
811                         CPU_FREE(c->cpuset);
812                 c->cpuset = NULL;
813                 return 0;
814         }
815
816         FOREACH_WORD_QUOTED(w, l, rvalue, state) {
817                 _cleanup_free_ char *t = NULL;
818                 int r;
819                 unsigned cpu;
820
821                 t = strndup(w, l);
822                 if (!t)
823                         return log_oom();
824
825                 r = safe_atou(t, &cpu);
826
827                 if (!c->cpuset) {
828                         c->cpuset = cpu_set_malloc(&c->cpuset_ncpus);
829                         if (!c->cpuset)
830                                 return log_oom();
831                 }
832
833                 if (r < 0 || cpu >= c->cpuset_ncpus) {
834                         log_syntax(unit, LOG_ERR, filename, line, ERANGE,
835                                    "Failed to parse CPU affinity '%s', ignoring: %s", t, rvalue);
836                         return 0;
837                 }
838
839                 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
840         }
841
842         return 0;
843 }
844
845 int config_parse_exec_capabilities(const char *unit,
846                                    const char *filename,
847                                    unsigned line,
848                                    const char *section,
849                                    unsigned section_line,
850                                    const char *lvalue,
851                                    int ltype,
852                                    const char *rvalue,
853                                    void *data,
854                                    void *userdata) {
855
856         ExecContext *c = data;
857         cap_t cap;
858
859         assert(filename);
860         assert(lvalue);
861         assert(rvalue);
862         assert(data);
863
864         cap = cap_from_text(rvalue);
865         if (!cap) {
866                 log_syntax(unit, LOG_ERR, filename, line, errno,
867                            "Failed to parse capabilities, ignoring: %s", rvalue);
868                 return 0;
869         }
870
871         if (c->capabilities)
872                 cap_free(c->capabilities);
873         c->capabilities = cap;
874
875         return 0;
876 }
877
878 int config_parse_exec_secure_bits(const char *unit,
879                                   const char *filename,
880                                   unsigned line,
881                                   const char *section,
882                                   unsigned section_line,
883                                   const char *lvalue,
884                                   int ltype,
885                                   const char *rvalue,
886                                   void *data,
887                                   void *userdata) {
888
889         ExecContext *c = data;
890         char *w;
891         size_t l;
892         char *state;
893
894         assert(filename);
895         assert(lvalue);
896         assert(rvalue);
897         assert(data);
898
899         if (isempty(rvalue)) {
900                 /* An empty assignment resets the field */
901                 c->secure_bits = 0;
902                 return 0;
903         }
904
905         FOREACH_WORD_QUOTED(w, l, rvalue, state) {
906                 if (first_word(w, "keep-caps"))
907                         c->secure_bits |= 1<<SECURE_KEEP_CAPS;
908                 else if (first_word(w, "keep-caps-locked"))
909                         c->secure_bits |= 1<<SECURE_KEEP_CAPS_LOCKED;
910                 else if (first_word(w, "no-setuid-fixup"))
911                         c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP;
912                 else if (first_word(w, "no-setuid-fixup-locked"))
913                         c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP_LOCKED;
914                 else if (first_word(w, "noroot"))
915                         c->secure_bits |= 1<<SECURE_NOROOT;
916                 else if (first_word(w, "noroot-locked"))
917                         c->secure_bits |= 1<<SECURE_NOROOT_LOCKED;
918                 else {
919                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
920                                    "Failed to parse secure bits, ignoring: %s", rvalue);
921                         return 0;
922                 }
923         }
924
925         return 0;
926 }
927
928 int config_parse_bounding_set(const char *unit,
929                               const char *filename,
930                               unsigned line,
931                               const char *section,
932                               unsigned section_line,
933                               const char *lvalue,
934                               int ltype,
935                               const char *rvalue,
936                               void *data,
937                               void *userdata) {
938
939         uint64_t *capability_bounding_set_drop = data;
940         char *w;
941         size_t l;
942         char *state;
943         bool invert = false;
944         uint64_t sum = 0;
945
946         assert(filename);
947         assert(lvalue);
948         assert(rvalue);
949         assert(data);
950
951         if (rvalue[0] == '~') {
952                 invert = true;
953                 rvalue++;
954         }
955
956         /* Note that we store this inverted internally, since the
957          * kernel wants it like this. But we actually expose it
958          * non-inverted everywhere to have a fully normalized
959          * interface. */
960
961         FOREACH_WORD_QUOTED(w, l, rvalue, state) {
962                 _cleanup_free_ char *t = NULL;
963                 int r;
964                 cap_value_t cap;
965
966                 t = strndup(w, l);
967                 if (!t)
968                         return log_oom();
969
970                 r = cap_from_name(t, &cap);
971                 if (r < 0) {
972                         log_syntax(unit, LOG_ERR, filename, line, errno,
973                                    "Failed to parse capability in bounding set, ignoring: %s", t);
974                         continue;
975                 }
976
977                 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
978         }
979
980         if (invert)
981                 *capability_bounding_set_drop |= sum;
982         else
983                 *capability_bounding_set_drop |= ~sum;
984
985         return 0;
986 }
987
988 int config_parse_limit(const char *unit,
989                        const char *filename,
990                        unsigned line,
991                        const char *section,
992                        unsigned section_line,
993                        const char *lvalue,
994                        int ltype,
995                        const char *rvalue,
996                        void *data,
997                        void *userdata) {
998
999         struct rlimit **rl = data;
1000         unsigned long long u;
1001
1002         assert(filename);
1003         assert(lvalue);
1004         assert(rvalue);
1005         assert(data);
1006
1007         rl += ltype;
1008
1009         if (streq(rvalue, "infinity"))
1010                 u = (unsigned long long) RLIM_INFINITY;
1011         else {
1012                 int r;
1013
1014                 r = safe_atollu(rvalue, &u);
1015                 if (r < 0) {
1016                         log_syntax(unit, LOG_ERR, filename, line, -r,
1017                                    "Failed to parse resource value, ignoring: %s", rvalue);
1018                         return 0;
1019                 }
1020         }
1021
1022         if (!*rl) {
1023                 *rl = new(struct rlimit, 1);
1024                 if (!*rl)
1025                         return log_oom();
1026         }
1027
1028         (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
1029         return 0;
1030 }
1031
1032 #ifdef HAVE_SYSV_COMPAT
1033 int config_parse_sysv_priority(const char *unit,
1034                                const char *filename,
1035                                unsigned line,
1036                                const char *section,
1037                                unsigned section_line,
1038                                const char *lvalue,
1039                                int ltype,
1040                                const char *rvalue,
1041                                void *data,
1042                                void *userdata) {
1043
1044         int *priority = data;
1045         int i, r;
1046
1047         assert(filename);
1048         assert(lvalue);
1049         assert(rvalue);
1050         assert(data);
1051
1052         r = safe_atoi(rvalue, &i);
1053         if (r < 0 || i < 0) {
1054                 log_syntax(unit, LOG_ERR, filename, line, -r,
1055                            "Failed to parse SysV start priority, ignoring: %s", rvalue);
1056                 return 0;
1057         }
1058
1059         *priority = (int) i;
1060         return 0;
1061 }
1062 #endif
1063
1064 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
1065
1066 int config_parse_kill_signal(const char *unit,
1067                              const char *filename,
1068                              unsigned line,
1069                              const char *section,
1070                              unsigned section_line,
1071                              const char *lvalue,
1072                              int ltype,
1073                              const char *rvalue,
1074                              void *data,
1075                              void *userdata) {
1076
1077         int *sig = data;
1078         int r;
1079
1080         assert(filename);
1081         assert(lvalue);
1082         assert(rvalue);
1083         assert(sig);
1084
1085         r = signal_from_string_try_harder(rvalue);
1086         if (r <= 0) {
1087                 log_syntax(unit, LOG_ERR, filename, line, -r,
1088                            "Failed to parse kill signal, ignoring: %s", rvalue);
1089                 return 0;
1090         }
1091
1092         *sig = r;
1093         return 0;
1094 }
1095
1096 int config_parse_exec_mount_flags(const char *unit,
1097                                   const char *filename,
1098                                   unsigned line,
1099                                   const char *section,
1100                                   unsigned section_line,
1101                                   const char *lvalue,
1102                                   int ltype,
1103                                   const char *rvalue,
1104                                   void *data,
1105                                   void *userdata) {
1106
1107         ExecContext *c = data;
1108         char *w;
1109         size_t l;
1110         char *state;
1111         unsigned long flags = 0;
1112
1113         assert(filename);
1114         assert(lvalue);
1115         assert(rvalue);
1116         assert(data);
1117
1118         FOREACH_WORD_SEPARATOR(w, l, rvalue, ", ", state) {
1119                 _cleanup_free_ char *t;
1120
1121                 t = strndup(w, l);
1122                 if (!t)
1123                         return log_oom();
1124
1125                 if (streq(t, "shared"))
1126                         flags |= MS_SHARED;
1127                 else if (streq(t, "slave"))
1128                         flags |= MS_SLAVE;
1129                 else if (streq(w, "private"))
1130                         flags |= MS_PRIVATE;
1131                 else {
1132                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1133                                    "Failed to parse mount flag %s, ignoring: %s",
1134                                    t, rvalue);
1135                         return 0;
1136                 }
1137         }
1138
1139         c->mount_flags = flags;
1140         return 0;
1141 }
1142
1143 int config_parse_exec_selinux_context(
1144                 const char *unit,
1145                 const char *filename,
1146                 unsigned line,
1147                 const char *section,
1148                 unsigned section_line,
1149                 const char *lvalue,
1150                 int ltype,
1151                 const char *rvalue,
1152                 void *data,
1153                 void *userdata) {
1154
1155         ExecContext *c = data;
1156         Unit *u = userdata;
1157         bool ignore;
1158         char *k;
1159         int r;
1160
1161         assert(filename);
1162         assert(lvalue);
1163         assert(rvalue);
1164         assert(data);
1165
1166         if (isempty(rvalue)) {
1167                 free(c->selinux_context);
1168                 c->selinux_context = NULL;
1169                 c->selinux_context_ignore = false;
1170                 return 0;
1171         }
1172
1173         if (rvalue[0] == '-') {
1174                 ignore = true;
1175                 rvalue++;
1176         } else
1177                 ignore = false;
1178
1179         r = unit_name_printf(u, rvalue, &k);
1180         if (r < 0) {
1181                 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1182                 return 0;
1183         }
1184
1185         free(c->selinux_context);
1186         c->selinux_context = k;
1187         c->selinux_context_ignore = ignore;
1188
1189         return 0;
1190 }
1191
1192 int config_parse_exec_apparmor_profile(
1193                 const char *unit,
1194                 const char *filename,
1195                 unsigned line,
1196                 const char *section,
1197                 unsigned section_line,
1198                 const char *lvalue,
1199                 int ltype,
1200                 const char *rvalue,
1201                 void *data,
1202                 void *userdata) {
1203
1204         ExecContext *c = data;
1205         Unit *u = userdata;
1206         bool ignore;
1207         char *k;
1208         int r;
1209
1210         assert(filename);
1211         assert(lvalue);
1212         assert(rvalue);
1213         assert(data);
1214
1215         if (isempty(rvalue)) {
1216                 free(c->apparmor_profile);
1217                 c->apparmor_profile = NULL;
1218                 c->apparmor_profile_ignore = false;
1219                 return 0;
1220         }
1221
1222         if (rvalue[0] == '-') {
1223                 ignore = true;
1224                 rvalue++;
1225         } else
1226                 ignore = false;
1227
1228         r = unit_name_printf(u, rvalue, &k);
1229         if (r < 0) {
1230                 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1231                 return 0;
1232         }
1233
1234         free(c->apparmor_profile);
1235         c->apparmor_profile = k;
1236         c->apparmor_profile_ignore = ignore;
1237
1238         return 0;
1239 }
1240
1241 int config_parse_timer(const char *unit,
1242                        const char *filename,
1243                        unsigned line,
1244                        const char *section,
1245                        unsigned section_line,
1246                        const char *lvalue,
1247                        int ltype,
1248                        const char *rvalue,
1249                        void *data,
1250                        void *userdata) {
1251
1252         Timer *t = data;
1253         usec_t u = 0;
1254         TimerValue *v;
1255         TimerBase b;
1256         CalendarSpec *c = NULL;
1257         clockid_t id;
1258
1259         assert(filename);
1260         assert(lvalue);
1261         assert(rvalue);
1262         assert(data);
1263
1264         if (isempty(rvalue)) {
1265                 /* Empty assignment resets list */
1266                 timer_free_values(t);
1267                 return 0;
1268         }
1269
1270         b = timer_base_from_string(lvalue);
1271         if (b < 0) {
1272                 log_syntax(unit, LOG_ERR, filename, line, -b,
1273                            "Failed to parse timer base, ignoring: %s", lvalue);
1274                 return 0;
1275         }
1276
1277         if (b == TIMER_CALENDAR) {
1278                 if (calendar_spec_from_string(rvalue, &c) < 0) {
1279                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1280                                    "Failed to parse calendar specification, ignoring: %s",
1281                                    rvalue);
1282                         return 0;
1283                 }
1284
1285                 id = CLOCK_REALTIME;
1286         } else {
1287                 if (parse_sec(rvalue, &u) < 0) {
1288                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1289                                    "Failed to parse timer value, ignoring: %s",
1290                                    rvalue);
1291                         return 0;
1292                 }
1293
1294                 id = CLOCK_MONOTONIC;
1295         }
1296
1297         v = new0(TimerValue, 1);
1298         if (!v)
1299                 return log_oom();
1300
1301         v->base = b;
1302         v->clock_id = id;
1303         v->value = u;
1304         v->calendar_spec = c;
1305
1306         LIST_PREPEND(value, t->values, v);
1307
1308         return 0;
1309 }
1310
1311 int config_parse_trigger_unit(
1312                 const char *unit,
1313                 const char *filename,
1314                 unsigned line,
1315                 const char *section,
1316                 unsigned section_line,
1317                 const char *lvalue,
1318                 int ltype,
1319                 const char *rvalue,
1320                 void *data,
1321                 void *userdata) {
1322
1323         _cleanup_free_ char *p = NULL;
1324         Unit *u = data;
1325         UnitType type;
1326         int r;
1327
1328         assert(filename);
1329         assert(lvalue);
1330         assert(rvalue);
1331         assert(data);
1332
1333         if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
1334                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1335                            "Multiple units to trigger specified, ignoring: %s", rvalue);
1336                 return 0;
1337         }
1338
1339         r = unit_name_printf(u, rvalue, &p);
1340         if (r < 0)
1341                 log_syntax(unit, LOG_ERR, filename, line, -r,
1342                            "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1343
1344         type = unit_name_to_type(p ?: rvalue);
1345         if (type < 0) {
1346                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1347                            "Unit type not valid, ignoring: %s", rvalue);
1348                 return 0;
1349         }
1350
1351         if (type == u->type) {
1352                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1353                            "Trigger cannot be of same type, ignoring: %s", rvalue);
1354                 return 0;
1355         }
1356
1357         r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p ?: rvalue, NULL, true);
1358         if (r < 0) {
1359                 log_syntax(unit, LOG_ERR, filename, line, -r,
1360                            "Failed to add trigger on %s, ignoring: %s", p ?: rvalue, strerror(-r));
1361                 return 0;
1362         }
1363
1364         return 0;
1365 }
1366
1367 int config_parse_path_spec(const char *unit,
1368                            const char *filename,
1369                            unsigned line,
1370                            const char *section,
1371                            unsigned section_line,
1372                            const char *lvalue,
1373                            int ltype,
1374                            const char *rvalue,
1375                            void *data,
1376                            void *userdata) {
1377
1378         Path *p = data;
1379         PathSpec *s;
1380         PathType b;
1381         _cleanup_free_ char *k = NULL;
1382         int r;
1383
1384         assert(filename);
1385         assert(lvalue);
1386         assert(rvalue);
1387         assert(data);
1388
1389         if (isempty(rvalue)) {
1390                 /* Empty assignment clears list */
1391                 path_free_specs(p);
1392                 return 0;
1393         }
1394
1395         b = path_type_from_string(lvalue);
1396         if (b < 0) {
1397                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1398                            "Failed to parse path type, ignoring: %s", lvalue);
1399                 return 0;
1400         }
1401
1402         r = unit_full_printf(UNIT(p), rvalue, &k);
1403         if (r < 0) {
1404                 k = strdup(rvalue);
1405                 if (!k)
1406                         return log_oom();
1407                 else
1408                         log_syntax(unit, LOG_ERR, filename, line, -r,
1409                                    "Failed to resolve unit specifiers on %s. Ignoring.",
1410                                    rvalue);
1411         }
1412
1413         if (!path_is_absolute(k)) {
1414                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1415                            "Path is not absolute, ignoring: %s", k);
1416                 return 0;
1417         }
1418
1419         s = new0(PathSpec, 1);
1420         if (!s)
1421                 return log_oom();
1422
1423         s->unit = UNIT(p);
1424         s->path = path_kill_slashes(k);
1425         k = NULL;
1426         s->type = b;
1427         s->inotify_fd = -1;
1428
1429         LIST_PREPEND(spec, p->specs, s);
1430
1431         return 0;
1432 }
1433
1434 int config_parse_socket_service(const char *unit,
1435                                 const char *filename,
1436                                 unsigned line,
1437                                 const char *section,
1438                                 unsigned section_line,
1439                                 const char *lvalue,
1440                                 int ltype,
1441                                 const char *rvalue,
1442                                 void *data,
1443                                 void *userdata) {
1444
1445         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1446         Socket *s = data;
1447         int r;
1448         Unit *x;
1449         _cleanup_free_ char *p = NULL;
1450
1451         assert(filename);
1452         assert(lvalue);
1453         assert(rvalue);
1454         assert(data);
1455
1456         r = unit_name_printf(UNIT(s), rvalue, &p);
1457         if (r < 0) {
1458                 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
1459                 return 0;
1460         }
1461
1462         if (!endswith(p, ".service")) {
1463                 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type service, ignoring: %s", rvalue);
1464                 return 0;
1465         }
1466
1467         r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
1468         if (r < 0) {
1469                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1470                 return 0;
1471         }
1472
1473         unit_ref_set(&s->service, x);
1474
1475         return 0;
1476 }
1477
1478 int config_parse_service_sockets(const char *unit,
1479                                  const char *filename,
1480                                  unsigned line,
1481                                  const char *section,
1482                                  unsigned section_line,
1483                                  const char *lvalue,
1484                                  int ltype,
1485                                  const char *rvalue,
1486                                  void *data,
1487                                  void *userdata) {
1488
1489         Service *s = data;
1490         int r;
1491         char *state, *w;
1492         size_t l;
1493
1494         assert(filename);
1495         assert(lvalue);
1496         assert(rvalue);
1497         assert(data);
1498
1499         FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1500                 _cleanup_free_ char *t = NULL, *k = NULL;
1501
1502                 t = strndup(w, l);
1503                 if (!t)
1504                         return log_oom();
1505
1506                 r = unit_name_printf(UNIT(s), t, &k);
1507                 if (r < 0)
1508                         log_syntax(unit, LOG_ERR, filename, line, -r,
1509                                    "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1510
1511                 if (!endswith(k ?: t, ".socket")) {
1512                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1513                                    "Unit must be of type socket, ignoring: %s", k ?: t);
1514                         continue;
1515                 }
1516
1517                 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k ?: t, NULL, true);
1518                 if (r < 0)
1519                         log_syntax(unit, LOG_ERR, filename, line, -r,
1520                                    "Failed to add dependency on %s, ignoring: %s",
1521                                    k ?: t, strerror(-r));
1522
1523                 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k ?: t, NULL, true);
1524                 if (r < 0)
1525                         return r;
1526         }
1527
1528         return 0;
1529 }
1530
1531 int config_parse_service_timeout(const char *unit,
1532                                  const char *filename,
1533                                  unsigned line,
1534                                  const char *section,
1535                                  unsigned section_line,
1536                                  const char *lvalue,
1537                                  int ltype,
1538                                  const char *rvalue,
1539                                  void *data,
1540                                  void *userdata) {
1541
1542         Service *s = userdata;
1543         int r;
1544
1545         assert(filename);
1546         assert(lvalue);
1547         assert(rvalue);
1548         assert(s);
1549
1550         r = config_parse_sec(unit, filename, line, section, section_line, lvalue, ltype,
1551                              rvalue, data, userdata);
1552         if (r < 0)
1553                 return r;
1554
1555         if (streq(lvalue, "TimeoutSec")) {
1556                 s->start_timeout_defined = true;
1557                 s->timeout_stop_usec = s->timeout_start_usec;
1558         } else if (streq(lvalue, "TimeoutStartSec"))
1559                 s->start_timeout_defined = true;
1560
1561         return 0;
1562 }
1563
1564 int config_parse_busname_service(
1565                 const char *unit,
1566                 const char *filename,
1567                 unsigned line,
1568                 const char *section,
1569                 unsigned section_line,
1570                 const char *lvalue,
1571                 int ltype,
1572                 const char *rvalue,
1573                 void *data,
1574                 void *userdata) {
1575
1576         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1577         BusName *n = data;
1578         int r;
1579         Unit *x;
1580         _cleanup_free_ char *p = NULL;
1581
1582         assert(filename);
1583         assert(lvalue);
1584         assert(rvalue);
1585         assert(data);
1586
1587         r = unit_name_printf(UNIT(n), rvalue, &p);
1588         if (r < 0) {
1589                 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
1590                 return 0;
1591         }
1592
1593         if (!endswith(p, ".service")) {
1594                 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type service, ignoring: %s", rvalue);
1595                 return 0;
1596         }
1597
1598         r = manager_load_unit(UNIT(n)->manager, p, NULL, &error, &x);
1599         if (r < 0) {
1600                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1601                 return 0;
1602         }
1603
1604         unit_ref_set(&n->service, x);
1605
1606         return 0;
1607 }
1608
1609 int config_parse_unit_env_file(const char *unit,
1610                                const char *filename,
1611                                unsigned line,
1612                                const char *section,
1613                                unsigned section_line,
1614                                const char *lvalue,
1615                                int ltype,
1616                                const char *rvalue,
1617                                void *data,
1618                                void *userdata) {
1619
1620         char ***env = data;
1621         Unit *u = userdata;
1622         _cleanup_free_ char *n = NULL;
1623         const char *s;
1624         int r;
1625
1626         assert(filename);
1627         assert(lvalue);
1628         assert(rvalue);
1629         assert(data);
1630
1631         if (isempty(rvalue)) {
1632                 /* Empty assignment frees the list */
1633                 strv_free(*env);
1634                 *env = NULL;
1635                 return 0;
1636         }
1637
1638         r = unit_full_printf(u, rvalue, &n);
1639         if (r < 0)
1640                 log_syntax(unit, LOG_ERR, filename, line, r,
1641                            "Failed to resolve specifiers, ignoring: %s", rvalue);
1642
1643         s = n ?: rvalue;
1644         if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1645                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1646                            "Path '%s' is not absolute, ignoring.", s);
1647                 return 0;
1648         }
1649
1650         r = strv_extend(env, s);
1651         if (r < 0)
1652                 return log_oom();
1653
1654         return 0;
1655 }
1656
1657 int config_parse_environ(const char *unit,
1658                          const char *filename,
1659                          unsigned line,
1660                          const char *section,
1661                          unsigned section_line,
1662                          const char *lvalue,
1663                          int ltype,
1664                          const char *rvalue,
1665                          void *data,
1666                          void *userdata) {
1667
1668         Unit *u = userdata;
1669         char*** env = data, *w, *state;
1670         size_t l;
1671         _cleanup_free_ char *k = NULL;
1672         int r;
1673
1674         assert(filename);
1675         assert(lvalue);
1676         assert(rvalue);
1677         assert(data);
1678
1679         if (isempty(rvalue)) {
1680                 /* Empty assignment resets the list */
1681                 strv_free(*env);
1682                 *env = NULL;
1683                 return 0;
1684         }
1685
1686         if (u) {
1687                 r = unit_full_printf(u, rvalue, &k);
1688                 if (r < 0)
1689                         log_syntax(unit, LOG_ERR, filename, line, -r,
1690                                    "Failed to resolve specifiers, ignoring: %s", rvalue);
1691         }
1692
1693         if (!k)
1694                 k = strdup(rvalue);
1695         if (!k)
1696                 return log_oom();
1697
1698         FOREACH_WORD_QUOTED(w, l, k, state) {
1699                 _cleanup_free_ char *n;
1700                 char **x;
1701
1702                 n = cunescape_length(w, l);
1703                 if (!n)
1704                         return log_oom();
1705
1706                 if (!env_assignment_is_valid(n)) {
1707                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1708                                    "Invalid environment assignment, ignoring: %s", rvalue);
1709                         continue;
1710                 }
1711
1712                 x = strv_env_set(*env, n);
1713                 if (!x)
1714                         return log_oom();
1715
1716                 strv_free(*env);
1717                 *env = x;
1718         }
1719
1720         return 0;
1721 }
1722
1723 int config_parse_ip_tos(const char *unit,
1724                         const char *filename,
1725                         unsigned line,
1726                         const char *section,
1727                         unsigned section_line,
1728                         const char *lvalue,
1729                         int ltype,
1730                         const char *rvalue,
1731                         void *data,
1732                         void *userdata) {
1733
1734         int *ip_tos = data, x;
1735
1736         assert(filename);
1737         assert(lvalue);
1738         assert(rvalue);
1739         assert(data);
1740
1741         x = ip_tos_from_string(rvalue);
1742         if (x < 0) {
1743                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1744                            "Failed to parse IP TOS value, ignoring: %s", rvalue);
1745                 return 0;
1746         }
1747
1748         *ip_tos = x;
1749         return 0;
1750 }
1751
1752 int config_parse_unit_condition_path(const char *unit,
1753                                      const char *filename,
1754                                      unsigned line,
1755                                      const char *section,
1756                                      unsigned section_line,
1757                                      const char *lvalue,
1758                                      int ltype,
1759                                      const char *rvalue,
1760                                      void *data,
1761                                      void *userdata) {
1762
1763         ConditionType cond = ltype;
1764         Unit *u = data;
1765         bool trigger, negate;
1766         Condition *c;
1767         _cleanup_free_ char *p = NULL;
1768         int r;
1769
1770         assert(filename);
1771         assert(lvalue);
1772         assert(rvalue);
1773         assert(data);
1774
1775         if (isempty(rvalue)) {
1776                 /* Empty assignment resets the list */
1777                 condition_free_list(u->conditions);
1778                 u->conditions = NULL;
1779                 return 0;
1780         }
1781
1782         trigger = rvalue[0] == '|';
1783         if (trigger)
1784                 rvalue++;
1785
1786         negate = rvalue[0] == '!';
1787         if (negate)
1788                 rvalue++;
1789
1790         r = unit_full_printf(u, rvalue, &p);
1791         if (r < 0)
1792                 log_syntax(unit, LOG_ERR, filename, line, -r,
1793                            "Failed to resolve specifiers, ignoring: %s", rvalue);
1794         if (!p) {
1795                 p = strdup(rvalue);
1796                 if (!p)
1797                         return log_oom();
1798         }
1799
1800         if (!path_is_absolute(p)) {
1801                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1802                            "Path in condition not absolute, ignoring: %s", p);
1803                 return 0;
1804         }
1805
1806         c = condition_new(cond, p, trigger, negate);
1807         if (!c)
1808                 return log_oom();
1809
1810         LIST_PREPEND(conditions, u->conditions, c);
1811         return 0;
1812 }
1813
1814 int config_parse_unit_condition_string(const char *unit,
1815                                        const char *filename,
1816                                        unsigned line,
1817                                        const char *section,
1818                                        unsigned section_line,
1819                                        const char *lvalue,
1820                                        int ltype,
1821                                        const char *rvalue,
1822                                        void *data,
1823                                        void *userdata) {
1824
1825         ConditionType cond = ltype;
1826         Unit *u = data;
1827         bool trigger, negate;
1828         Condition *c;
1829         _cleanup_free_ char *s = NULL;
1830         int r;
1831
1832         assert(filename);
1833         assert(lvalue);
1834         assert(rvalue);
1835         assert(data);
1836
1837         if (isempty(rvalue)) {
1838                 /* Empty assignment resets the list */
1839                 condition_free_list(u->conditions);
1840                 u->conditions = NULL;
1841                 return 0;
1842         }
1843
1844         trigger = rvalue[0] == '|';
1845         if (trigger)
1846                 rvalue++;
1847
1848         negate = rvalue[0] == '!';
1849         if (negate)
1850                 rvalue++;
1851
1852         r = unit_full_printf(u, rvalue, &s);
1853         if (r < 0)
1854                 log_syntax(unit, LOG_ERR, filename, line, -r,
1855                            "Failed to resolve specifiers, ignoring: %s", rvalue);
1856         if (!s) {
1857                 s = strdup(rvalue);
1858                 if (!s)
1859                         return log_oom();
1860         }
1861
1862         c = condition_new(cond, s, trigger, negate);
1863         if (!c)
1864                 return log_oom();
1865
1866         LIST_PREPEND(conditions, u->conditions, c);
1867         return 0;
1868 }
1869
1870 int config_parse_unit_condition_null(const char *unit,
1871                                      const char *filename,
1872                                      unsigned line,
1873                                      const char *section,
1874                                      unsigned section_line,
1875                                      const char *lvalue,
1876                                      int ltype,
1877                                      const char *rvalue,
1878                                      void *data,
1879                                      void *userdata) {
1880
1881         Unit *u = data;
1882         Condition *c;
1883         bool trigger, negate;
1884         int b;
1885
1886         assert(filename);
1887         assert(lvalue);
1888         assert(rvalue);
1889         assert(data);
1890
1891         if (isempty(rvalue)) {
1892                 /* Empty assignment resets the list */
1893                 condition_free_list(u->conditions);
1894                 u->conditions = NULL;
1895                 return 0;
1896         }
1897
1898         trigger = rvalue[0] == '|';
1899         if (trigger)
1900                 rvalue++;
1901
1902         negate = rvalue[0] == '!';
1903         if (negate)
1904                 rvalue++;
1905
1906         b = parse_boolean(rvalue);
1907         if (b < 0) {
1908                 log_syntax(unit, LOG_ERR, filename, line, -b,
1909                            "Failed to parse boolean value in condition, ignoring: %s",
1910                            rvalue);
1911                 return 0;
1912         }
1913
1914         if (!b)
1915                 negate = !negate;
1916
1917         c = condition_new(CONDITION_NULL, NULL, trigger, negate);
1918         if (!c)
1919                 return log_oom();
1920
1921         LIST_PREPEND(conditions, u->conditions, c);
1922         return 0;
1923 }
1924
1925 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
1926 DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
1927
1928 int config_parse_unit_requires_mounts_for(
1929                 const char *unit,
1930                 const char *filename,
1931                 unsigned line,
1932                 const char *section,
1933                 unsigned section_line,
1934                 const char *lvalue,
1935                 int ltype,
1936                 const char *rvalue,
1937                 void *data,
1938                 void *userdata) {
1939
1940         Unit *u = userdata;
1941         char *state;
1942         size_t l;
1943         char *w;
1944
1945         assert(filename);
1946         assert(lvalue);
1947         assert(rvalue);
1948         assert(data);
1949
1950         FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1951                 int r;
1952                 _cleanup_free_ char *n;
1953
1954                 n = strndup(w, l);
1955                 if (!n)
1956                         return log_oom();
1957
1958                 if (!utf8_is_valid(n)) {
1959                         log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
1960                         continue;
1961                 }
1962
1963                 r = unit_require_mounts_for(u, n);
1964                 if (r < 0) {
1965                         log_syntax(unit, LOG_ERR, filename, line, r,
1966                                    "Failed to add required mount for, ignoring: %s", rvalue);
1967                         continue;
1968                 }
1969         }
1970
1971         return 0;
1972 }
1973
1974 int config_parse_documentation(const char *unit,
1975                                const char *filename,
1976                                unsigned line,
1977                                const char *section,
1978                                unsigned section_line,
1979                                const char *lvalue,
1980                                int ltype,
1981                                const char *rvalue,
1982                                void *data,
1983                                void *userdata) {
1984
1985         Unit *u = userdata;
1986         int r;
1987         char **a, **b;
1988
1989         assert(filename);
1990         assert(lvalue);
1991         assert(rvalue);
1992         assert(u);
1993
1994         if (isempty(rvalue)) {
1995                 /* Empty assignment resets the list */
1996                 strv_free(u->documentation);
1997                 u->documentation = NULL;
1998                 return 0;
1999         }
2000
2001         r = config_parse_unit_strv_printf(unit, filename, line, section, section_line, lvalue, ltype,
2002                                           rvalue, data, userdata);
2003         if (r < 0)
2004                 return r;
2005
2006         for (a = b = u->documentation; a && *a; a++) {
2007
2008                 if (is_valid_documentation_url(*a))
2009                         *(b++) = *a;
2010                 else {
2011                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2012                                    "Invalid URL, ignoring: %s", *a);
2013                         free(*a);
2014                 }
2015         }
2016         if (b)
2017                 *b = NULL;
2018
2019         return r;
2020 }
2021
2022 #ifdef HAVE_SECCOMP
2023 int config_parse_syscall_filter(
2024                 const char *unit,
2025                 const char *filename,
2026                 unsigned line,
2027                 const char *section,
2028                 unsigned section_line,
2029                 const char *lvalue,
2030                 int ltype,
2031                 const char *rvalue,
2032                 void *data,
2033                 void *userdata) {
2034
2035         static const char default_syscalls[] =
2036                 "execve\0"
2037                 "exit\0"
2038                 "exit_group\0"
2039                 "rt_sigreturn\0"
2040                 "sigreturn\0";
2041
2042         ExecContext *c = data;
2043         Unit *u = userdata;
2044         bool invert = false;
2045         char *w, *state;
2046         size_t l;
2047         int r;
2048
2049         assert(filename);
2050         assert(lvalue);
2051         assert(rvalue);
2052         assert(u);
2053
2054         if (isempty(rvalue)) {
2055                 /* Empty assignment resets the list */
2056                 set_free(c->syscall_filter);
2057                 c->syscall_filter = NULL;
2058                 c->syscall_whitelist = false;
2059                 return 0;
2060         }
2061
2062         if (rvalue[0] == '~') {
2063                 invert = true;
2064                 rvalue++;
2065         }
2066
2067         if (!c->syscall_filter) {
2068                 c->syscall_filter = set_new(trivial_hash_func, trivial_compare_func);
2069                 if (!c->syscall_filter)
2070                         return log_oom();
2071
2072                 if (invert)
2073                         /* Allow everything but the ones listed */
2074                         c->syscall_whitelist = false;
2075                 else {
2076                         const char *i;
2077
2078                         /* Allow nothing but the ones listed */
2079                         c->syscall_whitelist = true;
2080
2081                         /* Accept default syscalls if we are on a whitelist */
2082                         NULSTR_FOREACH(i, default_syscalls)  {
2083                                 int id;
2084
2085                                 id = seccomp_syscall_resolve_name(i);
2086                                 if (id < 0)
2087                                         continue;
2088
2089                                 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2090                                 if (r == -EEXIST)
2091                                         continue;
2092                                 if (r < 0)
2093                                         return log_oom();
2094                         }
2095                 }
2096         }
2097
2098         FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2099                 _cleanup_free_ char *t = NULL;
2100                 int id;
2101
2102                 t = strndup(w, l);
2103                 if (!t)
2104                         return log_oom();
2105
2106                 id = seccomp_syscall_resolve_name(t);
2107                 if (id < 0)  {
2108                         log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse system call, ignoring: %s", t);
2109                         continue;
2110                 }
2111
2112                 /* If we previously wanted to forbid a syscall and now
2113                  * we want to allow it, then remove it from the list
2114                  */
2115                 if (!invert == c->syscall_whitelist)  {
2116                         r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2117                         if (r == -EEXIST)
2118                                 continue;
2119                         if (r < 0)
2120                                 return log_oom();
2121                 } else
2122                         set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
2123         }
2124
2125         c->no_new_privileges = true;
2126
2127         return 0;
2128 }
2129
2130 int config_parse_syscall_archs(
2131                 const char *unit,
2132                 const char *filename,
2133                 unsigned line,
2134                 const char *section,
2135                 unsigned section_line,
2136                 const char *lvalue,
2137                 int ltype,
2138                 const char *rvalue,
2139                 void *data,
2140                 void *userdata) {
2141
2142         Set **archs = data;
2143         char *w, *state;
2144         size_t l;
2145         int r;
2146
2147         if (isempty(rvalue)) {
2148                 set_free(*archs);
2149                 *archs = NULL;
2150                 return 0;
2151         }
2152
2153         r = set_ensure_allocated(archs, trivial_hash_func, trivial_compare_func);
2154         if (r < 0)
2155                 return log_oom();
2156
2157         FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2158                 _cleanup_free_ char *t = NULL;
2159                 uint32_t a;
2160
2161                 t = strndup(w, l);
2162                 if (!t)
2163                         return log_oom();
2164
2165                 r = seccomp_arch_from_string(t, &a);
2166                 if (r < 0) {
2167                         log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse system call architecture, ignoring: %s", t);
2168                         continue;
2169                 }
2170
2171                 r = set_put(*archs, UINT32_TO_PTR(a + 1));
2172                 if (r == -EEXIST)
2173                         continue;
2174                 if (r < 0)
2175                         return log_oom();
2176         }
2177
2178         return 0;
2179 }
2180
2181 int config_parse_syscall_errno(
2182                 const char *unit,
2183                 const char *filename,
2184                 unsigned line,
2185                 const char *section,
2186                 unsigned section_line,
2187                 const char *lvalue,
2188                 int ltype,
2189                 const char *rvalue,
2190                 void *data,
2191                 void *userdata) {
2192
2193         ExecContext *c = data;
2194         int e;
2195
2196         assert(filename);
2197         assert(lvalue);
2198         assert(rvalue);
2199
2200         if (isempty(rvalue)) {
2201                 /* Empty assignment resets to KILL */
2202                 c->syscall_errno = 0;
2203                 return 0;
2204         }
2205
2206         e = errno_from_name(rvalue);
2207         if (e < 0) {
2208                 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse error number, ignoring: %s", rvalue);
2209                 return 0;
2210         }
2211
2212         c->syscall_errno = e;
2213         return 0;
2214 }
2215
2216 int config_parse_address_families(
2217                 const char *unit,
2218                 const char *filename,
2219                 unsigned line,
2220                 const char *section,
2221                 unsigned section_line,
2222                 const char *lvalue,
2223                 int ltype,
2224                 const char *rvalue,
2225                 void *data,
2226                 void *userdata) {
2227
2228         ExecContext *c = data;
2229         Unit *u = userdata;
2230         bool invert = false;
2231         char *w, *state;
2232         size_t l;
2233         int r;
2234
2235         assert(filename);
2236         assert(lvalue);
2237         assert(rvalue);
2238         assert(u);
2239
2240         if (isempty(rvalue)) {
2241                 /* Empty assignment resets the list */
2242                 set_free(c->address_families);
2243                 c->address_families = NULL;
2244                 c->address_families_whitelist = false;
2245                 return 0;
2246         }
2247
2248         if (rvalue[0] == '~') {
2249                 invert = true;
2250                 rvalue++;
2251         }
2252
2253         if (!c->address_families) {
2254                 c->address_families = set_new(trivial_hash_func, trivial_compare_func);
2255                 if (!c->address_families)
2256                         return log_oom();
2257
2258                 c->address_families_whitelist = !invert;
2259         }
2260
2261         FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2262                 _cleanup_free_ char *t = NULL;
2263                 int af;
2264
2265                 t = strndup(w, l);
2266                 if (!t)
2267                         return log_oom();
2268
2269                 af = af_from_name(t);
2270                 if (af <= 0)  {
2271                         log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse address family, ignoring: %s", t);
2272                         continue;
2273                 }
2274
2275                 /* If we previously wanted to forbid an address family and now
2276                  * we want to allow it, then remove it from the list
2277                  */
2278                 if (!invert == c->address_families_whitelist)  {
2279                         r = set_put(c->address_families, INT_TO_PTR(af));
2280                         if (r == -EEXIST)
2281                                 continue;
2282                         if (r < 0)
2283                                 return log_oom();
2284                 } else
2285                         set_remove(c->address_families, INT_TO_PTR(af));
2286         }
2287
2288         return 0;
2289 }
2290 #endif
2291
2292 int config_parse_unit_slice(
2293                 const char *unit,
2294                 const char *filename,
2295                 unsigned line,
2296                 const char *section,
2297                 unsigned section_line,
2298                 const char *lvalue,
2299                 int ltype,
2300                 const char *rvalue,
2301                 void *data,
2302                 void *userdata) {
2303
2304         _cleanup_free_ char *k = NULL;
2305         Unit *u = userdata, *slice;
2306         int r;
2307
2308         assert(filename);
2309         assert(lvalue);
2310         assert(rvalue);
2311         assert(u);
2312
2313         r = unit_name_printf(u, rvalue, &k);
2314         if (r < 0)
2315                 log_syntax(unit, LOG_ERR, filename, line, -r,
2316                            "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
2317         if (!k) {
2318                 k = strdup(rvalue);
2319                 if (!k)
2320                         return log_oom();
2321         }
2322
2323         r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
2324         if (r < 0) {
2325                 log_syntax(unit, LOG_ERR, filename, line, -r,
2326                            "Failed to load slice unit %s. Ignoring.", k);
2327                 return 0;
2328         }
2329
2330         if (slice->type != UNIT_SLICE) {
2331                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2332                            "Slice unit %s is not a slice. Ignoring.", k);
2333                 return 0;
2334         }
2335
2336         unit_ref_set(&u->slice, slice);
2337         return 0;
2338 }
2339
2340 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
2341
2342 int config_parse_cpu_shares(
2343                 const char *unit,
2344                 const char *filename,
2345                 unsigned line,
2346                 const char *section,
2347                 unsigned section_line,
2348                 const char *lvalue,
2349                 int ltype,
2350                 const char *rvalue,
2351                 void *data,
2352                 void *userdata) {
2353
2354         CGroupContext *c = data;
2355         unsigned long lu;
2356         int r;
2357
2358         assert(filename);
2359         assert(lvalue);
2360         assert(rvalue);
2361
2362         if (isempty(rvalue)) {
2363                 c->cpu_shares = 1024;
2364                 return 0;
2365         }
2366
2367         r = safe_atolu(rvalue, &lu);
2368         if (r < 0 || lu <= 0) {
2369                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2370                            "CPU shares '%s' invalid. Ignoring.", rvalue);
2371                 return 0;
2372         }
2373
2374         c->cpu_shares = lu;
2375         return 0;
2376 }
2377
2378 int config_parse_memory_limit(
2379                 const char *unit,
2380                 const char *filename,
2381                 unsigned line,
2382                 const char *section,
2383                 unsigned section_line,
2384                 const char *lvalue,
2385                 int ltype,
2386                 const char *rvalue,
2387                 void *data,
2388                 void *userdata) {
2389
2390         CGroupContext *c = data;
2391         off_t bytes;
2392         int r;
2393
2394         if (isempty(rvalue)) {
2395                 c->memory_limit = (uint64_t) -1;
2396                 return 0;
2397         }
2398
2399         assert_cc(sizeof(uint64_t) == sizeof(off_t));
2400
2401         r = parse_size(rvalue, 1024, &bytes);
2402         if (r < 0) {
2403                 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Memory limit '%s' invalid. Ignoring.", rvalue);
2404                 return 0;
2405         }
2406
2407         c->memory_limit = (uint64_t) bytes;
2408         return 0;
2409 }
2410
2411 int config_parse_device_allow(
2412                 const char *unit,
2413                 const char *filename,
2414                 unsigned line,
2415                 const char *section,
2416                 unsigned section_line,
2417                 const char *lvalue,
2418                 int ltype,
2419                 const char *rvalue,
2420                 void *data,
2421                 void *userdata) {
2422
2423         _cleanup_free_ char *path = NULL;
2424         CGroupContext *c = data;
2425         CGroupDeviceAllow *a;
2426         const char *m;
2427         size_t n;
2428
2429         if (isempty(rvalue)) {
2430                 while (c->device_allow)
2431                         cgroup_context_free_device_allow(c, c->device_allow);
2432
2433                 return 0;
2434         }
2435
2436         n = strcspn(rvalue, WHITESPACE);
2437         path = strndup(rvalue, n);
2438         if (!path)
2439                 return log_oom();
2440
2441         if (!startswith(path, "/dev/") &&
2442             !startswith(path, "block-") &&
2443             !startswith(path, "char-")) {
2444                 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid device node path '%s'. Ignoring.", path);
2445                 return 0;
2446         }
2447
2448         m = rvalue + n + strspn(rvalue + n, WHITESPACE);
2449         if (isempty(m))
2450                 m = "rwm";
2451
2452         if (!in_charset(m, "rwm")) {
2453                 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid device rights '%s'. Ignoring.", m);
2454                 return 0;
2455         }
2456
2457         a = new0(CGroupDeviceAllow, 1);
2458         if (!a)
2459                 return log_oom();
2460
2461         a->path = path;
2462         path = NULL;
2463         a->r = !!strchr(m, 'r');
2464         a->w = !!strchr(m, 'w');
2465         a->m = !!strchr(m, 'm');
2466
2467         LIST_PREPEND(device_allow, c->device_allow, a);
2468         return 0;
2469 }
2470
2471 int config_parse_blockio_weight(
2472                 const char *unit,
2473                 const char *filename,
2474                 unsigned line,
2475                 const char *section,
2476                 unsigned section_line,
2477                 const char *lvalue,
2478                 int ltype,
2479                 const char *rvalue,
2480                 void *data,
2481                 void *userdata) {
2482
2483         CGroupContext *c = data;
2484         unsigned long lu;
2485         int r;
2486
2487         assert(filename);
2488         assert(lvalue);
2489         assert(rvalue);
2490
2491         if (isempty(rvalue)) {
2492                 c->blockio_weight = 1000;
2493                 return 0;
2494         }
2495
2496         r = safe_atolu(rvalue, &lu);
2497         if (r < 0 || lu < 10 || lu > 1000) {
2498                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2499                            "Block IO weight '%s' invalid. Ignoring.", rvalue);
2500                 return 0;
2501         }
2502
2503         c->blockio_weight = lu;
2504
2505         return 0;
2506 }
2507
2508 int config_parse_blockio_device_weight(
2509                 const char *unit,
2510                 const char *filename,
2511                 unsigned line,
2512                 const char *section,
2513                 unsigned section_line,
2514                 const char *lvalue,
2515                 int ltype,
2516                 const char *rvalue,
2517                 void *data,
2518                 void *userdata) {
2519
2520         _cleanup_free_ char *path = NULL;
2521         CGroupBlockIODeviceWeight *w;
2522         CGroupContext *c = data;
2523         unsigned long lu;
2524         const char *weight;
2525         size_t n;
2526         int r;
2527
2528         assert(filename);
2529         assert(lvalue);
2530         assert(rvalue);
2531
2532         if (isempty(rvalue)) {
2533                 while (c->blockio_device_weights)
2534                         cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
2535
2536                 return 0;
2537         }
2538
2539         n = strcspn(rvalue, WHITESPACE);
2540         weight = rvalue + n;
2541         if (!*weight) {
2542                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2543                            "Expected block device and device weight. Ignoring.");
2544                 return 0;
2545         }
2546
2547         path = strndup(rvalue, n);
2548         if (!path)
2549                 return log_oom();
2550
2551         if (!path_startswith(path, "/dev")) {
2552                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2553                            "Invalid device node path '%s'. Ignoring.", path);
2554                 return 0;
2555         }
2556
2557         weight += strspn(weight, WHITESPACE);
2558         r = safe_atolu(weight, &lu);
2559         if (r < 0 || lu < 10 || lu > 1000) {
2560                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2561                            "Block IO weight '%s' invalid. Ignoring.", rvalue);
2562                 return 0;
2563         }
2564
2565
2566         w = new0(CGroupBlockIODeviceWeight, 1);
2567         if (!w)
2568                 return log_oom();
2569
2570         w->path = path;
2571         path = NULL;
2572
2573         w->weight = lu;
2574
2575         LIST_PREPEND(device_weights, c->blockio_device_weights, w);
2576         return 0;
2577 }
2578
2579 int config_parse_blockio_bandwidth(
2580                 const char *unit,
2581                 const char *filename,
2582                 unsigned line,
2583                 const char *section,
2584                 unsigned section_line,
2585                 const char *lvalue,
2586                 int ltype,
2587                 const char *rvalue,
2588                 void *data,
2589                 void *userdata) {
2590
2591         _cleanup_free_ char *path = NULL;
2592         CGroupBlockIODeviceBandwidth *b;
2593         CGroupContext *c = data;
2594         const char *bandwidth;
2595         off_t bytes;
2596         bool read;
2597         size_t n;
2598         int r;
2599
2600         assert(filename);
2601         assert(lvalue);
2602         assert(rvalue);
2603
2604         read = streq("BlockIOReadBandwidth", lvalue);
2605
2606         if (isempty(rvalue)) {
2607                 CGroupBlockIODeviceBandwidth *next;
2608
2609                 LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
2610                         if (b->read == read)
2611                                 cgroup_context_free_blockio_device_bandwidth(c, b);
2612
2613                 return 0;
2614         }
2615
2616         n = strcspn(rvalue, WHITESPACE);
2617         bandwidth = rvalue + n;
2618         bandwidth += strspn(bandwidth, WHITESPACE);
2619
2620         if (!*bandwidth) {
2621                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2622                            "Expected space separated pair of device node and bandwidth. Ignoring.");
2623                 return 0;
2624         }
2625
2626         path = strndup(rvalue, n);
2627         if (!path)
2628                 return log_oom();
2629
2630         if (!path_startswith(path, "/dev")) {
2631                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2632                            "Invalid device node path '%s'. Ignoring.", path);
2633                 return 0;
2634         }
2635
2636         r = parse_size(bandwidth, 1000, &bytes);
2637         if (r < 0 || bytes <= 0) {
2638                 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
2639                 return 0;
2640         }
2641
2642         b = new0(CGroupBlockIODeviceBandwidth, 1);
2643         if (!b)
2644                 return log_oom();
2645
2646         b->path = path;
2647         path = NULL;
2648         b->bandwidth = (uint64_t) bytes;
2649         b->read = read;
2650
2651         LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
2652
2653         return 0;
2654 }
2655
2656 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
2657
2658 int config_parse_job_mode_isolate(
2659                 const char *unit,
2660                 const char *filename,
2661                 unsigned line,
2662                 const char *section,
2663                 unsigned section_line,
2664                 const char *lvalue,
2665                 int ltype,
2666                 const char *rvalue,
2667                 void *data,
2668                 void *userdata) {
2669
2670         JobMode *m = data;
2671         int r;
2672
2673         assert(filename);
2674         assert(lvalue);
2675         assert(rvalue);
2676
2677         r = parse_boolean(rvalue);
2678         if (r < 0) {
2679                 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse boolean, ignoring: %s", rvalue);
2680                 return 0;
2681         }
2682
2683         *m = r ? JOB_ISOLATE : JOB_REPLACE;
2684         return 0;
2685 }
2686
2687 int config_parse_personality(
2688                 const char *unit,
2689                 const char *filename,
2690                 unsigned line,
2691                 const char *section,
2692                 unsigned section_line,
2693                 const char *lvalue,
2694                 int ltype,
2695                 const char *rvalue,
2696                 void *data,
2697                 void *userdata) {
2698
2699         unsigned long *personality = data, p;
2700
2701         assert(filename);
2702         assert(lvalue);
2703         assert(rvalue);
2704         assert(personality);
2705
2706         p = personality_from_string(rvalue);
2707         if (p == 0xffffffffUL) {
2708                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2709                            "Failed to parse personality, ignoring: %s", rvalue);
2710                 return 0;
2711         }
2712
2713         *personality = p;
2714         return 0;
2715 }
2716
2717 int config_parse_runtime_directory(
2718                 const char *unit,
2719                 const char *filename,
2720                 unsigned line,
2721                 const char *section,
2722                 unsigned section_line,
2723                 const char *lvalue,
2724                 int ltype,
2725                 const char *rvalue,
2726                 void *data,
2727                 void *userdata) {
2728
2729         char***rt = data, *w, *state;
2730         size_t l;
2731         int r;
2732
2733         assert(filename);
2734         assert(lvalue);
2735         assert(rvalue);
2736         assert(data);
2737
2738         if (isempty(rvalue)) {
2739                 /* Empty assignment resets the list */
2740                 strv_free(*rt);
2741                 *rt = NULL;
2742                 return 0;
2743         }
2744
2745         FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2746                 _cleanup_free_ char *n;
2747
2748                 n = strndup(w, l);
2749                 if (!n)
2750                         return log_oom();
2751
2752                 if (!filename_is_safe(n)) {
2753                         log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Runtime directory is not valid, ignoring assignment: %s", rvalue);
2754                         continue;
2755                 }
2756
2757                 r = strv_push(rt, n);
2758                 if (r < 0)
2759                         return log_oom();
2760
2761                 n = NULL;
2762         }
2763
2764         return 0;
2765 }
2766
2767 int config_parse_set_status(
2768                 const char *unit,
2769                 const char *filename,
2770                 unsigned line,
2771                 const char *section,
2772                 unsigned section_line,
2773                 const char *lvalue,
2774                 int ltype,
2775                 const char *rvalue,
2776                 void *data,
2777                 void *userdata) {
2778
2779         char *w;
2780         size_t l;
2781         char *state;
2782         int r;
2783         ExitStatusSet *status_set = data;
2784
2785         assert(filename);
2786         assert(lvalue);
2787         assert(rvalue);
2788         assert(data);
2789
2790         if (isempty(rvalue)) {
2791                 /* Empty assignment resets the list */
2792
2793                 set_free(status_set->signal);
2794                 set_free(status_set->code);
2795
2796                 status_set->signal = status_set->code = NULL;
2797                 return 0;
2798         }
2799
2800         FOREACH_WORD(w, l, rvalue, state) {
2801                 _cleanup_free_ char *temp;
2802                 int val;
2803
2804                 temp = strndup(w, l);
2805                 if (!temp)
2806                         return log_oom();
2807
2808                 r = safe_atoi(temp, &val);
2809                 if (r < 0) {
2810                         val = signal_from_string_try_harder(temp);
2811
2812                         if (val > 0) {
2813                                 r = set_ensure_allocated(&status_set->signal, trivial_hash_func, trivial_compare_func);
2814                                 if (r < 0)
2815                                         return log_oom();
2816
2817                                 r = set_put(status_set->signal, INT_TO_PTR(val));
2818                                 if (r < 0) {
2819                                         log_syntax(unit, LOG_ERR, filename, line, -r, "Unable to store: %s", w);
2820                                         return r;
2821                                 }
2822                         } else {
2823                                 log_syntax(unit, LOG_ERR, filename, line, -val, "Failed to parse value, ignoring: %s", w);
2824                                 return 0;
2825                         }
2826                 } else {
2827                         if (val < 0 || val > 255)
2828                                 log_syntax(unit, LOG_ERR, filename, line, ERANGE, "Value %d is outside range 0-255, ignoring", val);
2829                         else {
2830                                 r = set_ensure_allocated(&status_set->code, trivial_hash_func, trivial_compare_func);
2831                                 if (r < 0)
2832                                         return log_oom();
2833
2834                                 r = set_put(status_set->code, INT_TO_PTR(val));
2835                                 if (r < 0) {
2836                                         log_syntax(unit, LOG_ERR, filename, line, -r, "Unable to store: %s", w);
2837                                         return r;
2838                                 }
2839                         }
2840                 }
2841         }
2842
2843         return 0;
2844 }
2845
2846 int config_parse_namespace_path_strv(
2847                 const char *unit,
2848                 const char *filename,
2849                 unsigned line,
2850                 const char *section,
2851                 unsigned section_line,
2852                 const char *lvalue,
2853                 int ltype,
2854                 const char *rvalue,
2855                 void *data,
2856                 void *userdata) {
2857
2858         char*** sv = data, *w, *state;
2859         size_t l;
2860         int r;
2861
2862         assert(filename);
2863         assert(lvalue);
2864         assert(rvalue);
2865         assert(data);
2866
2867         if (isempty(rvalue)) {
2868                 /* Empty assignment resets the list */
2869                 strv_free(*sv);
2870                 *sv = NULL;
2871                 return 0;
2872         }
2873
2874         FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2875                 _cleanup_free_ char *n;
2876                 int offset;
2877
2878                 n = strndup(w, l);
2879                 if (!n)
2880                         return log_oom();
2881
2882                 if (!utf8_is_valid(n)) {
2883                         log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
2884                         continue;
2885                 }
2886
2887                 offset = n[0] == '-';
2888                 if (!path_is_absolute(n + offset)) {
2889                         log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Not an absolute path, ignoring: %s", rvalue);
2890                         continue;
2891                 }
2892
2893                 path_kill_slashes(n);
2894
2895                 r = strv_push(sv, n);
2896                 if (r < 0)
2897                         return log_oom();
2898
2899                 n = NULL;
2900         }
2901
2902         return 0;
2903 }
2904
2905 #define FOLLOW_MAX 8
2906
2907 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
2908         unsigned c = 0;
2909         int fd, r;
2910         FILE *f;
2911         char *id = NULL;
2912
2913         assert(filename);
2914         assert(*filename);
2915         assert(_f);
2916         assert(names);
2917
2918         /* This will update the filename pointer if the loaded file is
2919          * reached by a symlink. The old string will be freed. */
2920
2921         for (;;) {
2922                 char *target, *name;
2923
2924                 if (c++ >= FOLLOW_MAX)
2925                         return -ELOOP;
2926
2927                 path_kill_slashes(*filename);
2928
2929                 /* Add the file name we are currently looking at to
2930                  * the names of this unit, but only if it is a valid
2931                  * unit name. */
2932                 name = basename(*filename);
2933
2934                 if (unit_name_is_valid(name, TEMPLATE_VALID)) {
2935
2936                         id = set_get(names, name);
2937                         if (!id) {
2938                                 id = strdup(name);
2939                                 if (!id)
2940                                         return -ENOMEM;
2941
2942                                 r = set_consume(names, id);
2943                                 if (r < 0)
2944                                         return r;
2945                         }
2946                 }
2947
2948                 /* Try to open the file name, but don't if its a symlink */
2949                 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
2950                 if (fd >= 0)
2951                         break;
2952
2953                 if (errno != ELOOP)
2954                         return -errno;
2955
2956                 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
2957                 r = readlink_and_make_absolute(*filename, &target);
2958                 if (r < 0)
2959                         return r;
2960
2961                 free(*filename);
2962                 *filename = target;
2963         }
2964
2965         f = fdopen(fd, "re");
2966         if (!f) {
2967                 r = -errno;
2968                 close_nointr_nofail(fd);
2969                 return r;
2970         }
2971
2972         *_f = f;
2973         *_final = id;
2974         return 0;
2975 }
2976
2977 static int merge_by_names(Unit **u, Set *names, const char *id) {
2978         char *k;
2979         int r;
2980
2981         assert(u);
2982         assert(*u);
2983         assert(names);
2984
2985         /* Let's try to add in all symlink names we found */
2986         while ((k = set_steal_first(names))) {
2987
2988                 /* First try to merge in the other name into our
2989                  * unit */
2990                 r = unit_merge_by_name(*u, k);
2991                 if (r < 0) {
2992                         Unit *other;
2993
2994                         /* Hmm, we couldn't merge the other unit into
2995                          * ours? Then let's try it the other way
2996                          * round */
2997
2998                         other = manager_get_unit((*u)->manager, k);
2999                         free(k);
3000
3001                         if (other) {
3002                                 r = unit_merge(other, *u);
3003                                 if (r >= 0) {
3004                                         *u = other;
3005                                         return merge_by_names(u, names, NULL);
3006                                 }
3007                         }
3008
3009                         return r;
3010                 }
3011
3012                 if (id == k)
3013                         unit_choose_id(*u, id);
3014
3015                 free(k);
3016         }
3017
3018         return 0;
3019 }
3020
3021 static int load_from_path(Unit *u, const char *path) {
3022         int r;
3023         _cleanup_set_free_free_ Set *symlink_names = NULL;
3024         _cleanup_fclose_ FILE *f = NULL;
3025         _cleanup_free_ char *filename = NULL;
3026         char *id = NULL;
3027         Unit *merged;
3028         struct stat st;
3029
3030         assert(u);
3031         assert(path);
3032
3033         symlink_names = set_new(string_hash_func, string_compare_func);
3034         if (!symlink_names)
3035                 return -ENOMEM;
3036
3037         if (path_is_absolute(path)) {
3038
3039                 filename = strdup(path);
3040                 if (!filename)
3041                         return -ENOMEM;
3042
3043                 r = open_follow(&filename, &f, symlink_names, &id);
3044                 if (r < 0) {
3045                         free(filename);
3046                         filename = NULL;
3047
3048                         if (r != -ENOENT)
3049                                 return r;
3050                 }
3051
3052         } else  {
3053                 char **p;
3054
3055                 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
3056
3057                         /* Instead of opening the path right away, we manually
3058                          * follow all symlinks and add their name to our unit
3059                          * name set while doing so */
3060                         filename = path_make_absolute(path, *p);
3061                         if (!filename)
3062                                 return -ENOMEM;
3063
3064                         if (u->manager->unit_path_cache &&
3065                             !set_get(u->manager->unit_path_cache, filename))
3066                                 r = -ENOENT;
3067                         else
3068                                 r = open_follow(&filename, &f, symlink_names, &id);
3069
3070                         if (r < 0) {
3071                                 free(filename);
3072                                 filename = NULL;
3073
3074                                 if (r != -ENOENT)
3075                                         return r;
3076
3077                                 /* Empty the symlink names for the next run */
3078                                 set_clear_free(symlink_names);
3079                                 continue;
3080                         }
3081
3082                         break;
3083                 }
3084         }
3085
3086         if (!filename)
3087                 /* Hmm, no suitable file found? */
3088                 return 0;
3089
3090         merged = u;
3091         r = merge_by_names(&merged, symlink_names, id);
3092         if (r < 0)
3093                 return r;
3094
3095         if (merged != u) {
3096                 u->load_state = UNIT_MERGED;
3097                 return 0;
3098         }
3099
3100         if (fstat(fileno(f), &st) < 0)
3101                 return -errno;
3102
3103         if (null_or_empty(&st))
3104                 u->load_state = UNIT_MASKED;
3105         else {
3106                 u->load_state = UNIT_LOADED;
3107
3108                 /* Now, parse the file contents */
3109                 r = config_parse(u->id, filename, f, UNIT_VTABLE(u)->sections,
3110                                  config_item_perf_lookup,
3111                                  (void*) load_fragment_gperf_lookup, false, true, u);
3112                 if (r < 0)
3113                         return r;
3114         }
3115
3116         free(u->fragment_path);
3117         u->fragment_path = filename;
3118         filename = NULL;
3119
3120         u->fragment_mtime = timespec_load(&st.st_mtim);
3121
3122         if (u->source_path) {
3123                 if (stat(u->source_path, &st) >= 0)
3124                         u->source_mtime = timespec_load(&st.st_mtim);
3125                 else
3126                         u->source_mtime = 0;
3127         }
3128
3129         return 0;
3130 }
3131
3132 int unit_load_fragment(Unit *u) {
3133         int r;
3134         Iterator i;
3135         const char *t;
3136
3137         assert(u);
3138         assert(u->load_state == UNIT_STUB);
3139         assert(u->id);
3140
3141         /* First, try to find the unit under its id. We always look
3142          * for unit files in the default directories, to make it easy
3143          * to override things by placing things in /etc/systemd/system */
3144         r = load_from_path(u, u->id);
3145         if (r < 0)
3146                 return r;
3147
3148         /* Try to find an alias we can load this with */
3149         if (u->load_state == UNIT_STUB)
3150                 SET_FOREACH(t, u->names, i) {
3151
3152                         if (t == u->id)
3153                                 continue;
3154
3155                         r = load_from_path(u, t);
3156                         if (r < 0)
3157                                 return r;
3158
3159                         if (u->load_state != UNIT_STUB)
3160                                 break;
3161                 }
3162
3163         /* And now, try looking for it under the suggested (originally linked) path */
3164         if (u->load_state == UNIT_STUB && u->fragment_path) {
3165
3166                 r = load_from_path(u, u->fragment_path);
3167                 if (r < 0)
3168                         return r;
3169
3170                 if (u->load_state == UNIT_STUB) {
3171                         /* Hmm, this didn't work? Then let's get rid
3172                          * of the fragment path stored for us, so that
3173                          * we don't point to an invalid location. */
3174                         free(u->fragment_path);
3175                         u->fragment_path = NULL;
3176                 }
3177         }
3178
3179         /* Look for a template */
3180         if (u->load_state == UNIT_STUB && u->instance) {
3181                 _cleanup_free_ char *k;
3182
3183                 k = unit_name_template(u->id);
3184                 if (!k)
3185                         return -ENOMEM;
3186
3187                 r = load_from_path(u, k);
3188                 if (r < 0)
3189                         return r;
3190
3191                 if (u->load_state == UNIT_STUB)
3192                         SET_FOREACH(t, u->names, i) {
3193                                 _cleanup_free_ char *z = NULL;
3194
3195                                 if (t == u->id)
3196                                         continue;
3197
3198                                 z = unit_name_template(t);
3199                                 if (!z)
3200                                         return -ENOMEM;
3201
3202                                 r = load_from_path(u, z);
3203                                 if (r < 0)
3204                                         return r;
3205
3206                                 if (u->load_state != UNIT_STUB)
3207                                         break;
3208                         }
3209         }
3210
3211         return 0;
3212 }
3213
3214 void unit_dump_config_items(FILE *f) {
3215         static const struct {
3216                 const ConfigParserCallback callback;
3217                 const char *rvalue;
3218         } table[] = {
3219 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_LIBWRAP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
3220                 { config_parse_warn_compat,           "NOTSUPPORTED" },
3221 #endif
3222                 { config_parse_int,                   "INTEGER" },
3223                 { config_parse_unsigned,              "UNSIGNED" },
3224                 { config_parse_iec_size,              "SIZE" },
3225                 { config_parse_iec_off,               "SIZE" },
3226                 { config_parse_si_size,               "SIZE" },
3227                 { config_parse_bool,                  "BOOLEAN" },
3228                 { config_parse_string,                "STRING" },
3229                 { config_parse_path,                  "PATH" },
3230                 { config_parse_unit_path_printf,      "PATH" },
3231                 { config_parse_strv,                  "STRING [...]" },
3232                 { config_parse_exec_nice,             "NICE" },
3233                 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
3234                 { config_parse_exec_io_class,         "IOCLASS" },
3235                 { config_parse_exec_io_priority,      "IOPRIORITY" },
3236                 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
3237                 { config_parse_exec_cpu_sched_prio,   "CPUSCHEDPRIO" },
3238                 { config_parse_exec_cpu_affinity,     "CPUAFFINITY" },
3239                 { config_parse_mode,                  "MODE" },
3240                 { config_parse_unit_env_file,         "FILE" },
3241                 { config_parse_output,                "OUTPUT" },
3242                 { config_parse_input,                 "INPUT" },
3243                 { config_parse_log_facility,          "FACILITY" },
3244                 { config_parse_log_level,             "LEVEL" },
3245                 { config_parse_exec_capabilities,     "CAPABILITIES" },
3246                 { config_parse_exec_secure_bits,      "SECUREBITS" },
3247                 { config_parse_bounding_set,          "BOUNDINGSET" },
3248                 { config_parse_limit,                 "LIMIT" },
3249                 { config_parse_unit_deps,             "UNIT [...]" },
3250                 { config_parse_exec,                  "PATH [ARGUMENT [...]]" },
3251                 { config_parse_service_type,          "SERVICETYPE" },
3252                 { config_parse_service_restart,       "SERVICERESTART" },
3253 #ifdef HAVE_SYSV_COMPAT
3254                 { config_parse_sysv_priority,         "SYSVPRIORITY" },
3255 #endif
3256                 { config_parse_kill_mode,             "KILLMODE" },
3257                 { config_parse_kill_signal,           "SIGNAL" },
3258                 { config_parse_socket_listen,         "SOCKET [...]" },
3259                 { config_parse_socket_bind,           "SOCKETBIND" },
3260                 { config_parse_socket_bindtodevice,   "NETWORKINTERFACE" },
3261                 { config_parse_sec,                   "SECONDS" },
3262                 { config_parse_nsec,                  "NANOSECONDS" },
3263                 { config_parse_namespace_path_strv,   "PATH [...]" },
3264                 { config_parse_unit_requires_mounts_for, "PATH [...]" },
3265                 { config_parse_exec_mount_flags,      "MOUNTFLAG [...]" },
3266                 { config_parse_unit_string_printf,    "STRING" },
3267                 { config_parse_trigger_unit,          "UNIT" },
3268                 { config_parse_timer,                 "TIMER" },
3269                 { config_parse_path_spec,             "PATH" },
3270                 { config_parse_notify_access,         "ACCESS" },
3271                 { config_parse_ip_tos,                "TOS" },
3272                 { config_parse_unit_condition_path,   "CONDITION" },
3273                 { config_parse_unit_condition_string, "CONDITION" },
3274                 { config_parse_unit_condition_null,   "CONDITION" },
3275                 { config_parse_unit_slice,            "SLICE" },
3276                 { config_parse_documentation,         "URL" },
3277                 { config_parse_service_timeout,       "SECONDS" },
3278                 { config_parse_start_limit_action,    "ACTION" },
3279                 { config_parse_set_status,            "STATUS" },
3280                 { config_parse_service_sockets,       "SOCKETS" },
3281                 { config_parse_environ,               "ENVIRON" },
3282 #ifdef HAVE_SECCOMP
3283                 { config_parse_syscall_filter,        "SYSCALLS" },
3284                 { config_parse_syscall_archs,         "ARCHS" },
3285                 { config_parse_syscall_errno,         "ERRNO" },
3286                 { config_parse_address_families,      "FAMILIES" },
3287 #endif
3288                 { config_parse_cpu_shares,            "SHARES" },
3289                 { config_parse_memory_limit,          "LIMIT" },
3290                 { config_parse_device_allow,          "DEVICE" },
3291                 { config_parse_device_policy,         "POLICY" },
3292                 { config_parse_blockio_bandwidth,     "BANDWIDTH" },
3293                 { config_parse_blockio_weight,        "WEIGHT" },
3294                 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
3295                 { config_parse_long,                  "LONG" },
3296                 { config_parse_socket_service,        "SERVICE" },
3297 #ifdef HAVE_SELINUX
3298                 { config_parse_exec_selinux_context,  "LABEL" },
3299 #endif
3300                 { config_parse_job_mode,              "MODE" },
3301                 { config_parse_job_mode_isolate,      "BOOLEAN" },
3302                 { config_parse_personality,           "PERSONALITY" },
3303         };
3304
3305         const char *prev = NULL;
3306         const char *i;
3307
3308         assert(f);
3309
3310         NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
3311                 const char *rvalue = "OTHER", *lvalue;
3312                 unsigned j;
3313                 size_t prefix_len;
3314                 const char *dot;
3315                 const ConfigPerfItem *p;
3316
3317                 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
3318
3319                 dot = strchr(i, '.');
3320                 lvalue = dot ? dot + 1 : i;
3321                 prefix_len = dot-i;
3322
3323                 if (dot)
3324                         if (!prev || !strneq(prev, i, prefix_len+1)) {
3325                                 if (prev)
3326                                         fputc('\n', f);
3327
3328                                 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
3329                         }
3330
3331                 for (j = 0; j < ELEMENTSOF(table); j++)
3332                         if (p->parse == table[j].callback) {
3333                                 rvalue = table[j].rvalue;
3334                                 break;
3335                         }
3336
3337                 fprintf(f, "%s=%s\n", lvalue, rvalue);
3338                 prev = i;
3339         }
3340 }