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