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