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