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