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