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