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