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