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