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