]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/load-fragment.c
Merge pull request #8865 from yuwata/fix-signal
[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 /* An empty string resets controllers and set Delegate=yes. */
3422 c->delegate = true;
3423 c->delegate_controllers = 0;
3424 return 0;
3425 }
3426
3427 r = parse_boolean(rvalue);
3428 if (r < 0) {
3429 const char *p = rvalue;
3430 CGroupMask mask = 0;
3431
3432 for (;;) {
3433 _cleanup_free_ char *word = NULL;
3434 CGroupController cc;
3435
3436 r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
3437 if (r == 0)
3438 break;
3439 if (r == -ENOMEM)
3440 return log_oom();
3441 if (r < 0) {
3442 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
3443 return 0;
3444 }
3445
3446 cc = cgroup_controller_from_string(word);
3447 if (cc < 0) {
3448 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid controller name '%s', ignoring", rvalue);
3449 continue;
3450 }
3451
3452 mask |= CGROUP_CONTROLLER_TO_MASK(cc);
3453 }
3454
3455 c->delegate = true;
3456 c->delegate_controllers |= mask;
3457
3458 } else if (r > 0) {
3459 c->delegate = true;
3460 c->delegate_controllers = _CGROUP_MASK_ALL;
3461 } else {
3462 c->delegate = false;
3463 c->delegate_controllers = 0;
3464 }
3465
3466 return 0;
3467 }
3468
3469 int config_parse_device_allow(
3470 const char *unit,
3471 const char *filename,
3472 unsigned line,
3473 const char *section,
3474 unsigned section_line,
3475 const char *lvalue,
3476 int ltype,
3477 const char *rvalue,
3478 void *data,
3479 void *userdata) {
3480
3481 _cleanup_free_ char *path = NULL, *t = NULL;
3482 CGroupContext *c = data;
3483 CGroupDeviceAllow *a;
3484 const char *m = NULL;
3485 size_t n;
3486 int r;
3487
3488 if (isempty(rvalue)) {
3489 while (c->device_allow)
3490 cgroup_context_free_device_allow(c, c->device_allow);
3491
3492 return 0;
3493 }
3494
3495 r = unit_full_printf(userdata, rvalue, &t);
3496 if (r < 0) {
3497 log_syntax(unit, LOG_WARNING, filename, line, r,
3498 "Failed to resolve specifiers in %s, ignoring: %m",
3499 rvalue);
3500 return 0;
3501 }
3502
3503 n = strcspn(t, WHITESPACE);
3504
3505 path = strndup(t, n);
3506 if (!path)
3507 return log_oom();
3508
3509 if (!is_deviceallow_pattern(path) &&
3510 !path_startswith(path, "/run/systemd/inaccessible/")) {
3511 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
3512 return 0;
3513 }
3514
3515 m = t + n + strspn(t + n, WHITESPACE);
3516 if (isempty(m))
3517 m = "rwm";
3518
3519 if (!in_charset(m, "rwm")) {
3520 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device rights '%s'. Ignoring.", m);
3521 return 0;
3522 }
3523
3524 a = new0(CGroupDeviceAllow, 1);
3525 if (!a)
3526 return log_oom();
3527
3528 a->path = TAKE_PTR(path);
3529 a->r = !!strchr(m, 'r');
3530 a->w = !!strchr(m, 'w');
3531 a->m = !!strchr(m, 'm');
3532
3533 LIST_PREPEND(device_allow, c->device_allow, a);
3534 return 0;
3535 }
3536
3537 int config_parse_io_weight(
3538 const char *unit,
3539 const char *filename,
3540 unsigned line,
3541 const char *section,
3542 unsigned section_line,
3543 const char *lvalue,
3544 int ltype,
3545 const char *rvalue,
3546 void *data,
3547 void *userdata) {
3548
3549 uint64_t *weight = data;
3550 int r;
3551
3552 assert(filename);
3553 assert(lvalue);
3554 assert(rvalue);
3555
3556 r = cg_weight_parse(rvalue, weight);
3557 if (r < 0) {
3558 log_syntax(unit, LOG_ERR, filename, line, r, "IO weight '%s' invalid. Ignoring.", rvalue);
3559 return 0;
3560 }
3561
3562 return 0;
3563 }
3564
3565 int config_parse_io_device_weight(
3566 const char *unit,
3567 const char *filename,
3568 unsigned line,
3569 const char *section,
3570 unsigned section_line,
3571 const char *lvalue,
3572 int ltype,
3573 const char *rvalue,
3574 void *data,
3575 void *userdata) {
3576
3577 _cleanup_free_ char *path = NULL;
3578 CGroupIODeviceWeight *w;
3579 CGroupContext *c = data;
3580 const char *weight;
3581 uint64_t u;
3582 size_t n;
3583 int r;
3584
3585 assert(filename);
3586 assert(lvalue);
3587 assert(rvalue);
3588
3589 if (isempty(rvalue)) {
3590 while (c->io_device_weights)
3591 cgroup_context_free_io_device_weight(c, c->io_device_weights);
3592
3593 return 0;
3594 }
3595
3596 n = strcspn(rvalue, WHITESPACE);
3597 weight = rvalue + n;
3598 weight += strspn(weight, WHITESPACE);
3599
3600 if (isempty(weight)) {
3601 log_syntax(unit, LOG_ERR, filename, line, 0, "Expected block device and device weight. Ignoring.");
3602 return 0;
3603 }
3604
3605 path = strndup(rvalue, n);
3606 if (!path)
3607 return log_oom();
3608
3609 if (!path_startswith(path, "/dev") &&
3610 !path_startswith(path, "/run/systemd/inaccessible/")) {
3611 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
3612 return 0;
3613 }
3614
3615 r = cg_weight_parse(weight, &u);
3616 if (r < 0) {
3617 log_syntax(unit, LOG_ERR, filename, line, r, "IO weight '%s' invalid. Ignoring.", weight);
3618 return 0;
3619 }
3620
3621 assert(u != CGROUP_WEIGHT_INVALID);
3622
3623 w = new0(CGroupIODeviceWeight, 1);
3624 if (!w)
3625 return log_oom();
3626
3627 w->path = TAKE_PTR(path);
3628
3629 w->weight = u;
3630
3631 LIST_PREPEND(device_weights, c->io_device_weights, w);
3632 return 0;
3633 }
3634
3635 int config_parse_io_limit(
3636 const char *unit,
3637 const char *filename,
3638 unsigned line,
3639 const char *section,
3640 unsigned section_line,
3641 const char *lvalue,
3642 int ltype,
3643 const char *rvalue,
3644 void *data,
3645 void *userdata) {
3646
3647 _cleanup_free_ char *path = NULL;
3648 CGroupIODeviceLimit *l = NULL, *t;
3649 CGroupContext *c = data;
3650 CGroupIOLimitType type;
3651 const char *limit;
3652 uint64_t num;
3653 size_t n;
3654 int r;
3655
3656 assert(filename);
3657 assert(lvalue);
3658 assert(rvalue);
3659
3660 type = cgroup_io_limit_type_from_string(lvalue);
3661 assert(type >= 0);
3662
3663 if (isempty(rvalue)) {
3664 LIST_FOREACH(device_limits, l, c->io_device_limits)
3665 l->limits[type] = cgroup_io_limit_defaults[type];
3666 return 0;
3667 }
3668
3669 n = strcspn(rvalue, WHITESPACE);
3670 limit = rvalue + n;
3671 limit += strspn(limit, WHITESPACE);
3672
3673 if (!*limit) {
3674 log_syntax(unit, LOG_ERR, filename, line, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
3675 return 0;
3676 }
3677
3678 path = strndup(rvalue, n);
3679 if (!path)
3680 return log_oom();
3681
3682 if (!path_startswith(path, "/dev") &&
3683 !path_startswith(path, "/run/systemd/inaccessible/")) {
3684 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
3685 return 0;
3686 }
3687
3688 if (streq("infinity", limit)) {
3689 num = CGROUP_LIMIT_MAX;
3690 } else {
3691 r = parse_size(limit, 1000, &num);
3692 if (r < 0 || num <= 0) {
3693 log_syntax(unit, LOG_ERR, filename, line, r, "IO Limit '%s' invalid. Ignoring.", rvalue);
3694 return 0;
3695 }
3696 }
3697
3698 LIST_FOREACH(device_limits, t, c->io_device_limits) {
3699 if (path_equal(path, t->path)) {
3700 l = t;
3701 break;
3702 }
3703 }
3704
3705 if (!l) {
3706 CGroupIOLimitType ttype;
3707
3708 l = new0(CGroupIODeviceLimit, 1);
3709 if (!l)
3710 return log_oom();
3711
3712 l->path = TAKE_PTR(path);
3713 for (ttype = 0; ttype < _CGROUP_IO_LIMIT_TYPE_MAX; ttype++)
3714 l->limits[ttype] = cgroup_io_limit_defaults[ttype];
3715
3716 LIST_PREPEND(device_limits, c->io_device_limits, l);
3717 }
3718
3719 l->limits[type] = num;
3720
3721 return 0;
3722 }
3723
3724 int config_parse_blockio_weight(
3725 const char *unit,
3726 const char *filename,
3727 unsigned line,
3728 const char *section,
3729 unsigned section_line,
3730 const char *lvalue,
3731 int ltype,
3732 const char *rvalue,
3733 void *data,
3734 void *userdata) {
3735
3736 uint64_t *weight = data;
3737 int r;
3738
3739 assert(filename);
3740 assert(lvalue);
3741 assert(rvalue);
3742
3743 r = cg_blkio_weight_parse(rvalue, weight);
3744 if (r < 0) {
3745 log_syntax(unit, LOG_ERR, filename, line, r, "Block IO weight '%s' invalid. Ignoring.", rvalue);
3746 return 0;
3747 }
3748
3749 return 0;
3750 }
3751
3752 int config_parse_blockio_device_weight(
3753 const char *unit,
3754 const char *filename,
3755 unsigned line,
3756 const char *section,
3757 unsigned section_line,
3758 const char *lvalue,
3759 int ltype,
3760 const char *rvalue,
3761 void *data,
3762 void *userdata) {
3763
3764 _cleanup_free_ char *path = NULL;
3765 CGroupBlockIODeviceWeight *w;
3766 CGroupContext *c = data;
3767 const char *weight;
3768 uint64_t u;
3769 size_t n;
3770 int r;
3771
3772 assert(filename);
3773 assert(lvalue);
3774 assert(rvalue);
3775
3776 if (isempty(rvalue)) {
3777 while (c->blockio_device_weights)
3778 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
3779
3780 return 0;
3781 }
3782
3783 n = strcspn(rvalue, WHITESPACE);
3784 weight = rvalue + n;
3785 weight += strspn(weight, WHITESPACE);
3786
3787 if (isempty(weight)) {
3788 log_syntax(unit, LOG_ERR, filename, line, 0, "Expected block device and device weight. Ignoring.");
3789 return 0;
3790 }
3791
3792 path = strndup(rvalue, n);
3793 if (!path)
3794 return log_oom();
3795
3796 if (!path_startswith(path, "/dev") &&
3797 !path_startswith(path, "/run/systemd/inaccessible/")) {
3798 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
3799 return 0;
3800 }
3801
3802 r = cg_blkio_weight_parse(weight, &u);
3803 if (r < 0) {
3804 log_syntax(unit, LOG_ERR, filename, line, r, "Block IO weight '%s' invalid. Ignoring.", weight);
3805 return 0;
3806 }
3807
3808 assert(u != CGROUP_BLKIO_WEIGHT_INVALID);
3809
3810 w = new0(CGroupBlockIODeviceWeight, 1);
3811 if (!w)
3812 return log_oom();
3813
3814 w->path = TAKE_PTR(path);
3815
3816 w->weight = u;
3817
3818 LIST_PREPEND(device_weights, c->blockio_device_weights, w);
3819 return 0;
3820 }
3821
3822 int config_parse_blockio_bandwidth(
3823 const char *unit,
3824 const char *filename,
3825 unsigned line,
3826 const char *section,
3827 unsigned section_line,
3828 const char *lvalue,
3829 int ltype,
3830 const char *rvalue,
3831 void *data,
3832 void *userdata) {
3833
3834 _cleanup_free_ char *path = NULL;
3835 CGroupBlockIODeviceBandwidth *b = NULL, *t;
3836 CGroupContext *c = data;
3837 const char *bandwidth;
3838 uint64_t bytes;
3839 bool read;
3840 size_t n;
3841 int r;
3842
3843 assert(filename);
3844 assert(lvalue);
3845 assert(rvalue);
3846
3847 read = streq("BlockIOReadBandwidth", lvalue);
3848
3849 if (isempty(rvalue)) {
3850 LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
3851 b->rbps = CGROUP_LIMIT_MAX;
3852 b->wbps = CGROUP_LIMIT_MAX;
3853 }
3854 return 0;
3855 }
3856
3857 n = strcspn(rvalue, WHITESPACE);
3858 bandwidth = rvalue + n;
3859 bandwidth += strspn(bandwidth, WHITESPACE);
3860
3861 if (!*bandwidth) {
3862 log_syntax(unit, LOG_ERR, filename, line, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
3863 return 0;
3864 }
3865
3866 path = strndup(rvalue, n);
3867 if (!path)
3868 return log_oom();
3869
3870 if (!path_startswith(path, "/dev") &&
3871 !path_startswith(path, "/run/systemd/inaccessible/")) {
3872 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
3873 return 0;
3874 }
3875
3876 r = parse_size(bandwidth, 1000, &bytes);
3877 if (r < 0 || bytes <= 0) {
3878 log_syntax(unit, LOG_ERR, filename, line, r, "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
3879 return 0;
3880 }
3881
3882 LIST_FOREACH(device_bandwidths, t, c->blockio_device_bandwidths) {
3883 if (path_equal(path, t->path)) {
3884 b = t;
3885 break;
3886 }
3887 }
3888
3889 if (!t) {
3890 b = new0(CGroupBlockIODeviceBandwidth, 1);
3891 if (!b)
3892 return log_oom();
3893
3894 b->path = TAKE_PTR(path);
3895 b->rbps = CGROUP_LIMIT_MAX;
3896 b->wbps = CGROUP_LIMIT_MAX;
3897
3898 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
3899 }
3900
3901 if (read)
3902 b->rbps = bytes;
3903 else
3904 b->wbps = bytes;
3905
3906 return 0;
3907 }
3908
3909 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
3910
3911 int config_parse_job_mode_isolate(
3912 const char *unit,
3913 const char *filename,
3914 unsigned line,
3915 const char *section,
3916 unsigned section_line,
3917 const char *lvalue,
3918 int ltype,
3919 const char *rvalue,
3920 void *data,
3921 void *userdata) {
3922
3923 JobMode *m = data;
3924 int r;
3925
3926 assert(filename);
3927 assert(lvalue);
3928 assert(rvalue);
3929
3930 r = parse_boolean(rvalue);
3931 if (r < 0) {
3932 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse boolean, ignoring: %s", rvalue);
3933 return 0;
3934 }
3935
3936 log_notice("%s is deprecated. Please use OnFailureJobMode= instead", lvalue);
3937
3938 *m = r ? JOB_ISOLATE : JOB_REPLACE;
3939 return 0;
3940 }
3941
3942 DEFINE_CONFIG_PARSE_ENUM(config_parse_runtime_preserve_mode, exec_preserve_mode, ExecPreserveMode, "Failed to parse runtime directory preserve mode");
3943
3944 int config_parse_exec_directories(
3945 const char *unit,
3946 const char *filename,
3947 unsigned line,
3948 const char *section,
3949 unsigned section_line,
3950 const char *lvalue,
3951 int ltype,
3952 const char *rvalue,
3953 void *data,
3954 void *userdata) {
3955
3956 char***rt = data;
3957 Unit *u = userdata;
3958 const char *p;
3959 int r;
3960
3961 assert(filename);
3962 assert(lvalue);
3963 assert(rvalue);
3964 assert(data);
3965
3966 if (isempty(rvalue)) {
3967 /* Empty assignment resets the list */
3968 *rt = strv_free(*rt);
3969 return 0;
3970 }
3971
3972 for (p = rvalue;;) {
3973 _cleanup_free_ char *word = NULL, *k = NULL;
3974
3975 r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
3976 if (r == -ENOMEM)
3977 return log_oom();
3978 if (r < 0) {
3979 log_syntax(unit, LOG_WARNING, filename, line, r,
3980 "Invalid syntax, ignoring: %s", rvalue);
3981 return 0;
3982 }
3983 if (r == 0)
3984 return 0;
3985
3986 r = unit_full_printf(u, word, &k);
3987 if (r < 0) {
3988 log_syntax(unit, LOG_ERR, filename, line, r,
3989 "Failed to resolve specifiers in \"%s\", ignoring: %m", word);
3990 continue;
3991 }
3992
3993 if (!path_is_normalized(k) || path_is_absolute(k)) {
3994 log_syntax(unit, LOG_ERR, filename, line, 0,
3995 "%s= path is not valid, ignoring assignment: %s", lvalue, rvalue);
3996 continue;
3997 }
3998
3999 r = strv_push(rt, k);
4000 if (r < 0)
4001 return log_oom();
4002 k = NULL;
4003 }
4004 }
4005
4006 int config_parse_set_status(
4007 const char *unit,
4008 const char *filename,
4009 unsigned line,
4010 const char *section,
4011 unsigned section_line,
4012 const char *lvalue,
4013 int ltype,
4014 const char *rvalue,
4015 void *data,
4016 void *userdata) {
4017
4018 size_t l;
4019 const char *word, *state;
4020 int r;
4021 ExitStatusSet *status_set = data;
4022
4023 assert(filename);
4024 assert(lvalue);
4025 assert(rvalue);
4026 assert(data);
4027
4028 /* Empty assignment resets the list */
4029 if (isempty(rvalue)) {
4030 exit_status_set_free(status_set);
4031 return 0;
4032 }
4033
4034 FOREACH_WORD(word, l, rvalue, state) {
4035 _cleanup_free_ char *temp;
4036 int val;
4037 Set **set;
4038
4039 temp = strndup(word, l);
4040 if (!temp)
4041 return log_oom();
4042
4043 r = safe_atoi(temp, &val);
4044 if (r < 0) {
4045 val = signal_from_string(temp);
4046
4047 if (val <= 0) {
4048 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse value, ignoring: %s", word);
4049 continue;
4050 }
4051 set = &status_set->signal;
4052 } else {
4053 if (val < 0 || val > 255) {
4054 log_syntax(unit, LOG_ERR, filename, line, 0, "Value %d is outside range 0-255, ignoring", val);
4055 continue;
4056 }
4057 set = &status_set->status;
4058 }
4059
4060 r = set_ensure_allocated(set, NULL);
4061 if (r < 0)
4062 return log_oom();
4063
4064 r = set_put(*set, INT_TO_PTR(val));
4065 if (r < 0) {
4066 log_syntax(unit, LOG_ERR, filename, line, r, "Unable to store: %s", word);
4067 return r;
4068 }
4069 }
4070 if (!isempty(state))
4071 log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
4072
4073 return 0;
4074 }
4075
4076 int config_parse_namespace_path_strv(
4077 const char *unit,
4078 const char *filename,
4079 unsigned line,
4080 const char *section,
4081 unsigned section_line,
4082 const char *lvalue,
4083 int ltype,
4084 const char *rvalue,
4085 void *data,
4086 void *userdata) {
4087
4088 Unit *u = userdata;
4089 char*** sv = data;
4090 const char *cur;
4091 int r;
4092
4093 assert(filename);
4094 assert(lvalue);
4095 assert(rvalue);
4096 assert(data);
4097
4098 if (isempty(rvalue)) {
4099 /* Empty assignment resets the list */
4100 *sv = strv_free(*sv);
4101 return 0;
4102 }
4103
4104 cur = rvalue;
4105 for (;;) {
4106 _cleanup_free_ char *word = NULL, *resolved = NULL, *joined = NULL;
4107 const char *w;
4108 bool ignore_enoent = false, shall_prefix = false;
4109
4110 r = extract_first_word(&cur, &word, NULL, EXTRACT_QUOTES);
4111 if (r == 0)
4112 break;
4113 if (r == -ENOMEM)
4114 return log_oom();
4115 if (r < 0) {
4116 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract first word, ignoring: %s", rvalue);
4117 return 0;
4118 }
4119
4120 if (!utf8_is_valid(word)) {
4121 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, word);
4122 continue;
4123 }
4124
4125 w = word;
4126 if (startswith(w, "-")) {
4127 ignore_enoent = true;
4128 w++;
4129 }
4130 if (startswith(w, "+")) {
4131 shall_prefix = true;
4132 w++;
4133 }
4134
4135 r = unit_full_printf(u, w, &resolved);
4136 if (r < 0) {
4137 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers in %s: %m", word);
4138 continue;
4139 }
4140
4141 if (!path_is_absolute(resolved)) {
4142 log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute path, ignoring: %s", resolved);
4143 continue;
4144 }
4145
4146 path_kill_slashes(resolved);
4147
4148 joined = strjoin(ignore_enoent ? "-" : "",
4149 shall_prefix ? "+" : "",
4150 resolved);
4151
4152 r = strv_push(sv, joined);
4153 if (r < 0)
4154 return log_oom();
4155
4156 joined = NULL;
4157 }
4158
4159 return 0;
4160 }
4161
4162 int config_parse_temporary_filesystems(
4163 const char *unit,
4164 const char *filename,
4165 unsigned line,
4166 const char *section,
4167 unsigned section_line,
4168 const char *lvalue,
4169 int ltype,
4170 const char *rvalue,
4171 void *data,
4172 void *userdata) {
4173
4174 Unit *u = userdata;
4175 ExecContext *c = data;
4176 const char *cur;
4177 int r;
4178
4179 assert(filename);
4180 assert(lvalue);
4181 assert(rvalue);
4182 assert(data);
4183
4184 if (isempty(rvalue)) {
4185 /* Empty assignment resets the list */
4186 temporary_filesystem_free_many(c->temporary_filesystems, c->n_temporary_filesystems);
4187 c->temporary_filesystems = NULL;
4188 c->n_temporary_filesystems = 0;
4189 return 0;
4190 }
4191
4192 cur = rvalue;
4193 for (;;) {
4194 _cleanup_free_ char *word = NULL, *path = NULL, *resolved = NULL;
4195 const char *w;
4196
4197 r = extract_first_word(&cur, &word, NULL, EXTRACT_QUOTES);
4198 if (r == 0)
4199 break;
4200 if (r == -ENOMEM)
4201 return log_oom();
4202 if (r < 0) {
4203 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract first word, ignoring: %s", rvalue);
4204 return 0;
4205 }
4206
4207 w = word;
4208 r = extract_first_word(&w, &path, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
4209 if (r < 0)
4210 return r;
4211 if (r == 0)
4212 return -EINVAL;
4213
4214 r = unit_full_printf(u, path, &resolved);
4215 if (r < 0) {
4216 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers in %s, ignoring: %m", word);
4217 continue;
4218 }
4219
4220 if (!path_is_absolute(resolved)) {
4221 log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute path, ignoring: %s", resolved);
4222 continue;
4223 }
4224
4225 path_kill_slashes(resolved);
4226
4227 r = temporary_filesystem_add(&c->temporary_filesystems, &c->n_temporary_filesystems, path, w);
4228 if (r == -ENOMEM)
4229 return log_oom();
4230 if (r < 0) {
4231 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse mount options, ignoring: %s", word);
4232 continue;
4233 }
4234 }
4235
4236 return 0;
4237 }
4238
4239 int config_parse_bind_paths(
4240 const char *unit,
4241 const char *filename,
4242 unsigned line,
4243 const char *section,
4244 unsigned section_line,
4245 const char *lvalue,
4246 int ltype,
4247 const char *rvalue,
4248 void *data,
4249 void *userdata) {
4250
4251 ExecContext *c = data;
4252 Unit *u = userdata;
4253 const char *p;
4254 int r;
4255
4256 assert(filename);
4257 assert(lvalue);
4258 assert(rvalue);
4259 assert(data);
4260
4261 if (isempty(rvalue)) {
4262 /* Empty assignment resets the list */
4263 bind_mount_free_many(c->bind_mounts, c->n_bind_mounts);
4264 c->bind_mounts = NULL;
4265 c->n_bind_mounts = 0;
4266 return 0;
4267 }
4268
4269 p = rvalue;
4270 for (;;) {
4271 _cleanup_free_ char *source = NULL, *destination = NULL;
4272 _cleanup_free_ char *sresolved = NULL, *dresolved = NULL;
4273 char *s = NULL, *d = NULL;
4274 bool rbind = true, ignore_enoent = false;
4275
4276 r = extract_first_word(&p, &source, ":" WHITESPACE, EXTRACT_QUOTES|EXTRACT_DONT_COALESCE_SEPARATORS);
4277 if (r == 0)
4278 break;
4279 if (r == -ENOMEM)
4280 return log_oom();
4281 if (r < 0) {
4282 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s: %s", lvalue, rvalue);
4283 return 0;
4284 }
4285
4286 r = unit_full_printf(u, source, &sresolved);
4287 if (r < 0) {
4288 log_syntax(unit, LOG_ERR, filename, line, r,
4289 "Failed to resolved specifiers in \"%s\", ignoring: %m", source);
4290 return 0;
4291 }
4292
4293 s = sresolved;
4294 if (s[0] == '-') {
4295 ignore_enoent = true;
4296 s++;
4297 }
4298
4299 if (!utf8_is_valid(s)) {
4300 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, s);
4301 return 0;
4302 }
4303 if (!path_is_absolute(s)) {
4304 log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute source path, ignoring: %s", s);
4305 return 0;
4306 }
4307
4308 path_kill_slashes(s);
4309
4310 /* Optionally, the destination is specified. */
4311 if (p && p[-1] == ':') {
4312 r = extract_first_word(&p, &destination, ":" WHITESPACE, EXTRACT_QUOTES|EXTRACT_DONT_COALESCE_SEPARATORS);
4313 if (r == -ENOMEM)
4314 return log_oom();
4315 if (r < 0) {
4316 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s: %s", lvalue, rvalue);
4317 return 0;
4318 }
4319 if (r == 0) {
4320 log_syntax(unit, LOG_ERR, filename, line, 0, "Missing argument after ':': %s", rvalue);
4321 return 0;
4322 }
4323
4324 r = unit_full_printf(u, destination, &dresolved);
4325 if (r < 0) {
4326 log_syntax(unit, LOG_ERR, filename, line, r,
4327 "Failed to resolved specifiers in \"%s\", ignoring: %m", destination);
4328 return 0;
4329 }
4330
4331 if (!utf8_is_valid(dresolved)) {
4332 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, dresolved);
4333 return 0;
4334 }
4335 if (!path_is_absolute(dresolved)) {
4336 log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute destination path, ignoring: %s", dresolved);
4337 return 0;
4338 }
4339
4340 d = path_kill_slashes(dresolved);
4341
4342 /* Optionally, there's also a short option string specified */
4343 if (p && p[-1] == ':') {
4344 _cleanup_free_ char *options = NULL;
4345
4346 r = extract_first_word(&p, &options, NULL, EXTRACT_QUOTES);
4347 if (r == -ENOMEM)
4348 return log_oom();
4349 if (r < 0) {
4350 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s: %s", lvalue, rvalue);
4351 return 0;
4352 }
4353
4354 if (isempty(options) || streq(options, "rbind"))
4355 rbind = true;
4356 else if (streq(options, "norbind"))
4357 rbind = false;
4358 else {
4359 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid option string, ignoring setting: %s", options);
4360 return 0;
4361 }
4362 }
4363 } else
4364 d = s;
4365
4366 r = bind_mount_add(&c->bind_mounts, &c->n_bind_mounts,
4367 &(BindMount) {
4368 .source = s,
4369 .destination = d,
4370 .read_only = !!strstr(lvalue, "ReadOnly"),
4371 .recursive = rbind,
4372 .ignore_enoent = ignore_enoent,
4373 });
4374 if (r < 0)
4375 return log_oom();
4376 }
4377
4378 return 0;
4379 }
4380
4381 int config_parse_no_new_privileges(
4382 const char* unit,
4383 const char *filename,
4384 unsigned line,
4385 const char *section,
4386 unsigned section_line,
4387 const char *lvalue,
4388 int ltype,
4389 const char *rvalue,
4390 void *data,
4391 void *userdata) {
4392
4393 ExecContext *c = data;
4394 int k;
4395
4396 assert(filename);
4397 assert(lvalue);
4398 assert(rvalue);
4399 assert(data);
4400
4401 k = parse_boolean(rvalue);
4402 if (k < 0) {
4403 log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse boolean value, ignoring: %s", rvalue);
4404 return 0;
4405 }
4406
4407 c->no_new_privileges = k;
4408
4409 return 0;
4410 }
4411
4412 int config_parse_protect_home(
4413 const char* unit,
4414 const char *filename,
4415 unsigned line,
4416 const char *section,
4417 unsigned section_line,
4418 const char *lvalue,
4419 int ltype,
4420 const char *rvalue,
4421 void *data,
4422 void *userdata) {
4423
4424 ExecContext *c = data;
4425 ProtectHome h;
4426
4427 assert(filename);
4428 assert(lvalue);
4429 assert(rvalue);
4430 assert(data);
4431
4432 /* Our enum shall be a superset of booleans, hence first try
4433 * to parse as boolean, and then as enum */
4434
4435 h = parse_protect_home_or_bool(rvalue);
4436 if (h < 0) {
4437 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse protect home value, ignoring: %s", rvalue);
4438 return 0;
4439 }
4440
4441 c->protect_home = h;
4442
4443 return 0;
4444 }
4445
4446 int config_parse_protect_system(
4447 const char* unit,
4448 const char *filename,
4449 unsigned line,
4450 const char *section,
4451 unsigned section_line,
4452 const char *lvalue,
4453 int ltype,
4454 const char *rvalue,
4455 void *data,
4456 void *userdata) {
4457
4458 ExecContext *c = data;
4459 ProtectSystem s;
4460
4461 assert(filename);
4462 assert(lvalue);
4463 assert(rvalue);
4464 assert(data);
4465
4466 /* Our enum shall be a superset of booleans, hence first try
4467 * to parse as boolean, and then as enum */
4468
4469 s = parse_protect_system_or_bool(rvalue);
4470 if (s < 0) {
4471 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse protect system value, ignoring: %s", rvalue);
4472 return 0;
4473 }
4474
4475 c->protect_system = s;
4476
4477 return 0;
4478 }
4479
4480 DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_keyring_mode, exec_keyring_mode, ExecKeyringMode, "Failed to parse keyring mode");
4481
4482 int config_parse_job_timeout_sec(
4483 const char* unit,
4484 const char *filename,
4485 unsigned line,
4486 const char *section,
4487 unsigned section_line,
4488 const char *lvalue,
4489 int ltype,
4490 const char *rvalue,
4491 void *data,
4492 void *userdata) {
4493
4494 Unit *u = data;
4495 usec_t usec;
4496 int r;
4497
4498 assert(filename);
4499 assert(lvalue);
4500 assert(rvalue);
4501 assert(u);
4502
4503 r = parse_sec_fix_0(rvalue, &usec);
4504 if (r < 0) {
4505 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse JobTimeoutSec= parameter, ignoring: %s", rvalue);
4506 return 0;
4507 }
4508
4509 /* If the user explicitly changed JobTimeoutSec= also change JobRunningTimeoutSec=, for compatibility with old
4510 * versions. If JobRunningTimeoutSec= was explicitly set, avoid this however as whatever the user picked should
4511 * count. */
4512
4513 if (!u->job_running_timeout_set)
4514 u->job_running_timeout = usec;
4515
4516 u->job_timeout = usec;
4517
4518 return 0;
4519 }
4520
4521 int config_parse_job_running_timeout_sec(
4522 const char* unit,
4523 const char *filename,
4524 unsigned line,
4525 const char *section,
4526 unsigned section_line,
4527 const char *lvalue,
4528 int ltype,
4529 const char *rvalue,
4530 void *data,
4531 void *userdata) {
4532
4533 Unit *u = data;
4534 usec_t usec;
4535 int r;
4536
4537 assert(filename);
4538 assert(lvalue);
4539 assert(rvalue);
4540 assert(u);
4541
4542 r = parse_sec_fix_0(rvalue, &usec);
4543 if (r < 0) {
4544 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse JobRunningTimeoutSec= parameter, ignoring: %s", rvalue);
4545 return 0;
4546 }
4547
4548 u->job_running_timeout = usec;
4549 u->job_running_timeout_set = true;
4550
4551 return 0;
4552 }
4553
4554 #define FOLLOW_MAX 8
4555
4556 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
4557 char *id = NULL;
4558 unsigned c = 0;
4559 int fd, r;
4560 FILE *f;
4561
4562 assert(filename);
4563 assert(*filename);
4564 assert(_f);
4565 assert(names);
4566
4567 /* This will update the filename pointer if the loaded file is
4568 * reached by a symlink. The old string will be freed. */
4569
4570 for (;;) {
4571 char *target, *name;
4572
4573 if (c++ >= FOLLOW_MAX)
4574 return -ELOOP;
4575
4576 path_kill_slashes(*filename);
4577
4578 /* Add the file name we are currently looking at to
4579 * the names of this unit, but only if it is a valid
4580 * unit name. */
4581 name = basename(*filename);
4582 if (unit_name_is_valid(name, UNIT_NAME_ANY)) {
4583
4584 id = set_get(names, name);
4585 if (!id) {
4586 id = strdup(name);
4587 if (!id)
4588 return -ENOMEM;
4589
4590 r = set_consume(names, id);
4591 if (r < 0)
4592 return r;
4593 }
4594 }
4595
4596 /* Try to open the file name, but don't if its a symlink */
4597 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
4598 if (fd >= 0)
4599 break;
4600
4601 if (errno != ELOOP)
4602 return -errno;
4603
4604 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
4605 r = readlink_and_make_absolute(*filename, &target);
4606 if (r < 0)
4607 return r;
4608
4609 free(*filename);
4610 *filename = target;
4611 }
4612
4613 f = fdopen(fd, "re");
4614 if (!f) {
4615 safe_close(fd);
4616 return -errno;
4617 }
4618
4619 *_f = f;
4620 *_final = id;
4621
4622 return 0;
4623 }
4624
4625 static int merge_by_names(Unit **u, Set *names, const char *id) {
4626 char *k;
4627 int r;
4628
4629 assert(u);
4630 assert(*u);
4631 assert(names);
4632
4633 /* Let's try to add in all symlink names we found */
4634 while ((k = set_steal_first(names))) {
4635
4636 /* First try to merge in the other name into our
4637 * unit */
4638 r = unit_merge_by_name(*u, k);
4639 if (r < 0) {
4640 Unit *other;
4641
4642 /* Hmm, we couldn't merge the other unit into
4643 * ours? Then let's try it the other way
4644 * round */
4645
4646 /* If the symlink name we are looking at is unit template, then
4647 we must search for instance of this template */
4648 if (unit_name_is_valid(k, UNIT_NAME_TEMPLATE) && (*u)->instance) {
4649 _cleanup_free_ char *instance = NULL;
4650
4651 r = unit_name_replace_instance(k, (*u)->instance, &instance);
4652 if (r < 0)
4653 return r;
4654
4655 other = manager_get_unit((*u)->manager, instance);
4656 } else
4657 other = manager_get_unit((*u)->manager, k);
4658
4659 free(k);
4660
4661 if (other) {
4662 r = unit_merge(other, *u);
4663 if (r >= 0) {
4664 *u = other;
4665 return merge_by_names(u, names, NULL);
4666 }
4667 }
4668
4669 return r;
4670 }
4671
4672 if (id == k)
4673 unit_choose_id(*u, id);
4674
4675 free(k);
4676 }
4677
4678 return 0;
4679 }
4680
4681 static int load_from_path(Unit *u, const char *path) {
4682 _cleanup_set_free_free_ Set *symlink_names = NULL;
4683 _cleanup_fclose_ FILE *f = NULL;
4684 _cleanup_free_ char *filename = NULL;
4685 char *id = NULL;
4686 Unit *merged;
4687 struct stat st;
4688 int r;
4689
4690 assert(u);
4691 assert(path);
4692
4693 symlink_names = set_new(&string_hash_ops);
4694 if (!symlink_names)
4695 return -ENOMEM;
4696
4697 if (path_is_absolute(path)) {
4698
4699 filename = strdup(path);
4700 if (!filename)
4701 return -ENOMEM;
4702
4703 r = open_follow(&filename, &f, symlink_names, &id);
4704 if (r < 0) {
4705 filename = mfree(filename);
4706 if (r != -ENOENT)
4707 return r;
4708 }
4709
4710 } else {
4711 char **p;
4712
4713 STRV_FOREACH(p, u->manager->lookup_paths.search_path) {
4714
4715 /* Instead of opening the path right away, we manually
4716 * follow all symlinks and add their name to our unit
4717 * name set while doing so */
4718 filename = path_make_absolute(path, *p);
4719 if (!filename)
4720 return -ENOMEM;
4721
4722 if (u->manager->unit_path_cache &&
4723 !set_get(u->manager->unit_path_cache, filename))
4724 r = -ENOENT;
4725 else
4726 r = open_follow(&filename, &f, symlink_names, &id);
4727 if (r >= 0)
4728 break;
4729 filename = mfree(filename);
4730
4731 /* ENOENT means that the file is missing or is a dangling symlink.
4732 * ENOTDIR means that one of paths we expect to be is a directory
4733 * is not a directory, we should just ignore that.
4734 * EACCES means that the directory or file permissions are wrong.
4735 */
4736 if (r == -EACCES)
4737 log_debug_errno(r, "Cannot access \"%s\": %m", filename);
4738 else if (!IN_SET(r, -ENOENT, -ENOTDIR))
4739 return r;
4740
4741 /* Empty the symlink names for the next run */
4742 set_clear_free(symlink_names);
4743 }
4744 }
4745
4746 if (!filename)
4747 /* Hmm, no suitable file found? */
4748 return 0;
4749
4750 if (!unit_type_may_alias(u->type) && set_size(symlink_names) > 1) {
4751 log_unit_warning(u, "Unit type of %s does not support alias names, refusing loading via symlink.", u->id);
4752 return -ELOOP;
4753 }
4754
4755 merged = u;
4756 r = merge_by_names(&merged, symlink_names, id);
4757 if (r < 0)
4758 return r;
4759
4760 if (merged != u) {
4761 u->load_state = UNIT_MERGED;
4762 return 0;
4763 }
4764
4765 if (fstat(fileno(f), &st) < 0)
4766 return -errno;
4767
4768 if (null_or_empty(&st)) {
4769 u->load_state = UNIT_MASKED;
4770 u->fragment_mtime = 0;
4771 } else {
4772 u->load_state = UNIT_LOADED;
4773 u->fragment_mtime = timespec_load(&st.st_mtim);
4774
4775 /* Now, parse the file contents */
4776 r = config_parse(u->id, filename, f,
4777 UNIT_VTABLE(u)->sections,
4778 config_item_perf_lookup, load_fragment_gperf_lookup,
4779 CONFIG_PARSE_ALLOW_INCLUDE, u);
4780 if (r < 0)
4781 return r;
4782 }
4783
4784 free_and_replace(u->fragment_path, filename);
4785
4786 if (u->source_path) {
4787 if (stat(u->source_path, &st) >= 0)
4788 u->source_mtime = timespec_load(&st.st_mtim);
4789 else
4790 u->source_mtime = 0;
4791 }
4792
4793 return 0;
4794 }
4795
4796 int unit_load_fragment(Unit *u) {
4797 int r;
4798 Iterator i;
4799 const char *t;
4800
4801 assert(u);
4802 assert(u->load_state == UNIT_STUB);
4803 assert(u->id);
4804
4805 if (u->transient) {
4806 u->load_state = UNIT_LOADED;
4807 return 0;
4808 }
4809
4810 /* First, try to find the unit under its id. We always look
4811 * for unit files in the default directories, to make it easy
4812 * to override things by placing things in /etc/systemd/system */
4813 r = load_from_path(u, u->id);
4814 if (r < 0)
4815 return r;
4816
4817 /* Try to find an alias we can load this with */
4818 if (u->load_state == UNIT_STUB) {
4819 SET_FOREACH(t, u->names, i) {
4820
4821 if (t == u->id)
4822 continue;
4823
4824 r = load_from_path(u, t);
4825 if (r < 0)
4826 return r;
4827
4828 if (u->load_state != UNIT_STUB)
4829 break;
4830 }
4831 }
4832
4833 /* And now, try looking for it under the suggested (originally linked) path */
4834 if (u->load_state == UNIT_STUB && u->fragment_path) {
4835
4836 r = load_from_path(u, u->fragment_path);
4837 if (r < 0)
4838 return r;
4839
4840 if (u->load_state == UNIT_STUB)
4841 /* Hmm, this didn't work? Then let's get rid
4842 * of the fragment path stored for us, so that
4843 * we don't point to an invalid location. */
4844 u->fragment_path = mfree(u->fragment_path);
4845 }
4846
4847 /* Look for a template */
4848 if (u->load_state == UNIT_STUB && u->instance) {
4849 _cleanup_free_ char *k = NULL;
4850
4851 r = unit_name_template(u->id, &k);
4852 if (r < 0)
4853 return r;
4854
4855 r = load_from_path(u, k);
4856 if (r < 0) {
4857 if (r == -ENOEXEC)
4858 log_unit_notice(u, "Unit configuration has fatal error, unit will not be started.");
4859 return r;
4860 }
4861
4862 if (u->load_state == UNIT_STUB) {
4863 SET_FOREACH(t, u->names, i) {
4864 _cleanup_free_ char *z = NULL;
4865
4866 if (t == u->id)
4867 continue;
4868
4869 r = unit_name_template(t, &z);
4870 if (r < 0)
4871 return r;
4872
4873 r = load_from_path(u, z);
4874 if (r < 0)
4875 return r;
4876
4877 if (u->load_state != UNIT_STUB)
4878 break;
4879 }
4880 }
4881 }
4882
4883 return 0;
4884 }
4885
4886 void unit_dump_config_items(FILE *f) {
4887 static const struct {
4888 const ConfigParserCallback callback;
4889 const char *rvalue;
4890 } table[] = {
4891 #if !HAVE_SYSV_COMPAT || !HAVE_SECCOMP || !HAVE_PAM || !HAVE_SELINUX || !ENABLE_SMACK || !HAVE_APPARMOR
4892 { config_parse_warn_compat, "NOTSUPPORTED" },
4893 #endif
4894 { config_parse_int, "INTEGER" },
4895 { config_parse_unsigned, "UNSIGNED" },
4896 { config_parse_iec_size, "SIZE" },
4897 { config_parse_iec_uint64, "SIZE" },
4898 { config_parse_si_size, "SIZE" },
4899 { config_parse_bool, "BOOLEAN" },
4900 { config_parse_string, "STRING" },
4901 { config_parse_path, "PATH" },
4902 { config_parse_unit_path_printf, "PATH" },
4903 { config_parse_strv, "STRING [...]" },
4904 { config_parse_exec_nice, "NICE" },
4905 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
4906 { config_parse_exec_io_class, "IOCLASS" },
4907 { config_parse_exec_io_priority, "IOPRIORITY" },
4908 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
4909 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
4910 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
4911 { config_parse_mode, "MODE" },
4912 { config_parse_unit_env_file, "FILE" },
4913 { config_parse_exec_output, "OUTPUT" },
4914 { config_parse_exec_input, "INPUT" },
4915 { config_parse_log_facility, "FACILITY" },
4916 { config_parse_log_level, "LEVEL" },
4917 { config_parse_exec_secure_bits, "SECUREBITS" },
4918 { config_parse_capability_set, "BOUNDINGSET" },
4919 { config_parse_limit, "LIMIT" },
4920 { config_parse_unit_deps, "UNIT [...]" },
4921 { config_parse_exec, "PATH [ARGUMENT [...]]" },
4922 { config_parse_service_type, "SERVICETYPE" },
4923 { config_parse_service_restart, "SERVICERESTART" },
4924 #if HAVE_SYSV_COMPAT
4925 { config_parse_sysv_priority, "SYSVPRIORITY" },
4926 #endif
4927 { config_parse_kill_mode, "KILLMODE" },
4928 { config_parse_signal, "SIGNAL" },
4929 { config_parse_socket_listen, "SOCKET [...]" },
4930 { config_parse_socket_bind, "SOCKETBIND" },
4931 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
4932 { config_parse_sec, "SECONDS" },
4933 { config_parse_nsec, "NANOSECONDS" },
4934 { config_parse_namespace_path_strv, "PATH [...]" },
4935 { config_parse_bind_paths, "PATH[:PATH[:OPTIONS]] [...]" },
4936 { config_parse_unit_requires_mounts_for, "PATH [...]" },
4937 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
4938 { config_parse_unit_string_printf, "STRING" },
4939 { config_parse_trigger_unit, "UNIT" },
4940 { config_parse_timer, "TIMER" },
4941 { config_parse_path_spec, "PATH" },
4942 { config_parse_notify_access, "ACCESS" },
4943 { config_parse_ip_tos, "TOS" },
4944 { config_parse_unit_condition_path, "CONDITION" },
4945 { config_parse_unit_condition_string, "CONDITION" },
4946 { config_parse_unit_condition_null, "CONDITION" },
4947 { config_parse_unit_slice, "SLICE" },
4948 { config_parse_documentation, "URL" },
4949 { config_parse_service_timeout, "SECONDS" },
4950 { config_parse_emergency_action, "ACTION" },
4951 { config_parse_set_status, "STATUS" },
4952 { config_parse_service_sockets, "SOCKETS" },
4953 { config_parse_environ, "ENVIRON" },
4954 #if HAVE_SECCOMP
4955 { config_parse_syscall_filter, "SYSCALLS" },
4956 { config_parse_syscall_archs, "ARCHS" },
4957 { config_parse_syscall_errno, "ERRNO" },
4958 { config_parse_address_families, "FAMILIES" },
4959 { config_parse_restrict_namespaces, "NAMESPACES" },
4960 #endif
4961 { config_parse_cpu_shares, "SHARES" },
4962 { config_parse_cpu_weight, "WEIGHT" },
4963 { config_parse_memory_limit, "LIMIT" },
4964 { config_parse_device_allow, "DEVICE" },
4965 { config_parse_device_policy, "POLICY" },
4966 { config_parse_io_limit, "LIMIT" },
4967 { config_parse_io_weight, "WEIGHT" },
4968 { config_parse_io_device_weight, "DEVICEWEIGHT" },
4969 { config_parse_blockio_bandwidth, "BANDWIDTH" },
4970 { config_parse_blockio_weight, "WEIGHT" },
4971 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
4972 { config_parse_long, "LONG" },
4973 { config_parse_socket_service, "SERVICE" },
4974 #if HAVE_SELINUX
4975 { config_parse_exec_selinux_context, "LABEL" },
4976 #endif
4977 { config_parse_job_mode, "MODE" },
4978 { config_parse_job_mode_isolate, "BOOLEAN" },
4979 { config_parse_personality, "PERSONALITY" },
4980 };
4981
4982 const char *prev = NULL;
4983 const char *i;
4984
4985 assert(f);
4986
4987 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
4988 const char *rvalue = "OTHER", *lvalue;
4989 unsigned j;
4990 size_t prefix_len;
4991 const char *dot;
4992 const ConfigPerfItem *p;
4993
4994 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
4995
4996 dot = strchr(i, '.');
4997 lvalue = dot ? dot + 1 : i;
4998 prefix_len = dot-i;
4999
5000 if (dot)
5001 if (!prev || !strneq(prev, i, prefix_len+1)) {
5002 if (prev)
5003 fputc('\n', f);
5004
5005 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
5006 }
5007
5008 for (j = 0; j < ELEMENTSOF(table); j++)
5009 if (p->parse == table[j].callback) {
5010 rvalue = table[j].rvalue;
5011 break;
5012 }
5013
5014 fprintf(f, "%s=%s\n", lvalue, rvalue);
5015 prev = i;
5016 }
5017 }