]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/load-fragment.c
move _cleanup_ attribute in front of the type
[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
37 #include <systemd/sd-messages.h>
38
39 #include "unit.h"
40 #include "strv.h"
41 #include "conf-parser.h"
42 #include "load-fragment.h"
43 #include "log.h"
44 #include "ioprio.h"
45 #include "securebits.h"
46 #include "missing.h"
47 #include "unit-name.h"
48 #include "unit-printf.h"
49 #include "dbus-common.h"
50 #include "utf8.h"
51 #include "path-util.h"
52 #include "syscall-list.h"
53 #include "env-util.h"
54
55 #ifndef HAVE_SYSV_COMPAT
56 int config_parse_warn_compat(const char *unit,
57 const char *filename,
58 unsigned line,
59 const char *section,
60 const char *lvalue,
61 int ltype,
62 const char *rvalue,
63 void *data,
64 void *userdata) {
65
66 log_syntax(unit, LOG_DEBUG, filename, line, EINVAL,
67 "Support for option %s= has been disabled at compile time and is ignored",
68 lvalue);
69 return 0;
70 }
71 #endif
72
73 int config_parse_unit_deps(const char* unit,
74 const char *filename,
75 unsigned line,
76 const char *section,
77 const char *lvalue,
78 int ltype,
79 const char *rvalue,
80 void *data,
81 void *userdata) {
82
83 UnitDependency d = ltype;
84 Unit *u = userdata;
85 char *w;
86 size_t l;
87 char *state;
88
89 assert(filename);
90 assert(lvalue);
91 assert(rvalue);
92
93 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
94 _cleanup_free_ char *t = NULL, *k = NULL;
95 int r;
96
97 t = strndup(w, l);
98 if (!t)
99 return log_oom();
100
101 k = unit_name_printf(u, t);
102 if (!k)
103 return log_oom();
104
105 r = unit_add_dependency_by_name(u, d, k, NULL, true);
106 if (r < 0)
107 log_syntax(unit, LOG_ERR, filename, line, -r,
108 "Failed to add dependency on %s, ignoring: %s", k, strerror(-r));
109 }
110
111 return 0;
112 }
113
114 int config_parse_unit_string_printf(const char *unit,
115 const char *filename,
116 unsigned line,
117 const char *section,
118 const char *lvalue,
119 int ltype,
120 const char *rvalue,
121 void *data,
122 void *userdata) {
123
124 Unit *u = userdata;
125 _cleanup_free_ char *k = NULL;
126
127 assert(filename);
128 assert(lvalue);
129 assert(rvalue);
130 assert(u);
131
132 k = unit_full_printf(u, rvalue);
133 if (!k)
134 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
135 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
136
137 return config_parse_string(unit, filename, line, section, lvalue, ltype,
138 k ? k : rvalue, data, userdata);
139 }
140
141 int config_parse_unit_strv_printf(const char *unit,
142 const char *filename,
143 unsigned line,
144 const char *section,
145 const char *lvalue,
146 int ltype,
147 const char *rvalue,
148 void *data,
149 void *userdata) {
150
151 Unit *u = userdata;
152 _cleanup_free_ char *k = NULL;
153
154 assert(filename);
155 assert(lvalue);
156 assert(rvalue);
157 assert(u);
158
159 k = unit_full_printf(u, rvalue);
160 if (!k)
161 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
162 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
163
164 return config_parse_strv(unit, filename, line, section, lvalue, ltype,
165 k ? k : rvalue, data, userdata);
166 }
167
168 int config_parse_unit_path_printf(const char *unit,
169 const char *filename,
170 unsigned line,
171 const char *section,
172 const char *lvalue,
173 int ltype,
174 const char *rvalue,
175 void *data,
176 void *userdata) {
177
178 Unit *u = userdata;
179 _cleanup_free_ char *k = NULL;
180
181 assert(filename);
182 assert(lvalue);
183 assert(rvalue);
184 assert(u);
185
186 k = unit_full_printf(u, rvalue);
187 if (!k)
188 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
189 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
190
191 return config_parse_path(unit, filename, line, section, lvalue, ltype,
192 k ? k : rvalue, data, userdata);
193 }
194
195 int config_parse_socket_listen(const char *unit,
196 const char *filename,
197 unsigned line,
198 const char *section,
199 const char *lvalue,
200 int ltype,
201 const char *rvalue,
202 void *data,
203 void *userdata) {
204
205 SocketPort *p, *tail;
206 Socket *s;
207
208 assert(filename);
209 assert(lvalue);
210 assert(rvalue);
211 assert(data);
212
213 s = SOCKET(data);
214
215 if (isempty(rvalue)) {
216 /* An empty assignment removes all ports */
217 socket_free_ports(s);
218 return 0;
219 }
220
221 p = new0(SocketPort, 1);
222 if (!p)
223 return log_oom();
224
225 if (ltype != SOCKET_SOCKET) {
226
227 p->type = ltype;
228 p->path = unit_full_printf(UNIT(s), rvalue);
229 if (!p->path) {
230 p->path = strdup(rvalue);
231 if (!p->path) {
232 free(p);
233 return log_oom();
234 } else
235 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
236 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
237 }
238
239 path_kill_slashes(p->path);
240
241 } else if (streq(lvalue, "ListenNetlink")) {
242 _cleanup_free_ char *k = NULL;
243 int r;
244
245 p->type = SOCKET_SOCKET;
246 k = unit_full_printf(UNIT(s), rvalue);
247 if (!k)
248 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
249 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
250
251 r = socket_address_parse_netlink(&p->address, k ? k : rvalue);
252 if (r < 0) {
253 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
254 "Failed to parse address value, ignoring: %s", rvalue);
255 free(p);
256 return 0;
257 }
258
259 } else {
260 _cleanup_free_ char *k = NULL;
261 int r;
262
263 p->type = SOCKET_SOCKET;
264 k = unit_full_printf(UNIT(s), rvalue);
265 if (!k)
266 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
267 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
268
269 r = socket_address_parse(&p->address, k ? k : rvalue);
270 if (r < 0) {
271 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
272 "Failed to parse address value, ignoring: %s", rvalue);
273 free(p);
274 return 0;
275 }
276
277 if (streq(lvalue, "ListenStream"))
278 p->address.type = SOCK_STREAM;
279 else if (streq(lvalue, "ListenDatagram"))
280 p->address.type = SOCK_DGRAM;
281 else {
282 assert(streq(lvalue, "ListenSequentialPacket"));
283 p->address.type = SOCK_SEQPACKET;
284 }
285
286 if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
287 log_syntax(unit, LOG_ERR, filename, line, ENOTSUP,
288 "Address family not supported, ignoring: %s", rvalue);
289 free(p);
290 return 0;
291 }
292 }
293
294 p->fd = -1;
295
296 if (s->ports) {
297 LIST_FIND_TAIL(SocketPort, port, s->ports, tail);
298 LIST_INSERT_AFTER(SocketPort, port, s->ports, tail, p);
299 } else
300 LIST_PREPEND(SocketPort, port, s->ports, p);
301
302 return 0;
303 }
304
305 int config_parse_socket_bind(const char *unit,
306 const char *filename,
307 unsigned line,
308 const char *section,
309 const char *lvalue,
310 int ltype,
311 const char *rvalue,
312 void *data,
313 void *userdata) {
314
315 Socket *s;
316 SocketAddressBindIPv6Only b;
317
318 assert(filename);
319 assert(lvalue);
320 assert(rvalue);
321 assert(data);
322
323 s = SOCKET(data);
324
325 b = socket_address_bind_ipv6_only_from_string(rvalue);
326 if (b < 0) {
327 int r;
328
329 r = parse_boolean(rvalue);
330 if (r < 0) {
331 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
332 "Failed to parse bind IPv6 only value, ignoring: %s", rvalue);
333 return 0;
334 }
335
336 s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
337 } else
338 s->bind_ipv6_only = b;
339
340 return 0;
341 }
342
343 int config_parse_exec_nice(const char *unit,
344 const char *filename,
345 unsigned line,
346 const char *section,
347 const char *lvalue,
348 int ltype,
349 const char *rvalue,
350 void *data,
351 void *userdata) {
352
353 ExecContext *c = data;
354 int priority, r;
355
356 assert(filename);
357 assert(lvalue);
358 assert(rvalue);
359 assert(data);
360
361 r = safe_atoi(rvalue, &priority);
362 if (r < 0) {
363 log_syntax(unit, LOG_ERR, filename, line, -r,
364 "Failed to parse nice priority, ignoring: %s. ", rvalue);
365 return 0;
366 }
367
368 if (priority < PRIO_MIN || priority >= PRIO_MAX) {
369 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
370 "Nice priority out of range, ignoring: %s", rvalue);
371 return 0;
372 }
373
374 c->nice = priority;
375 c->nice_set = true;
376
377 return 0;
378 }
379
380 int config_parse_exec_oom_score_adjust(const char* unit,
381 const char *filename,
382 unsigned line,
383 const char *section,
384 const char *lvalue,
385 int ltype,
386 const char *rvalue,
387 void *data,
388 void *userdata) {
389
390 ExecContext *c = data;
391 int oa, r;
392
393 assert(filename);
394 assert(lvalue);
395 assert(rvalue);
396 assert(data);
397
398 r = safe_atoi(rvalue, &oa);
399 if (r < 0) {
400 log_syntax(unit, LOG_ERR, filename, line, -r,
401 "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
402 return 0;
403 }
404
405 if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
406 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
407 "OOM score adjust value out of range, ignoring: %s", rvalue);
408 return 0;
409 }
410
411 c->oom_score_adjust = oa;
412 c->oom_score_adjust_set = true;
413
414 return 0;
415 }
416
417 int config_parse_exec(const char *unit,
418 const char *filename,
419 unsigned line,
420 const char *section,
421 const char *lvalue,
422 int ltype,
423 const char *rvalue,
424 void *data,
425 void *userdata) {
426
427 ExecCommand **e = data, *nce;
428 char *path, **n;
429 unsigned k;
430 int r;
431
432 assert(filename);
433 assert(lvalue);
434 assert(rvalue);
435 assert(e);
436
437 e += ltype;
438
439 if (isempty(rvalue)) {
440 /* An empty assignment resets the list */
441 exec_command_free_list(*e);
442 *e = NULL;
443 return 0;
444 }
445
446 /* We accept an absolute path as first argument, or
447 * alternatively an absolute prefixed with @ to allow
448 * overriding of argv[0]. */
449 for (;;) {
450 int i;
451 char *w;
452 size_t l;
453 char *state;
454 bool honour_argv0 = false, ignore = false;
455
456 path = NULL;
457 nce = NULL;
458 n = NULL;
459
460 rvalue += strspn(rvalue, WHITESPACE);
461
462 if (rvalue[0] == 0)
463 break;
464
465 for (i = 0; i < 2; i++) {
466 if (rvalue[0] == '-' && !ignore) {
467 ignore = true;
468 rvalue ++;
469 }
470
471 if (rvalue[0] == '@' && !honour_argv0) {
472 honour_argv0 = true;
473 rvalue ++;
474 }
475 }
476
477 if (*rvalue != '/') {
478 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
479 "Executable path is not absolute, ignoring: %s", rvalue);
480 return 0;
481 }
482
483 k = 0;
484 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
485 if (strneq(w, ";", MAX(l, 1U)))
486 break;
487
488 k++;
489 }
490
491 n = new(char*, k + !honour_argv0);
492 if (!n)
493 return log_oom();
494
495 k = 0;
496 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
497 if (strneq(w, ";", MAX(l, 1U)))
498 break;
499 else if (strneq(w, "\\;", MAX(l, 1U)))
500 w ++;
501
502 if (honour_argv0 && w == rvalue) {
503 assert(!path);
504
505 path = strndup(w, l);
506 if (!path) {
507 r = log_oom();
508 goto fail;
509 }
510
511 if (!utf8_is_valid(path)) {
512 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
513 "Path is not UTF-8 clean, ignoring assignment: %s",
514 rvalue);
515 r = 0;
516 goto fail;
517 }
518
519 } else {
520 char *c;
521
522 c = n[k++] = cunescape_length(w, l);
523 if (!c) {
524 r = log_oom();
525 goto fail;
526 }
527
528 if (!utf8_is_valid(c)) {
529 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
530 "Path is not UTF-8 clean, ignoring assignment: %s",
531 rvalue);
532 r = 0;
533 goto fail;
534 }
535 }
536 }
537
538 n[k] = NULL;
539
540 if (!n[0]) {
541 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
542 "Invalid command line, ignoring: %s", rvalue);
543 r = 0;
544 goto fail;
545 }
546
547 if (!path) {
548 path = strdup(n[0]);
549 if (!path) {
550 r = log_oom();
551 goto fail;
552 }
553 }
554
555 assert(path_is_absolute(path));
556
557 nce = new0(ExecCommand, 1);
558 if (!nce) {
559 r = log_oom();
560 goto fail;
561 }
562
563 nce->argv = n;
564 nce->path = path;
565 nce->ignore = ignore;
566
567 path_kill_slashes(nce->path);
568
569 exec_command_append_list(e, nce);
570
571 rvalue = state;
572 }
573
574 return 0;
575
576 fail:
577 n[k] = NULL;
578 strv_free(n);
579 free(path);
580 free(nce);
581
582 return r;
583 }
584
585 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
586 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
587
588 int config_parse_socket_bindtodevice(const char* unit,
589 const char *filename,
590 unsigned line,
591 const char *section,
592 const char *lvalue,
593 int ltype,
594 const char *rvalue,
595 void *data,
596 void *userdata) {
597
598 Socket *s = data;
599 char *n;
600
601 assert(filename);
602 assert(lvalue);
603 assert(rvalue);
604 assert(data);
605
606 if (rvalue[0] && !streq(rvalue, "*")) {
607 n = strdup(rvalue);
608 if (!n)
609 return log_oom();
610 } else
611 n = NULL;
612
613 free(s->bind_to_device);
614 s->bind_to_device = n;
615
616 return 0;
617 }
618
619 DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
620 DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
621
622 int config_parse_exec_io_class(const char *unit,
623 const char *filename,
624 unsigned line,
625 const char *section,
626 const char *lvalue,
627 int ltype,
628 const char *rvalue,
629 void *data,
630 void *userdata) {
631
632 ExecContext *c = data;
633 int x;
634
635 assert(filename);
636 assert(lvalue);
637 assert(rvalue);
638 assert(data);
639
640 x = ioprio_class_from_string(rvalue);
641 if (x < 0) {
642 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
643 "Failed to parse IO scheduling class, ignoring: %s", rvalue);
644 return 0;
645 }
646
647 c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
648 c->ioprio_set = true;
649
650 return 0;
651 }
652
653 int config_parse_exec_io_priority(const char *unit,
654 const char *filename,
655 unsigned line,
656 const char *section,
657 const char *lvalue,
658 int ltype,
659 const char *rvalue,
660 void *data,
661 void *userdata) {
662
663 ExecContext *c = data;
664 int i, r;
665
666 assert(filename);
667 assert(lvalue);
668 assert(rvalue);
669 assert(data);
670
671 r = safe_atoi(rvalue, &i);
672 if (r < 0 || i < 0 || i >= IOPRIO_BE_NR) {
673 log_syntax(unit, LOG_ERR, filename, line, -r,
674 "Failed to parse IO priority, ignoring: %s", rvalue);
675 return 0;
676 }
677
678 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
679 c->ioprio_set = true;
680
681 return 0;
682 }
683
684 int config_parse_exec_cpu_sched_policy(const char *unit,
685 const char *filename,
686 unsigned line,
687 const char *section,
688 const char *lvalue,
689 int ltype,
690 const char *rvalue,
691 void *data,
692 void *userdata) {
693
694
695 ExecContext *c = data;
696 int x;
697
698 assert(filename);
699 assert(lvalue);
700 assert(rvalue);
701 assert(data);
702
703 x = sched_policy_from_string(rvalue);
704 if (x < 0) {
705 log_syntax(unit, LOG_ERR, filename, line, -x,
706 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
707 return 0;
708 }
709
710 c->cpu_sched_policy = x;
711 /* Moving to or from real-time policy? We need to adjust the priority */
712 c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x));
713 c->cpu_sched_set = true;
714
715 return 0;
716 }
717
718 int config_parse_exec_cpu_sched_prio(const char *unit,
719 const char *filename,
720 unsigned line,
721 const char *section,
722 const char *lvalue,
723 int ltype,
724 const char *rvalue,
725 void *data,
726 void *userdata) {
727
728 ExecContext *c = data;
729 int i, min, max, r;
730
731 assert(filename);
732 assert(lvalue);
733 assert(rvalue);
734 assert(data);
735
736 r = safe_atoi(rvalue, &i);
737 if (r < 0) {
738 log_syntax(unit, LOG_ERR, filename, line, -r,
739 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
740 return 0;
741 }
742
743 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
744 min = sched_get_priority_min(c->cpu_sched_policy);
745 max = sched_get_priority_max(c->cpu_sched_policy);
746
747 if (i < min || i > max) {
748 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
749 "CPU scheduling priority is out of range, ignoring: %s", rvalue);
750 return 0;
751 }
752
753 c->cpu_sched_priority = i;
754 c->cpu_sched_set = true;
755
756 return 0;
757 }
758
759 int config_parse_exec_cpu_affinity(const char *unit,
760 const char *filename,
761 unsigned line,
762 const char *section,
763 const char *lvalue,
764 int ltype,
765 const char *rvalue,
766 void *data,
767 void *userdata) {
768
769 ExecContext *c = data;
770 char *w;
771 size_t l;
772 char *state;
773
774 assert(filename);
775 assert(lvalue);
776 assert(rvalue);
777 assert(data);
778
779 if (isempty(rvalue)) {
780 /* An empty assignment resets the CPU list */
781 if (c->cpuset)
782 CPU_FREE(c->cpuset);
783 c->cpuset = NULL;
784 return 0;
785 }
786
787 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
788 _cleanup_free_ char *t = NULL;
789 int r;
790 unsigned cpu;
791
792 t = strndup(w, l);
793 if (!t)
794 return log_oom();
795
796 r = safe_atou(t, &cpu);
797
798 if (!c->cpuset) {
799 c->cpuset = cpu_set_malloc(&c->cpuset_ncpus);
800 if (!c->cpuset)
801 return log_oom();
802 }
803
804 if (r < 0 || cpu >= c->cpuset_ncpus) {
805 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
806 "Failed to parse CPU affinity '%s', ignoring: %s", t, rvalue);
807 return 0;
808 }
809
810 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
811 }
812
813 return 0;
814 }
815
816 int config_parse_exec_capabilities(const char *unit,
817 const char *filename,
818 unsigned line,
819 const char *section,
820 const char *lvalue,
821 int ltype,
822 const char *rvalue,
823 void *data,
824 void *userdata) {
825
826 ExecContext *c = data;
827 cap_t cap;
828
829 assert(filename);
830 assert(lvalue);
831 assert(rvalue);
832 assert(data);
833
834 cap = cap_from_text(rvalue);
835 if (!cap) {
836 log_syntax(unit, LOG_ERR, filename, line, errno,
837 "Failed to parse capabilities, ignoring: %s", rvalue);
838 return 0;
839 }
840
841 if (c->capabilities)
842 cap_free(c->capabilities);
843 c->capabilities = cap;
844
845 return 0;
846 }
847
848 int config_parse_exec_secure_bits(const char *unit,
849 const char *filename,
850 unsigned line,
851 const char *section,
852 const char *lvalue,
853 int ltype,
854 const char *rvalue,
855 void *data,
856 void *userdata) {
857
858 ExecContext *c = data;
859 char *w;
860 size_t l;
861 char *state;
862
863 assert(filename);
864 assert(lvalue);
865 assert(rvalue);
866 assert(data);
867
868 if (isempty(rvalue)) {
869 /* An empty assignment resets the field */
870 c->secure_bits = 0;
871 return 0;
872 }
873
874 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
875 if (first_word(w, "keep-caps"))
876 c->secure_bits |= 1<<SECURE_KEEP_CAPS;
877 else if (first_word(w, "keep-caps-locked"))
878 c->secure_bits |= 1<<SECURE_KEEP_CAPS_LOCKED;
879 else if (first_word(w, "no-setuid-fixup"))
880 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP;
881 else if (first_word(w, "no-setuid-fixup-locked"))
882 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP_LOCKED;
883 else if (first_word(w, "noroot"))
884 c->secure_bits |= 1<<SECURE_NOROOT;
885 else if (first_word(w, "noroot-locked"))
886 c->secure_bits |= 1<<SECURE_NOROOT_LOCKED;
887 else {
888 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
889 "Failed to parse secure bits, ignoring: %s", rvalue);
890 return 0;
891 }
892 }
893
894 return 0;
895 }
896
897 int config_parse_bounding_set(const char *unit,
898 const char *filename,
899 unsigned line,
900 const char *section,
901 const char *lvalue,
902 int ltype,
903 const char *rvalue,
904 void *data,
905 void *userdata) {
906
907 uint64_t *capability_bounding_set_drop = data;
908 char *w;
909 size_t l;
910 char *state;
911 bool invert = false;
912 uint64_t sum = 0;
913
914 assert(filename);
915 assert(lvalue);
916 assert(rvalue);
917 assert(data);
918
919 if (rvalue[0] == '~') {
920 invert = true;
921 rvalue++;
922 }
923
924 /* Note that we store this inverted internally, since the
925 * kernel wants it like this. But we actually expose it
926 * non-inverted everywhere to have a fully normalized
927 * interface. */
928
929 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
930 _cleanup_free_ char *t = NULL;
931 int r;
932 cap_value_t cap;
933
934 t = strndup(w, l);
935 if (!t)
936 return log_oom();
937
938 r = cap_from_name(t, &cap);
939 if (r < 0) {
940 log_syntax(unit, LOG_ERR, filename, line, errno,
941 "Failed to parse capability in bounding set, ignoring: %s", t);
942 continue;
943 }
944
945 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
946 }
947
948 if (invert)
949 *capability_bounding_set_drop |= sum;
950 else
951 *capability_bounding_set_drop |= ~sum;
952
953 return 0;
954 }
955
956 int config_parse_limit(const char *unit,
957 const char *filename,
958 unsigned line,
959 const char *section,
960 const char *lvalue,
961 int ltype,
962 const char *rvalue,
963 void *data,
964 void *userdata) {
965
966 struct rlimit **rl = data;
967 unsigned long long u;
968
969 assert(filename);
970 assert(lvalue);
971 assert(rvalue);
972 assert(data);
973
974 rl += ltype;
975
976 if (streq(rvalue, "infinity"))
977 u = (unsigned long long) RLIM_INFINITY;
978 else {
979 int r;
980
981 r = safe_atollu(rvalue, &u);
982 if (r < 0) {
983 log_syntax(unit, LOG_ERR, filename, line, -r,
984 "Failed to parse resource value, ignoring: %s", rvalue);
985 return 0;
986 }
987 }
988
989 if (!*rl) {
990 *rl = new(struct rlimit, 1);
991 if (!*rl)
992 return log_oom();
993 }
994
995 (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
996 return 0;
997 }
998
999 int config_parse_unit_cgroup(const char *unit,
1000 const char *filename,
1001 unsigned line,
1002 const char *section,
1003 const char *lvalue,
1004 int ltype,
1005 const char *rvalue,
1006 void *data,
1007 void *userdata) {
1008
1009 Unit *u = userdata;
1010 char *w;
1011 size_t l;
1012 char *state;
1013
1014 if (isempty(rvalue)) {
1015 /* An empty assignment resets the list */
1016 cgroup_bonding_free_list(u->cgroup_bondings, false);
1017 u->cgroup_bondings = NULL;
1018 return 0;
1019 }
1020
1021 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1022 _cleanup_free_ char *t = NULL, *k = NULL, *ku = NULL;
1023 int r;
1024
1025 t = strndup(w, l);
1026 if (!t)
1027 return log_oom();
1028
1029 k = unit_full_printf(u, t);
1030 if (!k)
1031 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1032 "Failed to resolve unit specifiers on %s. Ignoring.",
1033 t);
1034
1035 ku = cunescape(k ? k : t);
1036 if (!ku)
1037 return log_oom();
1038
1039 r = unit_add_cgroup_from_text(u, ku, true, NULL);
1040 if (r < 0) {
1041 log_syntax(unit, LOG_ERR, filename, line, -r,
1042 "Failed to parse cgroup value %s, ignoring: %s",
1043 k, rvalue);
1044 return 0;
1045 }
1046 }
1047
1048 return 0;
1049 }
1050
1051 #ifdef HAVE_SYSV_COMPAT
1052 int config_parse_sysv_priority(const char *unit,
1053 const char *filename,
1054 unsigned line,
1055 const char *section,
1056 const char *lvalue,
1057 int ltype,
1058 const char *rvalue,
1059 void *data,
1060 void *userdata) {
1061
1062 int *priority = data;
1063 int i, r;
1064
1065 assert(filename);
1066 assert(lvalue);
1067 assert(rvalue);
1068 assert(data);
1069
1070 r = safe_atoi(rvalue, &i);
1071 if (r < 0 || i < 0) {
1072 log_syntax(unit, LOG_ERR, filename, line, -r,
1073 "Failed to parse SysV start priority, ignoring: %s", rvalue);
1074 return 0;
1075 }
1076
1077 *priority = (int) i;
1078 return 0;
1079 }
1080 #endif
1081
1082 int config_parse_fsck_passno(const char *unit,
1083 const char *filename,
1084 unsigned line,
1085 const char *section,
1086 const char *lvalue,
1087 int ltype,
1088 const char *rvalue,
1089 void *data,
1090 void *userdata) {
1091
1092 int *passno = data;
1093 int i, r;
1094
1095 assert(filename);
1096 assert(lvalue);
1097 assert(rvalue);
1098 assert(data);
1099
1100 r = safe_atoi(rvalue, &i);
1101 if (r || i < 0) {
1102 log_syntax(unit, LOG_ERR, filename, line, -r,
1103 "Failed to parse fsck pass number, ignoring: %s", rvalue);
1104 return 0;
1105 }
1106
1107 *passno = (int) i;
1108 return 0;
1109 }
1110
1111 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
1112
1113 int config_parse_kill_signal(const char *unit,
1114 const char *filename,
1115 unsigned line,
1116 const char *section,
1117 const char *lvalue,
1118 int ltype,
1119 const char *rvalue,
1120 void *data,
1121 void *userdata) {
1122
1123 int *sig = data;
1124 int r;
1125
1126 assert(filename);
1127 assert(lvalue);
1128 assert(rvalue);
1129 assert(sig);
1130
1131 r = signal_from_string_try_harder(rvalue);
1132 if (r <= 0) {
1133 log_syntax(unit, LOG_ERR, filename, line, -r,
1134 "Failed to parse kill signal, ignoring: %s", rvalue);
1135 return 0;
1136 }
1137
1138 *sig = r;
1139 return 0;
1140 }
1141
1142 int config_parse_exec_mount_flags(const char *unit,
1143 const char *filename,
1144 unsigned line,
1145 const char *section,
1146 const char *lvalue,
1147 int ltype,
1148 const char *rvalue,
1149 void *data,
1150 void *userdata) {
1151
1152 ExecContext *c = data;
1153 char *w;
1154 size_t l;
1155 char *state;
1156 unsigned long flags = 0;
1157
1158 assert(filename);
1159 assert(lvalue);
1160 assert(rvalue);
1161 assert(data);
1162
1163 FOREACH_WORD_SEPARATOR(w, l, rvalue, ", ", state) {
1164 _cleanup_free_ char *t;
1165
1166 t = strndup(w, l);
1167 if (!t)
1168 return log_oom();
1169
1170 if (streq(t, "shared"))
1171 flags |= MS_SHARED;
1172 else if (streq(t, "slave"))
1173 flags |= MS_SLAVE;
1174 else if (streq(w, "private"))
1175 flags |= MS_PRIVATE;
1176 else {
1177 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1178 "Failed to parse mount flag %s, ignoring: %s",
1179 t, rvalue);
1180 return 0;
1181 }
1182 }
1183
1184 c->mount_flags = flags;
1185 return 0;
1186 }
1187
1188 int config_parse_timer(const char *unit,
1189 const char *filename,
1190 unsigned line,
1191 const char *section,
1192 const char *lvalue,
1193 int ltype,
1194 const char *rvalue,
1195 void *data,
1196 void *userdata) {
1197
1198 Timer *t = data;
1199 usec_t u = 0;
1200 TimerValue *v;
1201 TimerBase b;
1202 CalendarSpec *c = NULL;
1203 clockid_t id;
1204
1205 assert(filename);
1206 assert(lvalue);
1207 assert(rvalue);
1208 assert(data);
1209
1210 if (isempty(rvalue)) {
1211 /* Empty assignment resets list */
1212 timer_free_values(t);
1213 return 0;
1214 }
1215
1216 b = timer_base_from_string(lvalue);
1217 if (b < 0) {
1218 log_syntax(unit, LOG_ERR, filename, line, -b,
1219 "Failed to parse timer base, ignoring: %s", lvalue);
1220 return 0;
1221 }
1222
1223 if (b == TIMER_CALENDAR) {
1224 if (calendar_spec_from_string(rvalue, &c) < 0) {
1225 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1226 "Failed to parse calendar specification, ignoring: %s",
1227 rvalue);
1228 return 0;
1229 }
1230
1231 id = CLOCK_REALTIME;
1232 } else {
1233 if (parse_sec(rvalue, &u) < 0) {
1234 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1235 "Failed to parse timer value, ignoring: %s",
1236 rvalue);
1237 return 0;
1238 }
1239
1240 id = CLOCK_MONOTONIC;
1241 }
1242
1243 v = new0(TimerValue, 1);
1244 if (!v)
1245 return log_oom();
1246
1247 v->base = b;
1248 v->clock_id = id;
1249 v->value = u;
1250 v->calendar_spec = c;
1251
1252 LIST_PREPEND(TimerValue, value, t->values, v);
1253
1254 return 0;
1255 }
1256
1257 int config_parse_timer_unit(const char *unit,
1258 const char *filename,
1259 unsigned line,
1260 const char *section,
1261 const char *lvalue,
1262 int ltype,
1263 const char *rvalue,
1264 void *data,
1265 void *userdata) {
1266
1267 Timer *t = data;
1268 int r;
1269 DBusError error;
1270 Unit *u;
1271 _cleanup_free_ char *p = NULL;
1272
1273 assert(filename);
1274 assert(lvalue);
1275 assert(rvalue);
1276 assert(data);
1277
1278 dbus_error_init(&error);
1279
1280 p = unit_name_printf(UNIT(t), rvalue);
1281 if (!p)
1282 return log_oom();
1283
1284 if (endswith(p, ".timer")) {
1285 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1286 "Unit cannot be of type timer, ignoring: %s", rvalue);
1287 return 0;
1288 }
1289
1290 r = manager_load_unit(UNIT(t)->manager, p, NULL, NULL, &u);
1291 if (r < 0) {
1292 log_syntax(unit, LOG_ERR, filename, line, -r,
1293 "Failed to load unit %s, ignoring: %s",
1294 rvalue, bus_error(&error, r));
1295 dbus_error_free(&error);
1296 return 0;
1297 }
1298
1299 unit_ref_set(&t->unit, u);
1300
1301 return 0;
1302 }
1303
1304 int config_parse_path_spec(const char *unit,
1305 const char *filename,
1306 unsigned line,
1307 const char *section,
1308 const char *lvalue,
1309 int ltype,
1310 const char *rvalue,
1311 void *data,
1312 void *userdata) {
1313
1314 Path *p = data;
1315 PathSpec *s;
1316 PathType b;
1317 _cleanup_free_ char *k = NULL;
1318
1319 assert(filename);
1320 assert(lvalue);
1321 assert(rvalue);
1322 assert(data);
1323
1324 if (isempty(rvalue)) {
1325 /* Empty assignment clears list */
1326 path_free_specs(p);
1327 return 0;
1328 }
1329
1330 b = path_type_from_string(lvalue);
1331 if (b < 0) {
1332 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1333 "Failed to parse path type, ignoring: %s", lvalue);
1334 return 0;
1335 }
1336
1337 k = unit_full_printf(UNIT(p), rvalue);
1338 if (!k) {
1339 k = strdup(rvalue);
1340 if (!k)
1341 return log_oom();
1342 else
1343 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1344 "Failed to resolve unit specifiers on %s. Ignoring.",
1345 rvalue);
1346 }
1347
1348 if (!path_is_absolute(k)) {
1349 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1350 "Path is not absolute, ignoring: %s", k);
1351 return 0;
1352 }
1353
1354 s = new0(PathSpec, 1);
1355 if (!s)
1356 return log_oom();
1357
1358 s->path = path_kill_slashes(k);
1359 k = NULL;
1360 s->type = b;
1361 s->inotify_fd = -1;
1362
1363 LIST_PREPEND(PathSpec, spec, p->specs, s);
1364
1365 return 0;
1366 }
1367
1368 int config_parse_path_unit(const char *unit,
1369 const char *filename,
1370 unsigned line,
1371 const char *section,
1372 const char *lvalue,
1373 int ltype,
1374 const char *rvalue,
1375 void *data,
1376 void *userdata) {
1377
1378 Path *t = data;
1379 int r;
1380 DBusError error;
1381 Unit *u;
1382 _cleanup_free_ char *p = NULL;
1383
1384 assert(filename);
1385 assert(lvalue);
1386 assert(rvalue);
1387 assert(data);
1388
1389 dbus_error_init(&error);
1390
1391 p = unit_name_printf(UNIT(t), rvalue);
1392 if (!p)
1393 return log_oom();
1394
1395 if (endswith(p, ".path")) {
1396 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1397 "Unit cannot be of type path, ignoring: %s", p);
1398 return 0;
1399 }
1400
1401 r = manager_load_unit(UNIT(t)->manager, p, NULL, &error, &u);
1402 if (r < 0) {
1403 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1404 "Failed to load unit %s, ignoring: %s",
1405 p, bus_error(&error, r));
1406 dbus_error_free(&error);
1407 return 0;
1408 }
1409
1410 unit_ref_set(&t->unit, u);
1411
1412 return 0;
1413 }
1414
1415 int config_parse_socket_service(const char *unit,
1416 const char *filename,
1417 unsigned line,
1418 const char *section,
1419 const char *lvalue,
1420 int ltype,
1421 const char *rvalue,
1422 void *data,
1423 void *userdata) {
1424
1425 Socket *s = data;
1426 int r;
1427 DBusError error;
1428 Unit *x;
1429 _cleanup_free_ char *p = NULL;
1430
1431 assert(filename);
1432 assert(lvalue);
1433 assert(rvalue);
1434 assert(data);
1435
1436 dbus_error_init(&error);
1437
1438 p = unit_name_printf(UNIT(s), rvalue);
1439 if (!p)
1440 return log_oom();
1441
1442 if (!endswith(p, ".service")) {
1443 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1444 "Unit must be of type service, ignoring: %s", rvalue);
1445 return 0;
1446 }
1447
1448 r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
1449 if (r < 0) {
1450 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1451 "Failed to load unit %s, ignoring: %s",
1452 rvalue, bus_error(&error, r));
1453 dbus_error_free(&error);
1454 return 0;
1455 }
1456
1457 unit_ref_set(&s->service, x);
1458
1459 return 0;
1460 }
1461
1462 int config_parse_service_sockets(const char *unit,
1463 const char *filename,
1464 unsigned line,
1465 const char *section,
1466 const char *lvalue,
1467 int ltype,
1468 const char *rvalue,
1469 void *data,
1470 void *userdata) {
1471
1472 Service *s = data;
1473 int r;
1474 char *state, *w;
1475 size_t l;
1476
1477 assert(filename);
1478 assert(lvalue);
1479 assert(rvalue);
1480 assert(data);
1481
1482 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1483 _cleanup_free_ char *t = NULL, *k = NULL;
1484
1485 t = strndup(w, l);
1486 if (!t)
1487 return log_oom();
1488
1489 k = unit_name_printf(UNIT(s), t);
1490 if (!k)
1491 return log_oom();
1492
1493 if (!endswith(k, ".socket")) {
1494 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1495 "Unit must be of type socket, ignoring: %s", k);
1496 continue;
1497 }
1498
1499 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true);
1500 if (r < 0)
1501 log_syntax(unit, LOG_ERR, filename, line, -r,
1502 "Failed to add dependency on %s, ignoring: %s",
1503 k, strerror(-r));
1504
1505 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true);
1506 if (r < 0)
1507 return r;
1508 }
1509
1510 return 0;
1511 }
1512
1513 int config_parse_service_timeout(const char *unit,
1514 const char *filename,
1515 unsigned line,
1516 const char *section,
1517 const char *lvalue,
1518 int ltype,
1519 const char *rvalue,
1520 void *data,
1521 void *userdata) {
1522
1523 Service *s = userdata;
1524 int r;
1525
1526 assert(filename);
1527 assert(lvalue);
1528 assert(rvalue);
1529 assert(s);
1530
1531 r = config_parse_sec(unit, filename, line, section, lvalue, ltype,
1532 rvalue, data, userdata);
1533 if (r < 0)
1534 return r;
1535
1536 if (streq(lvalue, "TimeoutSec")) {
1537 s->start_timeout_defined = true;
1538 s->timeout_stop_usec = s->timeout_start_usec;
1539 } else if (streq(lvalue, "TimeoutStartSec"))
1540 s->start_timeout_defined = true;
1541
1542 return 0;
1543 }
1544
1545 int config_parse_unit_env_file(const char *unit,
1546 const char *filename,
1547 unsigned line,
1548 const char *section,
1549 const char *lvalue,
1550 int ltype,
1551 const char *rvalue,
1552 void *data,
1553 void *userdata) {
1554
1555 char ***env = data;
1556 Unit *u = userdata;
1557 _cleanup_free_ char *s = NULL;
1558 int r;
1559
1560 assert(filename);
1561 assert(lvalue);
1562 assert(rvalue);
1563 assert(data);
1564
1565 if (isempty(rvalue)) {
1566 /* Empty assignment frees the list */
1567 strv_free(*env);
1568 *env = NULL;
1569 return 0;
1570 }
1571
1572 s = unit_full_printf(u, rvalue);
1573 if (!s)
1574 return log_oom();
1575
1576 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1577 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1578 "Path '%s' is not absolute, ignoring.", s);
1579 return 0;
1580 }
1581
1582 r = strv_extend(env, s);
1583 if (r < 0)
1584 return log_oom();
1585
1586 return 0;
1587 }
1588
1589 int config_parse_environ(const char *unit,
1590 const char *filename,
1591 unsigned line,
1592 const char *section,
1593 const char *lvalue,
1594 int ltype,
1595 const char *rvalue,
1596 void *data,
1597 void *userdata) {
1598
1599 Unit *u = userdata;
1600 char*** env = data, *w, *state;
1601 size_t l;
1602 _cleanup_free_ char *k = NULL;
1603
1604 assert(filename);
1605 assert(lvalue);
1606 assert(rvalue);
1607 assert(u);
1608
1609 if (isempty(rvalue)) {
1610 /* Empty assignment resets the list */
1611 strv_free(*env);
1612 *env = NULL;
1613 return 0;
1614 }
1615
1616 k = unit_full_printf(u, rvalue);
1617 if (!k)
1618 return log_oom();
1619
1620 FOREACH_WORD_QUOTED(w, l, k, state) {
1621 _cleanup_free_ char *n;
1622 char **x;
1623
1624 n = cunescape_length(w, l);
1625 if (!n)
1626 return log_oom();
1627
1628 if (!env_assignment_is_valid(n)) {
1629 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1630 "Invalid environment assignment, ignoring: %s", rvalue);
1631 continue;
1632 }
1633
1634 x = strv_env_set(*env, n);
1635 if (!x)
1636 return log_oom();
1637
1638 strv_free(*env);
1639 *env = x;
1640 }
1641
1642 return 0;
1643 }
1644
1645 int config_parse_ip_tos(const char *unit,
1646 const char *filename,
1647 unsigned line,
1648 const char *section,
1649 const char *lvalue,
1650 int ltype,
1651 const char *rvalue,
1652 void *data,
1653 void *userdata) {
1654
1655 int *ip_tos = data, x;
1656
1657 assert(filename);
1658 assert(lvalue);
1659 assert(rvalue);
1660 assert(data);
1661
1662 x = ip_tos_from_string(rvalue);
1663 if (x < 0) {
1664 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1665 "Failed to parse IP TOS value, ignoring: %s", rvalue);
1666 return 0;
1667 }
1668
1669 *ip_tos = x;
1670 return 0;
1671 }
1672
1673 int config_parse_unit_condition_path(const char *unit,
1674 const char *filename,
1675 unsigned line,
1676 const char *section,
1677 const char *lvalue,
1678 int ltype,
1679 const char *rvalue,
1680 void *data,
1681 void *userdata) {
1682
1683 ConditionType cond = ltype;
1684 Unit *u = data;
1685 bool trigger, negate;
1686 Condition *c;
1687 _cleanup_free_ char *p = NULL;
1688
1689 assert(filename);
1690 assert(lvalue);
1691 assert(rvalue);
1692 assert(data);
1693
1694 if (isempty(rvalue)) {
1695 /* Empty assignment resets the list */
1696 condition_free_list(u->conditions);
1697 u->conditions = NULL;
1698 return 0;
1699 }
1700
1701 trigger = rvalue[0] == '|';
1702 if (trigger)
1703 rvalue++;
1704
1705 negate = rvalue[0] == '!';
1706 if (negate)
1707 rvalue++;
1708
1709 p = unit_full_printf(u, rvalue);
1710 if (!p)
1711 return log_oom();
1712
1713 if (!path_is_absolute(p)) {
1714 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1715 "Path in condition not absolute, ignoring: %s", p);
1716 return 0;
1717 }
1718
1719 c = condition_new(cond, p, trigger, negate);
1720 if (!c)
1721 return log_oom();
1722
1723 LIST_PREPEND(Condition, conditions, u->conditions, c);
1724 return 0;
1725 }
1726
1727 int config_parse_unit_condition_string(const char *unit,
1728 const char *filename,
1729 unsigned line,
1730 const char *section,
1731 const char *lvalue,
1732 int ltype,
1733 const char *rvalue,
1734 void *data,
1735 void *userdata) {
1736
1737 ConditionType cond = ltype;
1738 Unit *u = data;
1739 bool trigger, negate;
1740 Condition *c;
1741 _cleanup_free_ char *s = NULL;
1742
1743 assert(filename);
1744 assert(lvalue);
1745 assert(rvalue);
1746 assert(data);
1747
1748 if (isempty(rvalue)) {
1749 /* Empty assignment resets the list */
1750 condition_free_list(u->conditions);
1751 u->conditions = NULL;
1752 return 0;
1753 }
1754
1755 trigger = rvalue[0] == '|';
1756 if (trigger)
1757 rvalue++;
1758
1759 negate = rvalue[0] == '!';
1760 if (negate)
1761 rvalue++;
1762
1763 s = unit_full_printf(u, rvalue);
1764 if (!s)
1765 return log_oom();
1766
1767 c = condition_new(cond, s, trigger, negate);
1768 if (!c)
1769 return log_oom();
1770
1771 LIST_PREPEND(Condition, conditions, u->conditions, c);
1772 return 0;
1773 }
1774
1775 int config_parse_unit_condition_null(const char *unit,
1776 const char *filename,
1777 unsigned line,
1778 const char *section,
1779 const char *lvalue,
1780 int ltype,
1781 const char *rvalue,
1782 void *data,
1783 void *userdata) {
1784
1785 Unit *u = data;
1786 Condition *c;
1787 bool trigger, negate;
1788 int b;
1789
1790 assert(filename);
1791 assert(lvalue);
1792 assert(rvalue);
1793 assert(data);
1794
1795 if (isempty(rvalue)) {
1796 /* Empty assignment resets the list */
1797 condition_free_list(u->conditions);
1798 u->conditions = NULL;
1799 return 0;
1800 }
1801
1802 trigger = rvalue[0] == '|';
1803 if (trigger)
1804 rvalue++;
1805
1806 negate = rvalue[0] == '!';
1807 if (negate)
1808 rvalue++;
1809
1810 b = parse_boolean(rvalue);
1811 if (b < 0) {
1812 log_syntax(unit, LOG_ERR, filename, line, -b,
1813 "Failed to parse boolean value in condition, ignoring: %s",
1814 rvalue);
1815 return 0;
1816 }
1817
1818 if (!b)
1819 negate = !negate;
1820
1821 c = condition_new(CONDITION_NULL, NULL, trigger, negate);
1822 if (!c)
1823 return log_oom();
1824
1825 LIST_PREPEND(Condition, conditions, u->conditions, c);
1826 return 0;
1827 }
1828
1829 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
1830 DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
1831
1832 int config_parse_unit_cgroup_attr(const char *unit,
1833 const char *filename,
1834 unsigned line,
1835 const char *section,
1836 const char *lvalue,
1837 int ltype,
1838 const char *rvalue,
1839 void *data,
1840 void *userdata) {
1841
1842 Unit *u = data;
1843 size_t a, b;
1844 _cleanup_free_ char *n = NULL, *v = NULL;
1845 const CGroupSemantics *s;
1846 int r;
1847
1848 assert(filename);
1849 assert(lvalue);
1850 assert(rvalue);
1851 assert(data);
1852
1853 if (isempty(rvalue)) {
1854 /* Empty assignment clears the list */
1855 cgroup_attribute_free_list(u->cgroup_attributes);
1856 u->cgroup_attributes = NULL;
1857 return 0;
1858 }
1859
1860 a = strcspn(rvalue, WHITESPACE);
1861 b = strspn(rvalue + a, WHITESPACE);
1862 if (a <= 0 || b <= 0) {
1863 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1864 "Failed to parse cgroup attribute value, ignoring: %s",
1865 rvalue);
1866 return 0;
1867 }
1868
1869 n = strndup(rvalue, a);
1870 if (!n)
1871 return log_oom();
1872
1873 r = cgroup_semantics_find(NULL, n, rvalue + a + b, &v, &s);
1874 if (r < 0) {
1875 log_syntax(unit, LOG_ERR, filename, line, -r,
1876 "Failed to parse cgroup attribute value, ignoring: %s",
1877 rvalue);
1878 return 0;
1879 }
1880
1881 r = unit_add_cgroup_attribute(u, s, NULL, n, v ? v : rvalue + a + b, NULL);
1882 if (r < 0) {
1883 log_syntax(unit, LOG_ERR, filename, line, -r,
1884 "Failed to add cgroup attribute value, ignoring: %s", rvalue);
1885 return 0;
1886 }
1887
1888 return 0;
1889 }
1890
1891 int config_parse_unit_cgroup_attr_pretty(const char *unit,
1892 const char *filename,
1893 unsigned line,
1894 const char *section,
1895 const char *lvalue,
1896 int ltype,
1897 const char *rvalue,
1898 void *data,
1899 void *userdata) {
1900
1901 Unit *u = data;
1902 _cleanup_free_ char *v = NULL;
1903 const CGroupSemantics *s;
1904 int r;
1905
1906 assert(filename);
1907 assert(lvalue);
1908 assert(rvalue);
1909 assert(data);
1910
1911 r = cgroup_semantics_find(NULL, lvalue, rvalue, &v, &s);
1912 if (r < 0) {
1913 log_syntax(unit, LOG_ERR, filename, line, -r,
1914 "Failed to parse cgroup attribute value, ignoring: %s",
1915 rvalue);
1916 return 0;
1917 } else if (r == 0) {
1918 log_syntax(unit, LOG_ERR, filename, line, ENOTSUP,
1919 "Unknown or unsupported cgroup attribute %s, ignoring: %s",
1920 lvalue, rvalue);
1921 return 0;
1922 }
1923
1924 r = unit_add_cgroup_attribute(u, s, NULL, NULL, v, NULL);
1925 if (r < 0) {
1926 log_syntax(unit, LOG_ERR, filename, line, -r,
1927 "Failed to add cgroup attribute value, ignoring: %s", rvalue);
1928 return 0;
1929 }
1930
1931 return 0;
1932 }
1933
1934 int config_parse_unit_requires_mounts_for(const char *unit,
1935 const char *filename,
1936 unsigned line,
1937 const char *section,
1938 const char *lvalue,
1939 int ltype,
1940 const char *rvalue,
1941 void *data,
1942 void *userdata) {
1943
1944 Unit *u = userdata;
1945 int r;
1946 bool empty_before;
1947
1948 assert(filename);
1949 assert(lvalue);
1950 assert(rvalue);
1951 assert(data);
1952
1953 empty_before = !u->requires_mounts_for;
1954
1955 r = config_parse_path_strv(unit, filename, line, section, lvalue, ltype,
1956 rvalue, data, userdata);
1957
1958 /* Make it easy to find units with requires_mounts set */
1959 if (empty_before && u->requires_mounts_for)
1960 LIST_PREPEND(Unit, has_requires_mounts_for, u->manager->has_requires_mounts_for, u);
1961
1962 return r;
1963 }
1964
1965 int config_parse_documentation(const char *unit,
1966 const char *filename,
1967 unsigned line,
1968 const char *section,
1969 const char *lvalue,
1970 int ltype,
1971 const char *rvalue,
1972 void *data,
1973 void *userdata) {
1974
1975 Unit *u = userdata;
1976 int r;
1977 char **a, **b;
1978
1979 assert(filename);
1980 assert(lvalue);
1981 assert(rvalue);
1982 assert(u);
1983
1984 if (isempty(rvalue)) {
1985 /* Empty assignment resets the list */
1986 strv_free(u->documentation);
1987 u->documentation = NULL;
1988 return 0;
1989 }
1990
1991 r = config_parse_unit_strv_printf(unit, filename, line, section, lvalue, ltype,
1992 rvalue, data, userdata);
1993 if (r < 0)
1994 return r;
1995
1996 for (a = b = u->documentation; a && *a; a++) {
1997
1998 if (is_valid_documentation_url(*a))
1999 *(b++) = *a;
2000 else {
2001 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2002 "Invalid URL, ignoring: %s", *a);
2003 free(*a);
2004 }
2005 }
2006 *b = NULL;
2007
2008 return r;
2009 }
2010
2011 static void syscall_set(uint32_t *p, int nr) {
2012 nr = SYSCALL_TO_INDEX(nr);
2013 p[nr >> 4] |= 1 << (nr & 31);
2014 }
2015
2016 static void syscall_unset(uint32_t *p, int nr) {
2017 nr = SYSCALL_TO_INDEX(nr);
2018 p[nr >> 4] &= ~(1 << (nr & 31));
2019 }
2020
2021 int config_parse_syscall_filter(const char *unit,
2022 const char *filename,
2023 unsigned line,
2024 const char *section,
2025 const char *lvalue,
2026 int ltype,
2027 const char *rvalue,
2028 void *data,
2029 void *userdata) {
2030
2031 ExecContext *c = data;
2032 Unit *u = userdata;
2033 bool invert = false;
2034 char *w;
2035 size_t l;
2036 char *state;
2037
2038 assert(filename);
2039 assert(lvalue);
2040 assert(rvalue);
2041 assert(u);
2042
2043 if (isempty(rvalue)) {
2044 /* Empty assignment resets the list */
2045 free(c->syscall_filter);
2046 c->syscall_filter = NULL;
2047 return 0;
2048 }
2049
2050 if (rvalue[0] == '~') {
2051 invert = true;
2052 rvalue++;
2053 }
2054
2055 if (!c->syscall_filter) {
2056 size_t n;
2057
2058 n = (syscall_max() + 31) >> 4;
2059 c->syscall_filter = new(uint32_t, n);
2060 if (!c->syscall_filter)
2061 return log_oom();
2062
2063 memset(c->syscall_filter, invert ? 0xFF : 0, n * sizeof(uint32_t));
2064
2065 /* Add these by default */
2066 syscall_set(c->syscall_filter, __NR_execve);
2067 syscall_set(c->syscall_filter, __NR_rt_sigreturn);
2068 #ifdef __NR_sigreturn
2069 syscall_set(c->syscall_filter, __NR_sigreturn);
2070 #endif
2071 syscall_set(c->syscall_filter, __NR_exit_group);
2072 syscall_set(c->syscall_filter, __NR_exit);
2073 }
2074
2075 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2076 int id;
2077 _cleanup_free_ char *t = NULL;
2078
2079 t = strndup(w, l);
2080 if (!t)
2081 return log_oom();
2082
2083 id = syscall_from_name(t);
2084 if (id < 0) {
2085 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2086 "Failed to parse syscall, ignoring: %s", t);
2087 continue;
2088 }
2089
2090 if (invert)
2091 syscall_unset(c->syscall_filter, id);
2092 else
2093 syscall_set(c->syscall_filter, id);
2094 }
2095
2096 c->no_new_privileges = true;
2097
2098 return 0;
2099 }
2100
2101 #define FOLLOW_MAX 8
2102
2103 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
2104 unsigned c = 0;
2105 int fd, r;
2106 FILE *f;
2107 char *id = NULL;
2108
2109 assert(filename);
2110 assert(*filename);
2111 assert(_f);
2112 assert(names);
2113
2114 /* This will update the filename pointer if the loaded file is
2115 * reached by a symlink. The old string will be freed. */
2116
2117 for (;;) {
2118 char *target, *name;
2119
2120 if (c++ >= FOLLOW_MAX)
2121 return -ELOOP;
2122
2123 path_kill_slashes(*filename);
2124
2125 /* Add the file name we are currently looking at to
2126 * the names of this unit, but only if it is a valid
2127 * unit name. */
2128 name = path_get_file_name(*filename);
2129
2130 if (unit_name_is_valid(name, true)) {
2131
2132 id = set_get(names, name);
2133 if (!id) {
2134 id = strdup(name);
2135 if (!id)
2136 return -ENOMEM;
2137
2138 r = set_put(names, id);
2139 if (r < 0) {
2140 free(id);
2141 return r;
2142 }
2143 }
2144 }
2145
2146 /* Try to open the file name, but don't if its a symlink */
2147 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
2148 if (fd >= 0)
2149 break;
2150
2151 if (errno != ELOOP)
2152 return -errno;
2153
2154 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
2155 r = readlink_and_make_absolute(*filename, &target);
2156 if (r < 0)
2157 return r;
2158
2159 free(*filename);
2160 *filename = target;
2161 }
2162
2163 f = fdopen(fd, "re");
2164 if (!f) {
2165 r = -errno;
2166 close_nointr_nofail(fd);
2167 return r;
2168 }
2169
2170 *_f = f;
2171 *_final = id;
2172 return 0;
2173 }
2174
2175 static int merge_by_names(Unit **u, Set *names, const char *id) {
2176 char *k;
2177 int r;
2178
2179 assert(u);
2180 assert(*u);
2181 assert(names);
2182
2183 /* Let's try to add in all symlink names we found */
2184 while ((k = set_steal_first(names))) {
2185
2186 /* First try to merge in the other name into our
2187 * unit */
2188 r = unit_merge_by_name(*u, k);
2189 if (r < 0) {
2190 Unit *other;
2191
2192 /* Hmm, we couldn't merge the other unit into
2193 * ours? Then let's try it the other way
2194 * round */
2195
2196 other = manager_get_unit((*u)->manager, k);
2197 free(k);
2198
2199 if (other) {
2200 r = unit_merge(other, *u);
2201 if (r >= 0) {
2202 *u = other;
2203 return merge_by_names(u, names, NULL);
2204 }
2205 }
2206
2207 return r;
2208 }
2209
2210 if (id == k)
2211 unit_choose_id(*u, id);
2212
2213 free(k);
2214 }
2215
2216 return 0;
2217 }
2218
2219 static int load_from_path(Unit *u, const char *path) {
2220 int r;
2221 Set *symlink_names;
2222 FILE *f = NULL;
2223 char *filename = NULL, *id = NULL;
2224 Unit *merged;
2225 struct stat st;
2226
2227 assert(u);
2228 assert(path);
2229
2230 symlink_names = set_new(string_hash_func, string_compare_func);
2231 if (!symlink_names)
2232 return -ENOMEM;
2233
2234 if (path_is_absolute(path)) {
2235
2236 filename = strdup(path);
2237 if (!filename) {
2238 r = -ENOMEM;
2239 goto finish;
2240 }
2241
2242 r = open_follow(&filename, &f, symlink_names, &id);
2243 if (r < 0) {
2244 free(filename);
2245 filename = NULL;
2246
2247 if (r != -ENOENT)
2248 goto finish;
2249 }
2250
2251 } else {
2252 char **p;
2253
2254 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
2255
2256 /* Instead of opening the path right away, we manually
2257 * follow all symlinks and add their name to our unit
2258 * name set while doing so */
2259 filename = path_make_absolute(path, *p);
2260 if (!filename) {
2261 r = -ENOMEM;
2262 goto finish;
2263 }
2264
2265 if (u->manager->unit_path_cache &&
2266 !set_get(u->manager->unit_path_cache, filename))
2267 r = -ENOENT;
2268 else
2269 r = open_follow(&filename, &f, symlink_names, &id);
2270
2271 if (r < 0) {
2272 free(filename);
2273 filename = NULL;
2274
2275 if (r != -ENOENT)
2276 goto finish;
2277
2278 /* Empty the symlink names for the next run */
2279 set_clear_free(symlink_names);
2280 continue;
2281 }
2282
2283 break;
2284 }
2285 }
2286
2287 if (!filename) {
2288 /* Hmm, no suitable file found? */
2289 r = 0;
2290 goto finish;
2291 }
2292
2293 merged = u;
2294 r = merge_by_names(&merged, symlink_names, id);
2295 if (r < 0)
2296 goto finish;
2297
2298 if (merged != u) {
2299 u->load_state = UNIT_MERGED;
2300 r = 0;
2301 goto finish;
2302 }
2303
2304 if (fstat(fileno(f), &st) < 0) {
2305 r = -errno;
2306 goto finish;
2307 }
2308
2309 if (null_or_empty(&st))
2310 u->load_state = UNIT_MASKED;
2311 else {
2312 /* Now, parse the file contents */
2313 r = config_parse(u->id, filename, f, UNIT_VTABLE(u)->sections,
2314 config_item_perf_lookup,
2315 (void*) load_fragment_gperf_lookup, false, u);
2316 if (r < 0)
2317 goto finish;
2318
2319 u->load_state = UNIT_LOADED;
2320 }
2321
2322 free(u->fragment_path);
2323 u->fragment_path = filename;
2324 filename = NULL;
2325
2326 u->fragment_mtime = timespec_load(&st.st_mtim);
2327
2328 if (u->source_path) {
2329 if (stat(u->source_path, &st) >= 0)
2330 u->source_mtime = timespec_load(&st.st_mtim);
2331 else
2332 u->source_mtime = 0;
2333 }
2334
2335 r = 0;
2336
2337 finish:
2338 set_free_free(symlink_names);
2339 free(filename);
2340
2341 if (f)
2342 fclose(f);
2343
2344 return r;
2345 }
2346
2347 int unit_load_fragment(Unit *u) {
2348 int r;
2349 Iterator i;
2350 const char *t;
2351
2352 assert(u);
2353 assert(u->load_state == UNIT_STUB);
2354 assert(u->id);
2355
2356 /* First, try to find the unit under its id. We always look
2357 * for unit files in the default directories, to make it easy
2358 * to override things by placing things in /etc/systemd/system */
2359 r = load_from_path(u, u->id);
2360 if (r < 0)
2361 return r;
2362
2363 /* Try to find an alias we can load this with */
2364 if (u->load_state == UNIT_STUB)
2365 SET_FOREACH(t, u->names, i) {
2366
2367 if (t == u->id)
2368 continue;
2369
2370 r = load_from_path(u, t);
2371 if (r < 0)
2372 return r;
2373
2374 if (u->load_state != UNIT_STUB)
2375 break;
2376 }
2377
2378 /* And now, try looking for it under the suggested (originally linked) path */
2379 if (u->load_state == UNIT_STUB && u->fragment_path) {
2380
2381 r = load_from_path(u, u->fragment_path);
2382 if (r < 0)
2383 return r;
2384
2385 if (u->load_state == UNIT_STUB) {
2386 /* Hmm, this didn't work? Then let's get rid
2387 * of the fragment path stored for us, so that
2388 * we don't point to an invalid location. */
2389 free(u->fragment_path);
2390 u->fragment_path = NULL;
2391 }
2392 }
2393
2394 /* Look for a template */
2395 if (u->load_state == UNIT_STUB && u->instance) {
2396 char *k;
2397
2398 k = unit_name_template(u->id);
2399 if (!k)
2400 return -ENOMEM;
2401
2402 r = load_from_path(u, k);
2403 free(k);
2404
2405 if (r < 0)
2406 return r;
2407
2408 if (u->load_state == UNIT_STUB)
2409 SET_FOREACH(t, u->names, i) {
2410
2411 if (t == u->id)
2412 continue;
2413
2414 k = unit_name_template(t);
2415 if (!k)
2416 return -ENOMEM;
2417
2418 r = load_from_path(u, k);
2419 free(k);
2420
2421 if (r < 0)
2422 return r;
2423
2424 if (u->load_state != UNIT_STUB)
2425 break;
2426 }
2427 }
2428
2429 return 0;
2430 }
2431
2432 void unit_dump_config_items(FILE *f) {
2433 static const struct {
2434 const ConfigParserCallback callback;
2435 const char *rvalue;
2436 } table[] = {
2437 { config_parse_int, "INTEGER" },
2438 { config_parse_unsigned, "UNSIGNED" },
2439 { config_parse_bytes_size, "SIZE" },
2440 { config_parse_bool, "BOOLEAN" },
2441 { config_parse_string, "STRING" },
2442 { config_parse_path, "PATH" },
2443 { config_parse_unit_path_printf, "PATH" },
2444 { config_parse_strv, "STRING [...]" },
2445 { config_parse_exec_nice, "NICE" },
2446 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
2447 { config_parse_exec_io_class, "IOCLASS" },
2448 { config_parse_exec_io_priority, "IOPRIORITY" },
2449 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
2450 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
2451 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
2452 { config_parse_mode, "MODE" },
2453 { config_parse_unit_env_file, "FILE" },
2454 { config_parse_output, "OUTPUT" },
2455 { config_parse_input, "INPUT" },
2456 { config_parse_facility, "FACILITY" },
2457 { config_parse_level, "LEVEL" },
2458 { config_parse_exec_capabilities, "CAPABILITIES" },
2459 { config_parse_exec_secure_bits, "SECUREBITS" },
2460 { config_parse_bounding_set, "BOUNDINGSET" },
2461 { config_parse_limit, "LIMIT" },
2462 { config_parse_unit_cgroup, "CGROUP [...]" },
2463 { config_parse_unit_deps, "UNIT [...]" },
2464 { config_parse_exec, "PATH [ARGUMENT [...]]" },
2465 { config_parse_service_type, "SERVICETYPE" },
2466 { config_parse_service_restart, "SERVICERESTART" },
2467 #ifdef HAVE_SYSV_COMPAT
2468 { config_parse_sysv_priority, "SYSVPRIORITY" },
2469 #else
2470 { config_parse_warn_compat, "NOTSUPPORTED" },
2471 #endif
2472 { config_parse_kill_mode, "KILLMODE" },
2473 { config_parse_kill_signal, "SIGNAL" },
2474 { config_parse_socket_listen, "SOCKET [...]" },
2475 { config_parse_socket_bind, "SOCKETBIND" },
2476 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
2477 { config_parse_sec, "SECONDS" },
2478 { config_parse_nsec, "NANOSECONDS" },
2479 { config_parse_path_strv, "PATH [...]" },
2480 { config_parse_unit_requires_mounts_for, "PATH [...]" },
2481 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
2482 { config_parse_unit_string_printf, "STRING" },
2483 { config_parse_timer, "TIMER" },
2484 { config_parse_timer_unit, "NAME" },
2485 { config_parse_path_spec, "PATH" },
2486 { config_parse_path_unit, "UNIT" },
2487 { config_parse_notify_access, "ACCESS" },
2488 { config_parse_ip_tos, "TOS" },
2489 { config_parse_unit_condition_path, "CONDITION" },
2490 { config_parse_unit_condition_string, "CONDITION" },
2491 { config_parse_unit_condition_null, "CONDITION" },
2492 };
2493
2494 const char *prev = NULL;
2495 const char *i;
2496
2497 assert(f);
2498
2499 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
2500 const char *rvalue = "OTHER", *lvalue;
2501 unsigned j;
2502 size_t prefix_len;
2503 const char *dot;
2504 const ConfigPerfItem *p;
2505
2506 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
2507
2508 dot = strchr(i, '.');
2509 lvalue = dot ? dot + 1 : i;
2510 prefix_len = dot-i;
2511
2512 if (dot)
2513 if (!prev || !strneq(prev, i, prefix_len+1)) {
2514 if (prev)
2515 fputc('\n', f);
2516
2517 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
2518 }
2519
2520 for (j = 0; j < ELEMENTSOF(table); j++)
2521 if (p->parse == table[j].callback) {
2522 rvalue = table[j].rvalue;
2523 break;
2524 }
2525
2526 fprintf(f, "%s=%s\n", lvalue, rvalue);
2527 prev = i;
2528 }
2529 }