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