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