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