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