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