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