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