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