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