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