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