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