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