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