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