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