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