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