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