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