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