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