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