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