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