chiark / gitweb /
socket: introduce SELinuxLabelViaNet option
[elogind.git] / src / core / load-fragment.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2010 Lennart Poettering
7   Copyright 2012 Holger Hans Peter Freyther
8
9   systemd is free software; you can redistribute it and/or modify it
10   under the terms of the GNU Lesser General Public License as published by
11   the Free Software Foundation; either version 2.1 of the License, or
12   (at your option) any later version.
13
14   systemd is distributed in the hope that it will be useful, but
15   WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17   Lesser General Public License for more details.
18
19   You should have received a copy of the GNU Lesser General Public License
20   along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 ***/
22
23 #include <linux/oom.h>
24 #include <assert.h>
25 #include <errno.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <fcntl.h>
29 #include <sched.h>
30 #include <sys/prctl.h>
31 #include <sys/mount.h>
32 #include <linux/fs.h>
33 #include <sys/stat.h>
34 #include <sys/time.h>
35 #include <sys/resource.h>
36 #include <sys/types.h>
37 #include <grp.h>
38
39 #ifdef HAVE_SECCOMP
40 #include <seccomp.h>
41 #endif
42
43 #include "sd-messages.h"
44 #include "unit.h"
45 #include "strv.h"
46 #include "conf-parser.h"
47 #include "load-fragment.h"
48 #include "log.h"
49 #include "ioprio.h"
50 #include "securebits.h"
51 #include "missing.h"
52 #include "unit-name.h"
53 #include "unit-printf.h"
54 #include "utf8.h"
55 #include "path-util.h"
56 #include "env-util.h"
57 #include "cgroup.h"
58 #include "bus-util.h"
59 #include "bus-error.h"
60 #include "errno-list.h"
61 #include "af-list.h"
62
63 #ifdef HAVE_SECCOMP
64 #include "seccomp-util.h"
65 #endif
66
67 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
68 int config_parse_warn_compat(
69                 const char *unit,
70                 const char *filename,
71                 unsigned line,
72                 const char *section,
73                 unsigned section_line,
74                 const char *lvalue,
75                 int ltype,
76                 const char *rvalue,
77                 void *data,
78                 void *userdata) {
79
80         log_syntax(unit, LOG_DEBUG, filename, line, EINVAL,
81                    "Support for option %s= has been disabled at compile time and is ignored",
82                    lvalue);
83         return 0;
84 }
85 #endif
86
87 int config_parse_unit_deps(const char *unit,
88                            const char *filename,
89                            unsigned line,
90                            const char *section,
91                            unsigned section_line,
92                            const char *lvalue,
93                            int ltype,
94                            const char *rvalue,
95                            void *data,
96                            void *userdata) {
97
98         UnitDependency d = ltype;
99         Unit *u = userdata;
100         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_timer(const char *unit,
1319                        const char *filename,
1320                        unsigned line,
1321                        const char *section,
1322                        unsigned section_line,
1323                        const char *lvalue,
1324                        int ltype,
1325                        const char *rvalue,
1326                        void *data,
1327                        void *userdata) {
1328
1329         Timer *t = data;
1330         usec_t u = 0;
1331         TimerValue *v;
1332         TimerBase b;
1333         CalendarSpec *c = NULL;
1334
1335         assert(filename);
1336         assert(lvalue);
1337         assert(rvalue);
1338         assert(data);
1339
1340         if (isempty(rvalue)) {
1341                 /* Empty assignment resets list */
1342                 timer_free_values(t);
1343                 return 0;
1344         }
1345
1346         b = timer_base_from_string(lvalue);
1347         if (b < 0) {
1348                 log_syntax(unit, LOG_ERR, filename, line, -b,
1349                            "Failed to parse timer base, ignoring: %s", lvalue);
1350                 return 0;
1351         }
1352
1353         if (b == TIMER_CALENDAR) {
1354                 if (calendar_spec_from_string(rvalue, &c) < 0) {
1355                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1356                                    "Failed to parse calendar specification, ignoring: %s",
1357                                    rvalue);
1358                         return 0;
1359                 }
1360         } else {
1361                 if (parse_sec(rvalue, &u) < 0) {
1362                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1363                                    "Failed to parse timer value, ignoring: %s",
1364                                    rvalue);
1365                         return 0;
1366                 }
1367         }
1368
1369         v = new0(TimerValue, 1);
1370         if (!v)
1371                 return log_oom();
1372
1373         v->base = b;
1374         v->value = u;
1375         v->calendar_spec = c;
1376
1377         LIST_PREPEND(value, t->values, v);
1378
1379         return 0;
1380 }
1381
1382 int config_parse_trigger_unit(
1383                 const char *unit,
1384                 const char *filename,
1385                 unsigned line,
1386                 const char *section,
1387                 unsigned section_line,
1388                 const char *lvalue,
1389                 int ltype,
1390                 const char *rvalue,
1391                 void *data,
1392                 void *userdata) {
1393
1394         _cleanup_free_ char *p = NULL;
1395         Unit *u = data;
1396         UnitType type;
1397         int r;
1398
1399         assert(filename);
1400         assert(lvalue);
1401         assert(rvalue);
1402         assert(data);
1403
1404         if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
1405                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1406                            "Multiple units to trigger specified, ignoring: %s", rvalue);
1407                 return 0;
1408         }
1409
1410         r = unit_name_printf(u, rvalue, &p);
1411         if (r < 0)
1412                 log_syntax(unit, LOG_ERR, filename, line, -r,
1413                            "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1414
1415         type = unit_name_to_type(p ?: rvalue);
1416         if (type < 0) {
1417                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1418                            "Unit type not valid, ignoring: %s", rvalue);
1419                 return 0;
1420         }
1421
1422         if (type == u->type) {
1423                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1424                            "Trigger cannot be of same type, ignoring: %s", rvalue);
1425                 return 0;
1426         }
1427
1428         r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p ?: rvalue, NULL, true);
1429         if (r < 0) {
1430                 log_syntax(unit, LOG_ERR, filename, line, -r,
1431                            "Failed to add trigger on %s, ignoring: %s", p ?: rvalue, strerror(-r));
1432                 return 0;
1433         }
1434
1435         return 0;
1436 }
1437
1438 int config_parse_path_spec(const char *unit,
1439                            const char *filename,
1440                            unsigned line,
1441                            const char *section,
1442                            unsigned section_line,
1443                            const char *lvalue,
1444                            int ltype,
1445                            const char *rvalue,
1446                            void *data,
1447                            void *userdata) {
1448
1449         Path *p = data;
1450         PathSpec *s;
1451         PathType b;
1452         _cleanup_free_ char *k = NULL;
1453         int r;
1454
1455         assert(filename);
1456         assert(lvalue);
1457         assert(rvalue);
1458         assert(data);
1459
1460         if (isempty(rvalue)) {
1461                 /* Empty assignment clears list */
1462                 path_free_specs(p);
1463                 return 0;
1464         }
1465
1466         b = path_type_from_string(lvalue);
1467         if (b < 0) {
1468                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1469                            "Failed to parse path type, ignoring: %s", lvalue);
1470                 return 0;
1471         }
1472
1473         r = unit_full_printf(UNIT(p), rvalue, &k);
1474         if (r < 0) {
1475                 k = strdup(rvalue);
1476                 if (!k)
1477                         return log_oom();
1478                 else
1479                         log_syntax(unit, LOG_ERR, filename, line, -r,
1480                                    "Failed to resolve unit specifiers on %s. Ignoring.",
1481                                    rvalue);
1482         }
1483
1484         if (!path_is_absolute(k)) {
1485                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1486                            "Path is not absolute, ignoring: %s", k);
1487                 return 0;
1488         }
1489
1490         s = new0(PathSpec, 1);
1491         if (!s)
1492                 return log_oom();
1493
1494         s->unit = UNIT(p);
1495         s->path = path_kill_slashes(k);
1496         k = NULL;
1497         s->type = b;
1498         s->inotify_fd = -1;
1499
1500         LIST_PREPEND(spec, p->specs, s);
1501
1502         return 0;
1503 }
1504
1505 int config_parse_socket_service(const char *unit,
1506                                 const char *filename,
1507                                 unsigned line,
1508                                 const char *section,
1509                                 unsigned section_line,
1510                                 const char *lvalue,
1511                                 int ltype,
1512                                 const char *rvalue,
1513                                 void *data,
1514                                 void *userdata) {
1515
1516         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1517         Socket *s = data;
1518         int r;
1519         Unit *x;
1520         _cleanup_free_ char *p = NULL;
1521
1522         assert(filename);
1523         assert(lvalue);
1524         assert(rvalue);
1525         assert(data);
1526
1527         r = unit_name_printf(UNIT(s), rvalue, &p);
1528         if (r < 0) {
1529                 log_syntax(unit, LOG_ERR, filename, line, -r,
1530                            "Failed to resolve specifiers, ignoring: %s", rvalue);
1531                 return 0;
1532         }
1533
1534         if (!endswith(p, ".service")) {
1535                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1536                            "Unit must be of type service, ignoring: %s", rvalue);
1537                 return 0;
1538         }
1539
1540         r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
1541         if (r < 0) {
1542                 log_syntax(unit, LOG_ERR, filename, line, -r,
1543                            "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1544                 return 0;
1545         }
1546
1547         unit_ref_set(&s->service, x);
1548
1549         return 0;
1550 }
1551
1552 int config_parse_service_sockets(const char *unit,
1553                                  const char *filename,
1554                                  unsigned line,
1555                                  const char *section,
1556                                  unsigned section_line,
1557                                  const char *lvalue,
1558                                  int ltype,
1559                                  const char *rvalue,
1560                                  void *data,
1561                                  void *userdata) {
1562
1563         Service *s = data;
1564         int r;
1565         const char *word, *state;
1566         size_t l;
1567
1568         assert(filename);
1569         assert(lvalue);
1570         assert(rvalue);
1571         assert(data);
1572
1573         FOREACH_WORD_QUOTED(word, l, rvalue, state) {
1574                 _cleanup_free_ char *t = NULL, *k = NULL;
1575
1576                 t = strndup(word, l);
1577                 if (!t)
1578                         return log_oom();
1579
1580                 r = unit_name_printf(UNIT(s), t, &k);
1581                 if (r < 0)
1582                         log_syntax(unit, LOG_ERR, filename, line, -r,
1583                                    "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1584
1585                 if (!endswith(k ?: t, ".socket")) {
1586                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1587                                    "Unit must be of type socket, ignoring: %s", k ?: t);
1588                         continue;
1589                 }
1590
1591                 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k ?: t, NULL, true);
1592                 if (r < 0)
1593                         log_syntax(unit, LOG_ERR, filename, line, -r,
1594                                    "Failed to add dependency on %s, ignoring: %s",
1595                                    k ?: t, strerror(-r));
1596
1597                 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k ?: t, NULL, true);
1598                 if (r < 0)
1599                         return r;
1600         }
1601         if (!isempty(state))
1602                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1603                            "Trailing garbage, ignoring.");
1604
1605         return 0;
1606 }
1607
1608 int config_parse_service_timeout(const char *unit,
1609                                  const char *filename,
1610                                  unsigned line,
1611                                  const char *section,
1612                                  unsigned section_line,
1613                                  const char *lvalue,
1614                                  int ltype,
1615                                  const char *rvalue,
1616                                  void *data,
1617                                  void *userdata) {
1618
1619         Service *s = userdata;
1620         int r;
1621
1622         assert(filename);
1623         assert(lvalue);
1624         assert(rvalue);
1625         assert(s);
1626
1627         r = config_parse_sec(unit, filename, line, section, section_line, lvalue, ltype,
1628                              rvalue, data, userdata);
1629         if (r < 0)
1630                 return r;
1631
1632         if (streq(lvalue, "TimeoutSec")) {
1633                 s->start_timeout_defined = true;
1634                 s->timeout_stop_usec = s->timeout_start_usec;
1635         } else if (streq(lvalue, "TimeoutStartSec"))
1636                 s->start_timeout_defined = true;
1637
1638         return 0;
1639 }
1640
1641 int config_parse_busname_service(
1642                 const char *unit,
1643                 const char *filename,
1644                 unsigned line,
1645                 const char *section,
1646                 unsigned section_line,
1647                 const char *lvalue,
1648                 int ltype,
1649                 const char *rvalue,
1650                 void *data,
1651                 void *userdata) {
1652
1653         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1654         BusName *n = data;
1655         int r;
1656         Unit *x;
1657         _cleanup_free_ char *p = NULL;
1658
1659         assert(filename);
1660         assert(lvalue);
1661         assert(rvalue);
1662         assert(data);
1663
1664         r = unit_name_printf(UNIT(n), rvalue, &p);
1665         if (r < 0) {
1666                 log_syntax(unit, LOG_ERR, filename, line, -r,
1667                            "Failed to resolve specifiers, ignoring: %s", rvalue);
1668                 return 0;
1669         }
1670
1671         if (!endswith(p, ".service")) {
1672                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1673                            "Unit must be of type service, ignoring: %s", rvalue);
1674                 return 0;
1675         }
1676
1677         r = manager_load_unit(UNIT(n)->manager, p, NULL, &error, &x);
1678         if (r < 0) {
1679                 log_syntax(unit, LOG_ERR, filename, line, -r,
1680                            "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1681                 return 0;
1682         }
1683
1684         unit_ref_set(&n->service, x);
1685
1686         return 0;
1687 }
1688
1689 DEFINE_CONFIG_PARSE_ENUM(config_parse_bus_policy_world, busname_policy_access, BusNamePolicyAccess, "Failed to parse bus name policy access");
1690
1691 int config_parse_bus_policy(
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_free_ BusNamePolicy *p = NULL;
1704         _cleanup_free_ char *id_str = NULL;
1705         BusName *busname = data;
1706         char *access_str;
1707
1708         assert(filename);
1709         assert(lvalue);
1710         assert(rvalue);
1711         assert(data);
1712
1713         p = new0(BusNamePolicy, 1);
1714         if (!p)
1715                 return log_oom();
1716
1717         if (streq(lvalue, "AllowUser"))
1718                 p->type = BUSNAME_POLICY_TYPE_USER;
1719         else if (streq(lvalue, "AllowGroup"))
1720                 p->type = BUSNAME_POLICY_TYPE_GROUP;
1721         else
1722                 assert_not_reached("Unknown lvalue");
1723
1724         id_str = strdup(rvalue);
1725         if (!id_str)
1726                 return log_oom();
1727
1728         access_str = strpbrk(id_str, WHITESPACE);
1729         if (!access_str) {
1730                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1731                            "Invalid busname policy value '%s'", rvalue);
1732                 return 0;
1733         }
1734
1735         *access_str = '\0';
1736         access_str++;
1737         access_str += strspn(access_str, WHITESPACE);
1738
1739         p->access = busname_policy_access_from_string(access_str);
1740         if (p->access < 0) {
1741                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1742                            "Invalid busname policy access type '%s'", access_str);
1743                 return 0;
1744         }
1745
1746         p->name = id_str;
1747         id_str = NULL;
1748
1749         LIST_PREPEND(policy, busname->policy, p);
1750         p = NULL;
1751
1752         return 0;
1753 }
1754
1755 int config_parse_unit_env_file(const char *unit,
1756                                const char *filename,
1757                                unsigned line,
1758                                const char *section,
1759                                unsigned section_line,
1760                                const char *lvalue,
1761                                int ltype,
1762                                const char *rvalue,
1763                                void *data,
1764                                void *userdata) {
1765
1766         char ***env = data;
1767         Unit *u = userdata;
1768         _cleanup_free_ char *n = NULL;
1769         const char *s;
1770         int r;
1771
1772         assert(filename);
1773         assert(lvalue);
1774         assert(rvalue);
1775         assert(data);
1776
1777         if (isempty(rvalue)) {
1778                 /* Empty assignment frees the list */
1779                 strv_free(*env);
1780                 *env = NULL;
1781                 return 0;
1782         }
1783
1784         r = unit_full_printf(u, rvalue, &n);
1785         if (r < 0)
1786                 log_syntax(unit, LOG_ERR, filename, line, -r,
1787                            "Failed to resolve specifiers, ignoring: %s", rvalue);
1788
1789         s = n ?: rvalue;
1790         if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1791                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1792                            "Path '%s' is not absolute, ignoring.", s);
1793                 return 0;
1794         }
1795
1796         r = strv_extend(env, s);
1797         if (r < 0)
1798                 return log_oom();
1799
1800         return 0;
1801 }
1802
1803 int config_parse_environ(const char *unit,
1804                          const char *filename,
1805                          unsigned line,
1806                          const char *section,
1807                          unsigned section_line,
1808                          const char *lvalue,
1809                          int ltype,
1810                          const char *rvalue,
1811                          void *data,
1812                          void *userdata) {
1813
1814         Unit *u = userdata;
1815         char*** env = data;
1816         const char *word, *state;
1817         size_t l;
1818         _cleanup_free_ char *k = NULL;
1819         int r;
1820
1821         assert(filename);
1822         assert(lvalue);
1823         assert(rvalue);
1824         assert(data);
1825
1826         if (isempty(rvalue)) {
1827                 /* Empty assignment resets the list */
1828                 strv_free(*env);
1829                 *env = NULL;
1830                 return 0;
1831         }
1832
1833         if (u) {
1834                 r = unit_full_printf(u, rvalue, &k);
1835                 if (r < 0)
1836                         log_syntax(unit, LOG_ERR, filename, line, -r,
1837                                    "Failed to resolve specifiers, ignoring: %s", rvalue);
1838         }
1839
1840         if (!k)
1841                 k = strdup(rvalue);
1842         if (!k)
1843                 return log_oom();
1844
1845         FOREACH_WORD_QUOTED(word, l, k, state) {
1846                 _cleanup_free_ char *n;
1847                 char **x;
1848
1849                 n = cunescape_length(word, l);
1850                 if (!n)
1851                         return log_oom();
1852
1853                 if (!env_assignment_is_valid(n)) {
1854                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1855                                    "Invalid environment assignment, ignoring: %s", rvalue);
1856                         continue;
1857                 }
1858
1859                 x = strv_env_set(*env, n);
1860                 if (!x)
1861                         return log_oom();
1862
1863                 strv_free(*env);
1864                 *env = x;
1865         }
1866         if (!isempty(state))
1867                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1868                            "Trailing garbage, ignoring.");
1869
1870         return 0;
1871 }
1872
1873 int config_parse_ip_tos(const char *unit,
1874                         const char *filename,
1875                         unsigned line,
1876                         const char *section,
1877                         unsigned section_line,
1878                         const char *lvalue,
1879                         int ltype,
1880                         const char *rvalue,
1881                         void *data,
1882                         void *userdata) {
1883
1884         int *ip_tos = data, x;
1885
1886         assert(filename);
1887         assert(lvalue);
1888         assert(rvalue);
1889         assert(data);
1890
1891         x = ip_tos_from_string(rvalue);
1892         if (x < 0) {
1893                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1894                            "Failed to parse IP TOS value, ignoring: %s", rvalue);
1895                 return 0;
1896         }
1897
1898         *ip_tos = x;
1899         return 0;
1900 }
1901
1902 int config_parse_unit_condition_path(const char *unit,
1903                                      const char *filename,
1904                                      unsigned line,
1905                                      const char *section,
1906                                      unsigned section_line,
1907                                      const char *lvalue,
1908                                      int ltype,
1909                                      const char *rvalue,
1910                                      void *data,
1911                                      void *userdata) {
1912
1913         ConditionType cond = ltype;
1914         Unit *u = data;
1915         bool trigger, negate;
1916         Condition *c;
1917         _cleanup_free_ char *p = NULL;
1918         int r;
1919
1920         assert(filename);
1921         assert(lvalue);
1922         assert(rvalue);
1923         assert(data);
1924
1925         if (isempty(rvalue)) {
1926                 /* Empty assignment resets the list */
1927                 condition_free_list(u->conditions);
1928                 u->conditions = NULL;
1929                 return 0;
1930         }
1931
1932         trigger = rvalue[0] == '|';
1933         if (trigger)
1934                 rvalue++;
1935
1936         negate = rvalue[0] == '!';
1937         if (negate)
1938                 rvalue++;
1939
1940         r = unit_full_printf(u, rvalue, &p);
1941         if (r < 0)
1942                 log_syntax(unit, LOG_ERR, filename, line, -r,
1943                            "Failed to resolve specifiers, ignoring: %s", rvalue);
1944         if (!p) {
1945                 p = strdup(rvalue);
1946                 if (!p)
1947                         return log_oom();
1948         }
1949
1950         if (!path_is_absolute(p)) {
1951                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1952                            "Path in condition not absolute, ignoring: %s", p);
1953                 return 0;
1954         }
1955
1956         c = condition_new(cond, p, trigger, negate);
1957         if (!c)
1958                 return log_oom();
1959
1960         LIST_PREPEND(conditions, u->conditions, c);
1961         return 0;
1962 }
1963
1964 int config_parse_unit_condition_string(const char *unit,
1965                                        const char *filename,
1966                                        unsigned line,
1967                                        const char *section,
1968                                        unsigned section_line,
1969                                        const char *lvalue,
1970                                        int ltype,
1971                                        const char *rvalue,
1972                                        void *data,
1973                                        void *userdata) {
1974
1975         ConditionType cond = ltype;
1976         Unit *u = data;
1977         bool trigger, negate;
1978         Condition *c;
1979         _cleanup_free_ char *s = NULL;
1980         int r;
1981
1982         assert(filename);
1983         assert(lvalue);
1984         assert(rvalue);
1985         assert(data);
1986
1987         if (isempty(rvalue)) {
1988                 /* Empty assignment resets the list */
1989                 condition_free_list(u->conditions);
1990                 u->conditions = NULL;
1991                 return 0;
1992         }
1993
1994         trigger = rvalue[0] == '|';
1995         if (trigger)
1996                 rvalue++;
1997
1998         negate = rvalue[0] == '!';
1999         if (negate)
2000                 rvalue++;
2001
2002         r = unit_full_printf(u, rvalue, &s);
2003         if (r < 0)
2004                 log_syntax(unit, LOG_ERR, filename, line, -r,
2005                            "Failed to resolve specifiers, ignoring: %s", rvalue);
2006         if (!s) {
2007                 s = strdup(rvalue);
2008                 if (!s)
2009                         return log_oom();
2010         }
2011
2012         c = condition_new(cond, s, trigger, negate);
2013         if (!c)
2014                 return log_oom();
2015
2016         LIST_PREPEND(conditions, u->conditions, c);
2017         return 0;
2018 }
2019
2020 int config_parse_unit_condition_null(const char *unit,
2021                                      const char *filename,
2022                                      unsigned line,
2023                                      const char *section,
2024                                      unsigned section_line,
2025                                      const char *lvalue,
2026                                      int ltype,
2027                                      const char *rvalue,
2028                                      void *data,
2029                                      void *userdata) {
2030
2031         Unit *u = data;
2032         Condition *c;
2033         bool trigger, negate;
2034         int b;
2035
2036         assert(filename);
2037         assert(lvalue);
2038         assert(rvalue);
2039         assert(data);
2040
2041         if (isempty(rvalue)) {
2042                 /* Empty assignment resets the list */
2043                 condition_free_list(u->conditions);
2044                 u->conditions = NULL;
2045                 return 0;
2046         }
2047
2048         trigger = rvalue[0] == '|';
2049         if (trigger)
2050                 rvalue++;
2051
2052         negate = rvalue[0] == '!';
2053         if (negate)
2054                 rvalue++;
2055
2056         b = parse_boolean(rvalue);
2057         if (b < 0) {
2058                 log_syntax(unit, LOG_ERR, filename, line, -b,
2059                            "Failed to parse boolean value in condition, ignoring: %s",
2060                            rvalue);
2061                 return 0;
2062         }
2063
2064         if (!b)
2065                 negate = !negate;
2066
2067         c = condition_new(CONDITION_NULL, NULL, trigger, negate);
2068         if (!c)
2069                 return log_oom();
2070
2071         LIST_PREPEND(conditions, u->conditions, c);
2072         return 0;
2073 }
2074
2075 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
2076 DEFINE_CONFIG_PARSE_ENUM(config_parse_failure_action, failure_action, FailureAction, "Failed to parse failure action specifier");
2077
2078 int config_parse_unit_requires_mounts_for(
2079                 const char *unit,
2080                 const char *filename,
2081                 unsigned line,
2082                 const char *section,
2083                 unsigned section_line,
2084                 const char *lvalue,
2085                 int ltype,
2086                 const char *rvalue,
2087                 void *data,
2088                 void *userdata) {
2089
2090         Unit *u = userdata;
2091         const char *word, *state;
2092         size_t l;
2093
2094         assert(filename);
2095         assert(lvalue);
2096         assert(rvalue);
2097         assert(data);
2098
2099         FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2100                 int r;
2101                 _cleanup_free_ char *n;
2102
2103                 n = strndup(word, l);
2104                 if (!n)
2105                         return log_oom();
2106
2107                 if (!utf8_is_valid(n)) {
2108                         log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
2109                         continue;
2110                 }
2111
2112                 r = unit_require_mounts_for(u, n);
2113                 if (r < 0) {
2114                         log_syntax(unit, LOG_ERR, filename, line, -r,
2115                                    "Failed to add required mount for, ignoring: %s", rvalue);
2116                         continue;
2117                 }
2118         }
2119         if (!isempty(state))
2120                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2121                            "Trailing garbage, ignoring.");
2122
2123         return 0;
2124 }
2125
2126 int config_parse_documentation(const char *unit,
2127                                const char *filename,
2128                                unsigned line,
2129                                const char *section,
2130                                unsigned section_line,
2131                                const char *lvalue,
2132                                int ltype,
2133                                const char *rvalue,
2134                                void *data,
2135                                void *userdata) {
2136
2137         Unit *u = userdata;
2138         int r;
2139         char **a, **b;
2140
2141         assert(filename);
2142         assert(lvalue);
2143         assert(rvalue);
2144         assert(u);
2145
2146         if (isempty(rvalue)) {
2147                 /* Empty assignment resets the list */
2148                 strv_free(u->documentation);
2149                 u->documentation = NULL;
2150                 return 0;
2151         }
2152
2153         r = config_parse_unit_strv_printf(unit, filename, line, section, section_line, lvalue, ltype,
2154                                           rvalue, data, userdata);
2155         if (r < 0)
2156                 return r;
2157
2158         for (a = b = u->documentation; a && *a; a++) {
2159
2160                 if (is_valid_documentation_url(*a))
2161                         *(b++) = *a;
2162                 else {
2163                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2164                                    "Invalid URL, ignoring: %s", *a);
2165                         free(*a);
2166                 }
2167         }
2168         if (b)
2169                 *b = NULL;
2170
2171         return r;
2172 }
2173
2174 #ifdef HAVE_SECCOMP
2175 int config_parse_syscall_filter(
2176                 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         static const char default_syscalls[] =
2188                 "execve\0"
2189                 "exit\0"
2190                 "exit_group\0"
2191                 "rt_sigreturn\0"
2192                 "sigreturn\0";
2193
2194         ExecContext *c = data;
2195         Unit *u = userdata;
2196         bool invert = false;
2197         const char *word, *state;
2198         size_t l;
2199         int r;
2200
2201         assert(filename);
2202         assert(lvalue);
2203         assert(rvalue);
2204         assert(u);
2205
2206         if (isempty(rvalue)) {
2207                 /* Empty assignment resets the list */
2208                 set_free(c->syscall_filter);
2209                 c->syscall_filter = NULL;
2210                 c->syscall_whitelist = false;
2211                 return 0;
2212         }
2213
2214         if (rvalue[0] == '~') {
2215                 invert = true;
2216                 rvalue++;
2217         }
2218
2219         if (!c->syscall_filter) {
2220                 c->syscall_filter = set_new(trivial_hash_func, trivial_compare_func);
2221                 if (!c->syscall_filter)
2222                         return log_oom();
2223
2224                 if (invert)
2225                         /* Allow everything but the ones listed */
2226                         c->syscall_whitelist = false;
2227                 else {
2228                         const char *i;
2229
2230                         /* Allow nothing but the ones listed */
2231                         c->syscall_whitelist = true;
2232
2233                         /* Accept default syscalls if we are on a whitelist */
2234                         NULSTR_FOREACH(i, default_syscalls)  {
2235                                 int id;
2236
2237                                 id = seccomp_syscall_resolve_name(i);
2238                                 if (id < 0)
2239                                         continue;
2240
2241                                 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2242                                 if (r == -EEXIST)
2243                                         continue;
2244                                 if (r < 0)
2245                                         return log_oom();
2246                         }
2247                 }
2248         }
2249
2250         FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2251                 _cleanup_free_ char *t = NULL;
2252                 int id;
2253
2254                 t = strndup(word, l);
2255                 if (!t)
2256                         return log_oom();
2257
2258                 id = seccomp_syscall_resolve_name(t);
2259                 if (id < 0)  {
2260                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2261                                    "Failed to parse system call, ignoring: %s", t);
2262                         continue;
2263                 }
2264
2265                 /* If we previously wanted to forbid a syscall and now
2266                  * we want to allow it, then remove it from the list
2267                  */
2268                 if (!invert == c->syscall_whitelist)  {
2269                         r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2270                         if (r == -EEXIST)
2271                                 continue;
2272                         if (r < 0)
2273                                 return log_oom();
2274                 } else
2275                         set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
2276         }
2277         if (!isempty(state))
2278                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2279                            "Trailing garbage, ignoring.");
2280
2281         /* Turn on NNP, but only if it wasn't configured explicitly
2282          * before, and only if we are in user mode. */
2283         if (!c->no_new_privileges_set && u->manager->running_as == SYSTEMD_USER)
2284                 c->no_new_privileges = true;
2285
2286         return 0;
2287 }
2288
2289 int config_parse_syscall_archs(
2290                 const char *unit,
2291                 const char *filename,
2292                 unsigned line,
2293                 const char *section,
2294                 unsigned section_line,
2295                 const char *lvalue,
2296                 int ltype,
2297                 const char *rvalue,
2298                 void *data,
2299                 void *userdata) {
2300
2301         Set **archs = data;
2302         const char *word, *state;
2303         size_t l;
2304         int r;
2305
2306         if (isempty(rvalue)) {
2307                 set_free(*archs);
2308                 *archs = NULL;
2309                 return 0;
2310         }
2311
2312         r = set_ensure_allocated(archs, trivial_hash_func, trivial_compare_func);
2313         if (r < 0)
2314                 return log_oom();
2315
2316         FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2317                 _cleanup_free_ char *t = NULL;
2318                 uint32_t a;
2319
2320                 t = strndup(word, l);
2321                 if (!t)
2322                         return log_oom();
2323
2324                 r = seccomp_arch_from_string(t, &a);
2325                 if (r < 0) {
2326                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2327                                    "Failed to parse system call architecture, ignoring: %s", t);
2328                         continue;
2329                 }
2330
2331                 r = set_put(*archs, UINT32_TO_PTR(a + 1));
2332                 if (r == -EEXIST)
2333                         continue;
2334                 if (r < 0)
2335                         return log_oom();
2336         }
2337         if (!isempty(state))
2338                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2339                            "Trailing garbage, ignoring.");
2340
2341         return 0;
2342 }
2343
2344 int config_parse_syscall_errno(
2345                 const char *unit,
2346                 const char *filename,
2347                 unsigned line,
2348                 const char *section,
2349                 unsigned section_line,
2350                 const char *lvalue,
2351                 int ltype,
2352                 const char *rvalue,
2353                 void *data,
2354                 void *userdata) {
2355
2356         ExecContext *c = data;
2357         int e;
2358
2359         assert(filename);
2360         assert(lvalue);
2361         assert(rvalue);
2362
2363         if (isempty(rvalue)) {
2364                 /* Empty assignment resets to KILL */
2365                 c->syscall_errno = 0;
2366                 return 0;
2367         }
2368
2369         e = errno_from_name(rvalue);
2370         if (e < 0) {
2371                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2372                            "Failed to parse error number, ignoring: %s", rvalue);
2373                 return 0;
2374         }
2375
2376         c->syscall_errno = e;
2377         return 0;
2378 }
2379
2380 int config_parse_address_families(
2381                 const char *unit,
2382                 const char *filename,
2383                 unsigned line,
2384                 const char *section,
2385                 unsigned section_line,
2386                 const char *lvalue,
2387                 int ltype,
2388                 const char *rvalue,
2389                 void *data,
2390                 void *userdata) {
2391
2392         ExecContext *c = data;
2393         Unit *u = userdata;
2394         bool invert = false;
2395         const char *word, *state;
2396         size_t l;
2397         int r;
2398
2399         assert(filename);
2400         assert(lvalue);
2401         assert(rvalue);
2402         assert(u);
2403
2404         if (isempty(rvalue)) {
2405                 /* Empty assignment resets the list */
2406                 set_free(c->address_families);
2407                 c->address_families = NULL;
2408                 c->address_families_whitelist = false;
2409                 return 0;
2410         }
2411
2412         if (rvalue[0] == '~') {
2413                 invert = true;
2414                 rvalue++;
2415         }
2416
2417         if (!c->address_families) {
2418                 c->address_families = set_new(trivial_hash_func, trivial_compare_func);
2419                 if (!c->address_families)
2420                         return log_oom();
2421
2422                 c->address_families_whitelist = !invert;
2423         }
2424
2425         FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2426                 _cleanup_free_ char *t = NULL;
2427                 int af;
2428
2429                 t = strndup(word, l);
2430                 if (!t)
2431                         return log_oom();
2432
2433                 af = af_from_name(t);
2434                 if (af <= 0)  {
2435                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2436                                    "Failed to parse address family, ignoring: %s", t);
2437                         continue;
2438                 }
2439
2440                 /* If we previously wanted to forbid an address family and now
2441                  * we want to allow it, then remove it from the list
2442                  */
2443                 if (!invert == c->address_families_whitelist)  {
2444                         r = set_put(c->address_families, INT_TO_PTR(af));
2445                         if (r == -EEXIST)
2446                                 continue;
2447                         if (r < 0)
2448                                 return log_oom();
2449                 } else
2450                         set_remove(c->address_families, INT_TO_PTR(af));
2451         }
2452         if (!isempty(state))
2453                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2454                            "Trailing garbage, ignoring.");
2455
2456         return 0;
2457 }
2458 #endif
2459
2460 int config_parse_unit_slice(
2461                 const char *unit,
2462                 const char *filename,
2463                 unsigned line,
2464                 const char *section,
2465                 unsigned section_line,
2466                 const char *lvalue,
2467                 int ltype,
2468                 const char *rvalue,
2469                 void *data,
2470                 void *userdata) {
2471
2472         _cleanup_free_ char *k = NULL;
2473         Unit *u = userdata, *slice;
2474         int r;
2475
2476         assert(filename);
2477         assert(lvalue);
2478         assert(rvalue);
2479         assert(u);
2480
2481         r = unit_name_printf(u, rvalue, &k);
2482         if (r < 0)
2483                 log_syntax(unit, LOG_ERR, filename, line, -r,
2484                            "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
2485         if (!k) {
2486                 k = strdup(rvalue);
2487                 if (!k)
2488                         return log_oom();
2489         }
2490
2491         r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
2492         if (r < 0) {
2493                 log_syntax(unit, LOG_ERR, filename, line, -r,
2494                            "Failed to load slice unit %s. Ignoring.", k);
2495                 return 0;
2496         }
2497
2498         if (slice->type != UNIT_SLICE) {
2499                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2500                            "Slice unit %s is not a slice. Ignoring.", k);
2501                 return 0;
2502         }
2503
2504         unit_ref_set(&u->slice, slice);
2505         return 0;
2506 }
2507
2508 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
2509
2510 int config_parse_cpu_shares(
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         unsigned long *shares = data, lu;
2523         int r;
2524
2525         assert(filename);
2526         assert(lvalue);
2527         assert(rvalue);
2528
2529         if (isempty(rvalue)) {
2530                 *shares = (unsigned long) -1;
2531                 return 0;
2532         }
2533
2534         r = safe_atolu(rvalue, &lu);
2535         if (r < 0 || lu <= 0) {
2536                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2537                            "CPU shares '%s' invalid. Ignoring.", rvalue);
2538                 return 0;
2539         }
2540
2541         *shares = lu;
2542         return 0;
2543 }
2544
2545 int config_parse_cpu_quota(
2546                 const char *unit,
2547                 const char *filename,
2548                 unsigned line,
2549                 const char *section,
2550                 unsigned section_line,
2551                 const char *lvalue,
2552                 int ltype,
2553                 const char *rvalue,
2554                 void *data,
2555                 void *userdata) {
2556
2557         CGroupContext *c = data;
2558         double percent;
2559
2560         assert(filename);
2561         assert(lvalue);
2562         assert(rvalue);
2563
2564         if (isempty(rvalue)) {
2565                 c->cpu_quota_per_sec_usec = USEC_INFINITY;
2566                 return 0;
2567         }
2568
2569         if (!endswith(rvalue, "%")) {
2570
2571                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2572                            "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue);
2573                 return 0;
2574         }
2575
2576         if (sscanf(rvalue, "%lf%%", &percent) != 1 || percent <= 0) {
2577                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2578                            "CPU quota '%s' invalid. Ignoring.", rvalue);
2579                 return 0;
2580         }
2581
2582         c->cpu_quota_per_sec_usec = (usec_t) (percent * USEC_PER_SEC / 100);
2583
2584         return 0;
2585 }
2586
2587 int config_parse_memory_limit(
2588                 const char *unit,
2589                 const char *filename,
2590                 unsigned line,
2591                 const char *section,
2592                 unsigned section_line,
2593                 const char *lvalue,
2594                 int ltype,
2595                 const char *rvalue,
2596                 void *data,
2597                 void *userdata) {
2598
2599         CGroupContext *c = data;
2600         off_t bytes;
2601         int r;
2602
2603         if (isempty(rvalue)) {
2604                 c->memory_limit = (uint64_t) -1;
2605                 return 0;
2606         }
2607
2608         assert_cc(sizeof(uint64_t) == sizeof(off_t));
2609
2610         r = parse_size(rvalue, 1024, &bytes);
2611         if (r < 0) {
2612                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2613                            "Memory limit '%s' invalid. Ignoring.", rvalue);
2614                 return 0;
2615         }
2616
2617         c->memory_limit = (uint64_t) bytes;
2618         return 0;
2619 }
2620
2621 int config_parse_device_allow(
2622                 const char *unit,
2623                 const char *filename,
2624                 unsigned line,
2625                 const char *section,
2626                 unsigned section_line,
2627                 const char *lvalue,
2628                 int ltype,
2629                 const char *rvalue,
2630                 void *data,
2631                 void *userdata) {
2632
2633         _cleanup_free_ char *path = NULL;
2634         CGroupContext *c = data;
2635         CGroupDeviceAllow *a;
2636         const char *m;
2637         size_t n;
2638
2639         if (isempty(rvalue)) {
2640                 while (c->device_allow)
2641                         cgroup_context_free_device_allow(c, c->device_allow);
2642
2643                 return 0;
2644         }
2645
2646         n = strcspn(rvalue, WHITESPACE);
2647         path = strndup(rvalue, n);
2648         if (!path)
2649                 return log_oom();
2650
2651         if (!startswith(path, "/dev/") &&
2652             !startswith(path, "block-") &&
2653             !startswith(path, "char-")) {
2654                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2655                            "Invalid device node path '%s'. Ignoring.", path);
2656                 return 0;
2657         }
2658
2659         m = rvalue + n + strspn(rvalue + n, WHITESPACE);
2660         if (isempty(m))
2661                 m = "rwm";
2662
2663         if (!in_charset(m, "rwm")) {
2664                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2665                            "Invalid device rights '%s'. Ignoring.", m);
2666                 return 0;
2667         }
2668
2669         a = new0(CGroupDeviceAllow, 1);
2670         if (!a)
2671                 return log_oom();
2672
2673         a->path = path;
2674         path = NULL;
2675         a->r = !!strchr(m, 'r');
2676         a->w = !!strchr(m, 'w');
2677         a->m = !!strchr(m, 'm');
2678
2679         LIST_PREPEND(device_allow, c->device_allow, a);
2680         return 0;
2681 }
2682
2683 int config_parse_blockio_weight(
2684                 const char *unit,
2685                 const char *filename,
2686                 unsigned line,
2687                 const char *section,
2688                 unsigned section_line,
2689                 const char *lvalue,
2690                 int ltype,
2691                 const char *rvalue,
2692                 void *data,
2693                 void *userdata) {
2694
2695         unsigned long *weight = data, lu;
2696         int r;
2697
2698         assert(filename);
2699         assert(lvalue);
2700         assert(rvalue);
2701
2702         if (isempty(rvalue)) {
2703                 *weight = (unsigned long) -1;
2704                 return 0;
2705         }
2706
2707         r = safe_atolu(rvalue, &lu);
2708         if (r < 0 || lu < 10 || lu > 1000) {
2709                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2710                            "Block IO weight '%s' invalid. Ignoring.", rvalue);
2711                 return 0;
2712         }
2713
2714         *weight = lu;
2715         return 0;
2716 }
2717
2718 int config_parse_blockio_device_weight(
2719                 const char *unit,
2720                 const char *filename,
2721                 unsigned line,
2722                 const char *section,
2723                 unsigned section_line,
2724                 const char *lvalue,
2725                 int ltype,
2726                 const char *rvalue,
2727                 void *data,
2728                 void *userdata) {
2729
2730         _cleanup_free_ char *path = NULL;
2731         CGroupBlockIODeviceWeight *w;
2732         CGroupContext *c = data;
2733         unsigned long lu;
2734         const char *weight;
2735         size_t n;
2736         int r;
2737
2738         assert(filename);
2739         assert(lvalue);
2740         assert(rvalue);
2741
2742         if (isempty(rvalue)) {
2743                 while (c->blockio_device_weights)
2744                         cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
2745
2746                 return 0;
2747         }
2748
2749         n = strcspn(rvalue, WHITESPACE);
2750         weight = rvalue + n;
2751         if (!*weight) {
2752                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2753                            "Expected block device and device weight. Ignoring.");
2754                 return 0;
2755         }
2756
2757         path = strndup(rvalue, n);
2758         if (!path)
2759                 return log_oom();
2760
2761         if (!path_startswith(path, "/dev")) {
2762                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2763                            "Invalid device node path '%s'. Ignoring.", path);
2764                 return 0;
2765         }
2766
2767         weight += strspn(weight, WHITESPACE);
2768         r = safe_atolu(weight, &lu);
2769         if (r < 0 || lu < 10 || lu > 1000) {
2770                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2771                            "Block IO weight '%s' invalid. Ignoring.", rvalue);
2772                 return 0;
2773         }
2774
2775         w = new0(CGroupBlockIODeviceWeight, 1);
2776         if (!w)
2777                 return log_oom();
2778
2779         w->path = path;
2780         path = NULL;
2781
2782         w->weight = lu;
2783
2784         LIST_PREPEND(device_weights, c->blockio_device_weights, w);
2785         return 0;
2786 }
2787
2788 int config_parse_blockio_bandwidth(
2789                 const char *unit,
2790                 const char *filename,
2791                 unsigned line,
2792                 const char *section,
2793                 unsigned section_line,
2794                 const char *lvalue,
2795                 int ltype,
2796                 const char *rvalue,
2797                 void *data,
2798                 void *userdata) {
2799
2800         _cleanup_free_ char *path = NULL;
2801         CGroupBlockIODeviceBandwidth *b;
2802         CGroupContext *c = data;
2803         const char *bandwidth;
2804         off_t bytes;
2805         bool read;
2806         size_t n;
2807         int r;
2808
2809         assert(filename);
2810         assert(lvalue);
2811         assert(rvalue);
2812
2813         read = streq("BlockIOReadBandwidth", lvalue);
2814
2815         if (isempty(rvalue)) {
2816                 CGroupBlockIODeviceBandwidth *next;
2817
2818                 LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
2819                         if (b->read == read)
2820                                 cgroup_context_free_blockio_device_bandwidth(c, b);
2821
2822                 return 0;
2823         }
2824
2825         n = strcspn(rvalue, WHITESPACE);
2826         bandwidth = rvalue + n;
2827         bandwidth += strspn(bandwidth, WHITESPACE);
2828
2829         if (!*bandwidth) {
2830                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2831                            "Expected space separated pair of device node and bandwidth. Ignoring.");
2832                 return 0;
2833         }
2834
2835         path = strndup(rvalue, n);
2836         if (!path)
2837                 return log_oom();
2838
2839         if (!path_startswith(path, "/dev")) {
2840                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2841                            "Invalid device node path '%s'. Ignoring.", path);
2842                 return 0;
2843         }
2844
2845         r = parse_size(bandwidth, 1000, &bytes);
2846         if (r < 0 || bytes <= 0) {
2847                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2848                            "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
2849                 return 0;
2850         }
2851
2852         b = new0(CGroupBlockIODeviceBandwidth, 1);
2853         if (!b)
2854                 return log_oom();
2855
2856         b->path = path;
2857         path = NULL;
2858         b->bandwidth = (uint64_t) bytes;
2859         b->read = read;
2860
2861         LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
2862
2863         return 0;
2864 }
2865
2866 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
2867
2868 int config_parse_job_mode_isolate(
2869                 const char *unit,
2870                 const char *filename,
2871                 unsigned line,
2872                 const char *section,
2873                 unsigned section_line,
2874                 const char *lvalue,
2875                 int ltype,
2876                 const char *rvalue,
2877                 void *data,
2878                 void *userdata) {
2879
2880         JobMode *m = data;
2881         int r;
2882
2883         assert(filename);
2884         assert(lvalue);
2885         assert(rvalue);
2886
2887         r = parse_boolean(rvalue);
2888         if (r < 0) {
2889                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2890                            "Failed to parse boolean, ignoring: %s", rvalue);
2891                 return 0;
2892         }
2893
2894         *m = r ? JOB_ISOLATE : JOB_REPLACE;
2895         return 0;
2896 }
2897
2898 int config_parse_personality(
2899                 const char *unit,
2900                 const char *filename,
2901                 unsigned line,
2902                 const char *section,
2903                 unsigned section_line,
2904                 const char *lvalue,
2905                 int ltype,
2906                 const char *rvalue,
2907                 void *data,
2908                 void *userdata) {
2909
2910         unsigned long *personality = data, p;
2911
2912         assert(filename);
2913         assert(lvalue);
2914         assert(rvalue);
2915         assert(personality);
2916
2917         p = personality_from_string(rvalue);
2918         if (p == 0xffffffffUL) {
2919                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2920                            "Failed to parse personality, ignoring: %s", rvalue);
2921                 return 0;
2922         }
2923
2924         *personality = p;
2925         return 0;
2926 }
2927
2928 int config_parse_runtime_directory(
2929                 const char *unit,
2930                 const char *filename,
2931                 unsigned line,
2932                 const char *section,
2933                 unsigned section_line,
2934                 const char *lvalue,
2935                 int ltype,
2936                 const char *rvalue,
2937                 void *data,
2938                 void *userdata) {
2939
2940         char***rt = data;
2941         const char *word, *state;
2942         size_t l;
2943         int r;
2944
2945         assert(filename);
2946         assert(lvalue);
2947         assert(rvalue);
2948         assert(data);
2949
2950         if (isempty(rvalue)) {
2951                 /* Empty assignment resets the list */
2952                 strv_free(*rt);
2953                 *rt = NULL;
2954                 return 0;
2955         }
2956
2957         FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2958                 _cleanup_free_ char *n;
2959
2960                 n = strndup(word, l);
2961                 if (!n)
2962                         return log_oom();
2963
2964                 if (!filename_is_safe(n)) {
2965                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2966                                    "Runtime directory is not valid, ignoring assignment: %s", rvalue);
2967                         continue;
2968                 }
2969
2970                 r = strv_push(rt, n);
2971                 if (r < 0)
2972                         return log_oom();
2973
2974                 n = NULL;
2975         }
2976         if (!isempty(state))
2977                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2978                            "Trailing garbage, ignoring.");
2979
2980         return 0;
2981 }
2982
2983 int config_parse_set_status(
2984                 const char *unit,
2985                 const char *filename,
2986                 unsigned line,
2987                 const char *section,
2988                 unsigned section_line,
2989                 const char *lvalue,
2990                 int ltype,
2991                 const char *rvalue,
2992                 void *data,
2993                 void *userdata) {
2994
2995         size_t l;
2996         const char *word, *state;
2997         int r;
2998         ExitStatusSet *status_set = data;
2999
3000         assert(filename);
3001         assert(lvalue);
3002         assert(rvalue);
3003         assert(data);
3004
3005         /* Empty assignment resets the list */
3006         if (isempty(rvalue)) {
3007                 exit_status_set_free(status_set);
3008                 return 0;
3009         }
3010
3011         FOREACH_WORD(word, l, rvalue, state) {
3012                 _cleanup_free_ char *temp;
3013                 int val;
3014
3015                 temp = strndup(word, l);
3016                 if (!temp)
3017                         return log_oom();
3018
3019                 r = safe_atoi(temp, &val);
3020                 if (r < 0) {
3021                         val = signal_from_string_try_harder(temp);
3022
3023                         if (val <= 0) {
3024                                 log_syntax(unit, LOG_ERR, filename, line, -val,
3025                                            "Failed to parse value, ignoring: %s", word);
3026                                 return 0;
3027                         }
3028                 } else {
3029                         if (val < 0 || val > 255) {
3030                                 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
3031                                            "Value %d is outside range 0-255, ignoring", val);
3032                                 continue;
3033                         }
3034                 }
3035
3036                 r = set_ensure_allocated(&status_set->status, NULL, NULL);
3037                 if (r < 0)
3038                         return log_oom();
3039
3040                 r = set_put(status_set->status, INT_TO_PTR(val));
3041                 if (r < 0) {
3042                         log_syntax(unit, LOG_ERR, filename, line, -r,
3043                                    "Unable to store: %s", word);
3044                         return r;
3045                 }
3046         }
3047         if (!isempty(state))
3048                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3049                            "Trailing garbage, ignoring.");
3050
3051         return 0;
3052 }
3053
3054 int config_parse_namespace_path_strv(
3055                 const char *unit,
3056                 const char *filename,
3057                 unsigned line,
3058                 const char *section,
3059                 unsigned section_line,
3060                 const char *lvalue,
3061                 int ltype,
3062                 const char *rvalue,
3063                 void *data,
3064                 void *userdata) {
3065
3066         char*** sv = data;
3067         const char *word, *state;
3068         size_t l;
3069         int r;
3070
3071         assert(filename);
3072         assert(lvalue);
3073         assert(rvalue);
3074         assert(data);
3075
3076         if (isempty(rvalue)) {
3077                 /* Empty assignment resets the list */
3078                 strv_free(*sv);
3079                 *sv = NULL;
3080                 return 0;
3081         }
3082
3083         FOREACH_WORD_QUOTED(word, l, rvalue, state) {
3084                 _cleanup_free_ char *n;
3085                 int offset;
3086
3087                 n = strndup(word, l);
3088                 if (!n)
3089                         return log_oom();
3090
3091                 if (!utf8_is_valid(n)) {
3092                         log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
3093                         continue;
3094                 }
3095
3096                 offset = n[0] == '-';
3097                 if (!path_is_absolute(n + offset)) {
3098                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3099                                    "Not an absolute path, ignoring: %s", rvalue);
3100                         continue;
3101                 }
3102
3103                 path_kill_slashes(n);
3104
3105                 r = strv_push(sv, n);
3106                 if (r < 0)
3107                         return log_oom();
3108
3109                 n = NULL;
3110         }
3111         if (!isempty(state))
3112                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3113                            "Trailing garbage, ignoring.");
3114
3115         return 0;
3116 }
3117
3118 int config_parse_no_new_privileges(
3119                 const char* unit,
3120                 const char *filename,
3121                 unsigned line,
3122                 const char *section,
3123                 unsigned section_line,
3124                 const char *lvalue,
3125                 int ltype,
3126                 const char *rvalue,
3127                 void *data,
3128                 void *userdata) {
3129
3130         ExecContext *c = data;
3131         int k;
3132
3133         assert(filename);
3134         assert(lvalue);
3135         assert(rvalue);
3136         assert(data);
3137
3138         k = parse_boolean(rvalue);
3139         if (k < 0) {
3140                 log_syntax(unit, LOG_ERR, filename, line, -k,
3141                            "Failed to parse boolean value, ignoring: %s", rvalue);
3142                 return 0;
3143         }
3144
3145         c->no_new_privileges = !!k;
3146         c->no_new_privileges_set = true;
3147
3148         return 0;
3149 }
3150
3151 int config_parse_protect_home(
3152                 const char* unit,
3153                 const char *filename,
3154                 unsigned line,
3155                 const char *section,
3156                 unsigned section_line,
3157                 const char *lvalue,
3158                 int ltype,
3159                 const char *rvalue,
3160                 void *data,
3161                 void *userdata) {
3162
3163         ExecContext *c = data;
3164         int k;
3165
3166         assert(filename);
3167         assert(lvalue);
3168         assert(rvalue);
3169         assert(data);
3170
3171         /* Our enum shall be a superset of booleans, hence first try
3172          * to parse as as boolean, and then as enum */
3173
3174         k = parse_boolean(rvalue);
3175         if (k > 0)
3176                 c->protect_home = PROTECT_HOME_YES;
3177         else if (k == 0)
3178                 c->protect_home = PROTECT_HOME_NO;
3179         else {
3180                 ProtectHome h;
3181
3182                 h = protect_home_from_string(rvalue);
3183                 if (h < 0){
3184                         log_syntax(unit, LOG_ERR, filename, line, -h,
3185                                    "Failed to parse protect home value, ignoring: %s", rvalue);
3186                         return 0;
3187                 }
3188
3189                 c->protect_home = h;
3190         }
3191
3192         return 0;
3193 }
3194
3195 int config_parse_protect_system(
3196                 const char* unit,
3197                 const char *filename,
3198                 unsigned line,
3199                 const char *section,
3200                 unsigned section_line,
3201                 const char *lvalue,
3202                 int ltype,
3203                 const char *rvalue,
3204                 void *data,
3205                 void *userdata) {
3206
3207         ExecContext *c = data;
3208         int k;
3209
3210         assert(filename);
3211         assert(lvalue);
3212         assert(rvalue);
3213         assert(data);
3214
3215         /* Our enum shall be a superset of booleans, hence first try
3216          * to parse as as boolean, and then as enum */
3217
3218         k = parse_boolean(rvalue);
3219         if (k > 0)
3220                 c->protect_system = PROTECT_SYSTEM_YES;
3221         else if (k == 0)
3222                 c->protect_system = PROTECT_SYSTEM_NO;
3223         else {
3224                 ProtectSystem s;
3225
3226                 s = protect_system_from_string(rvalue);
3227                 if (s < 0){
3228                         log_syntax(unit, LOG_ERR, filename, line, -s,
3229                                    "Failed to parse protect system value, ignoring: %s", rvalue);
3230                         return 0;
3231                 }
3232
3233                 c->protect_system = s;
3234         }
3235
3236         return 0;
3237 }
3238
3239 #define FOLLOW_MAX 8
3240
3241 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
3242         unsigned c = 0;
3243         int fd, r;
3244         FILE *f;
3245         char *id = NULL;
3246
3247         assert(filename);
3248         assert(*filename);
3249         assert(_f);
3250         assert(names);
3251
3252         /* This will update the filename pointer if the loaded file is
3253          * reached by a symlink. The old string will be freed. */
3254
3255         for (;;) {
3256                 char *target, *name;
3257
3258                 if (c++ >= FOLLOW_MAX)
3259                         return -ELOOP;
3260
3261                 path_kill_slashes(*filename);
3262
3263                 /* Add the file name we are currently looking at to
3264                  * the names of this unit, but only if it is a valid
3265                  * unit name. */
3266                 name = basename(*filename);
3267
3268                 if (unit_name_is_valid(name, TEMPLATE_VALID)) {
3269
3270                         id = set_get(names, name);
3271                         if (!id) {
3272                                 id = strdup(name);
3273                                 if (!id)
3274                                         return -ENOMEM;
3275
3276                                 r = set_consume(names, id);
3277                                 if (r < 0)
3278                                         return r;
3279                         }
3280                 }
3281
3282                 /* Try to open the file name, but don't if its a symlink */
3283                 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
3284                 if (fd >= 0)
3285                         break;
3286
3287                 if (errno != ELOOP)
3288                         return -errno;
3289
3290                 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
3291                 r = readlink_and_make_absolute(*filename, &target);
3292                 if (r < 0)
3293                         return r;
3294
3295                 free(*filename);
3296                 *filename = target;
3297         }
3298
3299         f = fdopen(fd, "re");
3300         if (!f) {
3301                 r = -errno;
3302                 safe_close(fd);
3303                 return r;
3304         }
3305
3306         *_f = f;
3307         *_final = id;
3308         return 0;
3309 }
3310
3311 static int merge_by_names(Unit **u, Set *names, const char *id) {
3312         char *k;
3313         int r;
3314
3315         assert(u);
3316         assert(*u);
3317         assert(names);
3318
3319         /* Let's try to add in all symlink names we found */
3320         while ((k = set_steal_first(names))) {
3321
3322                 /* First try to merge in the other name into our
3323                  * unit */
3324                 r = unit_merge_by_name(*u, k);
3325                 if (r < 0) {
3326                         Unit *other;
3327
3328                         /* Hmm, we couldn't merge the other unit into
3329                          * ours? Then let's try it the other way
3330                          * round */
3331
3332                         other = manager_get_unit((*u)->manager, k);
3333                         free(k);
3334
3335                         if (other) {
3336                                 r = unit_merge(other, *u);
3337                                 if (r >= 0) {
3338                                         *u = other;
3339                                         return merge_by_names(u, names, NULL);
3340                                 }
3341                         }
3342
3343                         return r;
3344                 }
3345
3346                 if (id == k)
3347                         unit_choose_id(*u, id);
3348
3349                 free(k);
3350         }
3351
3352         return 0;
3353 }
3354
3355 static int load_from_path(Unit *u, const char *path) {
3356         int r;
3357         _cleanup_set_free_free_ Set *symlink_names = NULL;
3358         _cleanup_fclose_ FILE *f = NULL;
3359         _cleanup_free_ char *filename = NULL;
3360         char *id = NULL;
3361         Unit *merged;
3362         struct stat st;
3363
3364         assert(u);
3365         assert(path);
3366
3367         symlink_names = set_new(string_hash_func, string_compare_func);
3368         if (!symlink_names)
3369                 return -ENOMEM;
3370
3371         if (path_is_absolute(path)) {
3372
3373                 filename = strdup(path);
3374                 if (!filename)
3375                         return -ENOMEM;
3376
3377                 r = open_follow(&filename, &f, symlink_names, &id);
3378                 if (r < 0) {
3379                         free(filename);
3380                         filename = NULL;
3381
3382                         if (r != -ENOENT)
3383                                 return r;
3384                 }
3385
3386         } else  {
3387                 char **p;
3388
3389                 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
3390
3391                         /* Instead of opening the path right away, we manually
3392                          * follow all symlinks and add their name to our unit
3393                          * name set while doing so */
3394                         filename = path_make_absolute(path, *p);
3395                         if (!filename)
3396                                 return -ENOMEM;
3397
3398                         if (u->manager->unit_path_cache &&
3399                             !set_get(u->manager->unit_path_cache, filename))
3400                                 r = -ENOENT;
3401                         else
3402                                 r = open_follow(&filename, &f, symlink_names, &id);
3403
3404                         if (r < 0) {
3405                                 free(filename);
3406                                 filename = NULL;
3407
3408                                 if (r != -ENOENT)
3409                                         return r;
3410
3411                                 /* Empty the symlink names for the next run */
3412                                 set_clear_free(symlink_names);
3413                                 continue;
3414                         }
3415
3416                         break;
3417                 }
3418         }
3419
3420         if (!filename)
3421                 /* Hmm, no suitable file found? */
3422                 return 0;
3423
3424         merged = u;
3425         r = merge_by_names(&merged, symlink_names, id);
3426         if (r < 0)
3427                 return r;
3428
3429         if (merged != u) {
3430                 u->load_state = UNIT_MERGED;
3431                 return 0;
3432         }
3433
3434         if (fstat(fileno(f), &st) < 0)
3435                 return -errno;
3436
3437         if (null_or_empty(&st))
3438                 u->load_state = UNIT_MASKED;
3439         else {
3440                 u->load_state = UNIT_LOADED;
3441
3442                 /* Now, parse the file contents */
3443                 r = config_parse(u->id, filename, f,
3444                                  UNIT_VTABLE(u)->sections,
3445                                  config_item_perf_lookup, load_fragment_gperf_lookup,
3446                                  false, true, false, u);
3447                 if (r < 0)
3448                         return r;
3449         }
3450
3451         free(u->fragment_path);
3452         u->fragment_path = filename;
3453         filename = NULL;
3454
3455         u->fragment_mtime = timespec_load(&st.st_mtim);
3456
3457         if (u->source_path) {
3458                 if (stat(u->source_path, &st) >= 0)
3459                         u->source_mtime = timespec_load(&st.st_mtim);
3460                 else
3461                         u->source_mtime = 0;
3462         }
3463
3464         return 0;
3465 }
3466
3467 int unit_load_fragment(Unit *u) {
3468         int r;
3469         Iterator i;
3470         const char *t;
3471
3472         assert(u);
3473         assert(u->load_state == UNIT_STUB);
3474         assert(u->id);
3475
3476         /* First, try to find the unit under its id. We always look
3477          * for unit files in the default directories, to make it easy
3478          * to override things by placing things in /etc/systemd/system */
3479         r = load_from_path(u, u->id);
3480         if (r < 0)
3481                 return r;
3482
3483         /* Try to find an alias we can load this with */
3484         if (u->load_state == UNIT_STUB)
3485                 SET_FOREACH(t, u->names, i) {
3486
3487                         if (t == u->id)
3488                                 continue;
3489
3490                         r = load_from_path(u, t);
3491                         if (r < 0)
3492                                 return r;
3493
3494                         if (u->load_state != UNIT_STUB)
3495                                 break;
3496                 }
3497
3498         /* And now, try looking for it under the suggested (originally linked) path */
3499         if (u->load_state == UNIT_STUB && u->fragment_path) {
3500
3501                 r = load_from_path(u, u->fragment_path);
3502                 if (r < 0)
3503                         return r;
3504
3505                 if (u->load_state == UNIT_STUB) {
3506                         /* Hmm, this didn't work? Then let's get rid
3507                          * of the fragment path stored for us, so that
3508                          * we don't point to an invalid location. */
3509                         free(u->fragment_path);
3510                         u->fragment_path = NULL;
3511                 }
3512         }
3513
3514         /* Look for a template */
3515         if (u->load_state == UNIT_STUB && u->instance) {
3516                 _cleanup_free_ char *k;
3517
3518                 k = unit_name_template(u->id);
3519                 if (!k)
3520                         return -ENOMEM;
3521
3522                 r = load_from_path(u, k);
3523                 if (r < 0)
3524                         return r;
3525
3526                 if (u->load_state == UNIT_STUB)
3527                         SET_FOREACH(t, u->names, i) {
3528                                 _cleanup_free_ char *z = NULL;
3529
3530                                 if (t == u->id)
3531                                         continue;
3532
3533                                 z = unit_name_template(t);
3534                                 if (!z)
3535                                         return -ENOMEM;
3536
3537                                 r = load_from_path(u, z);
3538                                 if (r < 0)
3539                                         return r;
3540
3541                                 if (u->load_state != UNIT_STUB)
3542                                         break;
3543                         }
3544         }
3545
3546         return 0;
3547 }
3548
3549 void unit_dump_config_items(FILE *f) {
3550         static const struct {
3551                 const ConfigParserCallback callback;
3552                 const char *rvalue;
3553         } table[] = {
3554 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
3555                 { config_parse_warn_compat,           "NOTSUPPORTED" },
3556 #endif
3557                 { config_parse_int,                   "INTEGER" },
3558                 { config_parse_unsigned,              "UNSIGNED" },
3559                 { config_parse_iec_size,              "SIZE" },
3560                 { config_parse_iec_off,               "SIZE" },
3561                 { config_parse_si_size,               "SIZE" },
3562                 { config_parse_bool,                  "BOOLEAN" },
3563                 { config_parse_string,                "STRING" },
3564                 { config_parse_path,                  "PATH" },
3565                 { config_parse_unit_path_printf,      "PATH" },
3566                 { config_parse_strv,                  "STRING [...]" },
3567                 { config_parse_exec_nice,             "NICE" },
3568                 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
3569                 { config_parse_exec_io_class,         "IOCLASS" },
3570                 { config_parse_exec_io_priority,      "IOPRIORITY" },
3571                 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
3572                 { config_parse_exec_cpu_sched_prio,   "CPUSCHEDPRIO" },
3573                 { config_parse_exec_cpu_affinity,     "CPUAFFINITY" },
3574                 { config_parse_mode,                  "MODE" },
3575                 { config_parse_unit_env_file,         "FILE" },
3576                 { config_parse_output,                "OUTPUT" },
3577                 { config_parse_input,                 "INPUT" },
3578                 { config_parse_log_facility,          "FACILITY" },
3579                 { config_parse_log_level,             "LEVEL" },
3580                 { config_parse_exec_capabilities,     "CAPABILITIES" },
3581                 { config_parse_exec_secure_bits,      "SECUREBITS" },
3582                 { config_parse_bounding_set,          "BOUNDINGSET" },
3583                 { config_parse_limit,                 "LIMIT" },
3584                 { config_parse_unit_deps,             "UNIT [...]" },
3585                 { config_parse_exec,                  "PATH [ARGUMENT [...]]" },
3586                 { config_parse_service_type,          "SERVICETYPE" },
3587                 { config_parse_service_restart,       "SERVICERESTART" },
3588 #ifdef HAVE_SYSV_COMPAT
3589                 { config_parse_sysv_priority,         "SYSVPRIORITY" },
3590 #endif
3591                 { config_parse_kill_mode,             "KILLMODE" },
3592                 { config_parse_kill_signal,           "SIGNAL" },
3593                 { config_parse_socket_listen,         "SOCKET [...]" },
3594                 { config_parse_socket_bind,           "SOCKETBIND" },
3595                 { config_parse_socket_bindtodevice,   "NETWORKINTERFACE" },
3596                 { config_parse_sec,                   "SECONDS" },
3597                 { config_parse_nsec,                  "NANOSECONDS" },
3598                 { config_parse_namespace_path_strv,   "PATH [...]" },
3599                 { config_parse_unit_requires_mounts_for, "PATH [...]" },
3600                 { config_parse_exec_mount_flags,      "MOUNTFLAG [...]" },
3601                 { config_parse_unit_string_printf,    "STRING" },
3602                 { config_parse_trigger_unit,          "UNIT" },
3603                 { config_parse_timer,                 "TIMER" },
3604                 { config_parse_path_spec,             "PATH" },
3605                 { config_parse_notify_access,         "ACCESS" },
3606                 { config_parse_ip_tos,                "TOS" },
3607                 { config_parse_unit_condition_path,   "CONDITION" },
3608                 { config_parse_unit_condition_string, "CONDITION" },
3609                 { config_parse_unit_condition_null,   "CONDITION" },
3610                 { config_parse_unit_slice,            "SLICE" },
3611                 { config_parse_documentation,         "URL" },
3612                 { config_parse_service_timeout,       "SECONDS" },
3613                 { config_parse_failure_action,        "ACTION" },
3614                 { config_parse_set_status,            "STATUS" },
3615                 { config_parse_service_sockets,       "SOCKETS" },
3616                 { config_parse_environ,               "ENVIRON" },
3617 #ifdef HAVE_SECCOMP
3618                 { config_parse_syscall_filter,        "SYSCALLS" },
3619                 { config_parse_syscall_archs,         "ARCHS" },
3620                 { config_parse_syscall_errno,         "ERRNO" },
3621                 { config_parse_address_families,      "FAMILIES" },
3622 #endif
3623                 { config_parse_cpu_shares,            "SHARES" },
3624                 { config_parse_memory_limit,          "LIMIT" },
3625                 { config_parse_device_allow,          "DEVICE" },
3626                 { config_parse_device_policy,         "POLICY" },
3627                 { config_parse_blockio_bandwidth,     "BANDWIDTH" },
3628                 { config_parse_blockio_weight,        "WEIGHT" },
3629                 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
3630                 { config_parse_long,                  "LONG" },
3631                 { config_parse_socket_service,        "SERVICE" },
3632 #ifdef HAVE_SELINUX
3633                 { config_parse_exec_selinux_context,  "LABEL" },
3634 #endif
3635                 { config_parse_job_mode,              "MODE" },
3636                 { config_parse_job_mode_isolate,      "BOOLEAN" },
3637                 { config_parse_personality,           "PERSONALITY" },
3638         };
3639
3640         const char *prev = NULL;
3641         const char *i;
3642
3643         assert(f);
3644
3645         NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
3646                 const char *rvalue = "OTHER", *lvalue;
3647                 unsigned j;
3648                 size_t prefix_len;
3649                 const char *dot;
3650                 const ConfigPerfItem *p;
3651
3652                 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
3653
3654                 dot = strchr(i, '.');
3655                 lvalue = dot ? dot + 1 : i;
3656                 prefix_len = dot-i;
3657
3658                 if (dot)
3659                         if (!prev || !strneq(prev, i, prefix_len+1)) {
3660                                 if (prev)
3661                                         fputc('\n', f);
3662
3663                                 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
3664                         }
3665
3666                 for (j = 0; j < ELEMENTSOF(table); j++)
3667                         if (p->parse == table[j].callback) {
3668                                 rvalue = table[j].rvalue;
3669                                 break;
3670                         }
3671
3672                 fprintf(f, "%s=%s\n", lvalue, rvalue);
3673                 prev = i;
3674         }
3675 }