]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/load-fragment.c
service: add new RestartMode option
[thirdparty/systemd.git] / src / core / load-fragment.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
a7334b09 2/***
96b2fb93 3 Copyright © 2012 Holger Hans Peter Freyther
a7334b09
LP
4***/
5
3efd4195 6#include <errno.h>
87f0e418 7#include <fcntl.h>
25e870b5 8#include <linux/fs.h>
5f5d8eab 9#include <linux/oom.h>
349cc4a5 10#if HAVE_SECCOMP
618234a5
LP
11#include <seccomp.h>
12#endif
5f5d8eab 13#include <sched.h>
3d57c6ab 14#include <sys/resource.h>
3efd4195 15
bed0b7df
LP
16#include "sd-messages.h"
17
5f5d8eab 18#include "af-list.h"
57b7a260 19#include "all-units.h"
786d19fd 20#include "alloc-util.h"
fab34748 21#include "bpf-firewall.h"
e59ccd03 22#include "bpf-lsm.h"
0879da98 23#include "bpf-program.h"
cd09a5f3 24#include "bpf-socket-bind.h"
5f5d8eab
LP
25#include "bus-error.h"
26#include "bus-internal.h"
27#include "bus-util.h"
28#include "cap-list.h"
a103496c 29#include "capability-util.h"
fdb3deca 30#include "cgroup-setup.h"
3efd4195 31#include "conf-parser.h"
e30bbc90 32#include "core-varlink.h"
618234a5 33#include "cpu-set-util.h"
786d19fd 34#include "creds-util.h"
5f5d8eab
LP
35#include "env-util.h"
36#include "errno-list.h"
4f5dd394 37#include "escape.h"
3ffd4af2 38#include "fd-util.h"
0389f4fa 39#include "fileio.h"
f4f15635 40#include "fs-util.h"
08f3be7a 41#include "hexdecoct.h"
d3070fbd 42#include "io-util.h"
032b3afb 43#include "ioprio-util.h"
da96ad5a 44#include "ip-protocol-list.h"
adce225a 45#include "journal-file.h"
eefc66aa 46#include "limits-util.h"
3ffd4af2 47#include "load-fragment.h"
5f5d8eab 48#include "log.h"
5bead76e 49#include "missing_ioprio.h"
049af8ad 50#include "mountpoint-util.h"
d8b4d14d 51#include "nulstr-util.h"
cd48e23f 52#include "open-file.h"
c3eaba2d 53#include "parse-helpers.h"
6bedfcbb 54#include "parse-util.h"
9eb977db 55#include "path-util.h"
523ea123 56#include "pcre2-util.h"
ed5033fd 57#include "percent-util.h"
7b3e062c 58#include "process-util.h"
349cc4a5 59#if HAVE_SECCOMP
57183d11
LP
60#include "seccomp-util.h"
61#endif
07d46372 62#include "securebits-util.h"
23e9a7dd 63#include "selinux-util.h"
5f5d8eab 64#include "signal-util.h"
5c3fa98d 65#include "socket-netlink.h"
46a9ee5d 66#include "specifier.h"
8fcde012 67#include "stat-util.h"
07630cea 68#include "string-util.h"
5f5d8eab 69#include "strv.h"
91dd5f7c
LP
70#include "syslog-util.h"
71#include "time-util.h"
5f5d8eab
LP
72#include "unit-name.h"
73#include "unit-printf.h"
66dccd8d 74#include "user-util.h"
bb0c0d6f 75#include "utf8.h"
49cf4170 76#include "web-util.h"
57183d11 77
d2b42d63 78static int parse_socket_protocol(const char *s) {
53577580
YW
79 int r;
80
d2b42d63 81 r = parse_ip_protocol(s);
53577580 82 if (r < 0)
acf4d158 83 return r;
53577580
YW
84 if (!IN_SET(r, IPPROTO_UDPLITE, IPPROTO_SCTP))
85 return -EPROTONOSUPPORT;
86
87 return r;
88}
89
a07a7324
FS
90int parse_crash_chvt(const char *value, int *data) {
91 int b;
92
93 if (safe_atoi(value, data) >= 0)
94 return 0;
95
96 b = parse_boolean(value);
97 if (b < 0)
98 return b;
99
100 if (b > 0)
101 *data = 0; /* switch to where kmsg goes */
102 else
103 *data = -1; /* turn off switching */
104
105 return 0;
106}
107
108int parse_confirm_spawn(const char *value, char **console) {
109 char *s;
110 int r;
111
112 r = value ? parse_boolean(value) : 1;
113 if (r == 0) {
114 *console = NULL;
115 return 0;
4a8daee7 116 } else if (r > 0) /* on with default tty */
a07a7324
FS
117 s = strdup("/dev/console");
118 else if (is_path(value)) /* on with fully qualified path */
119 s = strdup(value);
120 else /* on with only a tty file name, not a fully qualified path */
4a8daee7 121 s = path_join("/dev/", value);
a07a7324
FS
122 if (!s)
123 return -ENOMEM;
124
125 *console = s;
126 return 0;
127}
128
d2b42d63 129DEFINE_CONFIG_PARSE(config_parse_socket_protocol, parse_socket_protocol, "Failed to parse socket protocol");
53577580 130DEFINE_CONFIG_PARSE(config_parse_exec_secure_bits, secure_bits_from_string, "Failed to parse secure bits");
5afe510c 131DEFINE_CONFIG_PARSE_ENUM(config_parse_collect_mode, collect_mode, CollectMode, "Failed to parse garbage collection mode");
53577580 132DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
53577580 133DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_keyring_mode, exec_keyring_mode, ExecKeyringMode, "Failed to parse keyring mode");
4e399953
LP
134DEFINE_CONFIG_PARSE_ENUM(config_parse_protect_proc, protect_proc, ProtectProc, "Failed to parse /proc/ protection mode");
135DEFINE_CONFIG_PARSE_ENUM(config_parse_proc_subset, proc_subset, ProcSubset, "Failed to parse /proc/ subset mode");
53577580
YW
136DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_utmp_mode, exec_utmp_mode, ExecUtmpMode, "Failed to parse utmp mode");
137DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
53577580 138DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
1e8c7bd5
YW
139DEFINE_CONFIG_PARSE_ENUM(config_parse_protect_home, protect_home, ProtectHome, "Failed to parse protect home value");
140DEFINE_CONFIG_PARSE_ENUM(config_parse_protect_system, protect_system, ProtectSystem, "Failed to parse protect system value");
b9c1883a 141DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_preserve_mode, exec_preserve_mode, ExecPreserveMode, "Failed to parse resource preserve mode");
53577580 142DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
596e4470 143DEFINE_CONFIG_PARSE_ENUM(config_parse_service_exit_type, service_exit_type, ServiceExitType, "Failed to parse service exit type");
53577580 144DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
e568fea9 145DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart_mode, service_restart_mode, ServiceRestartMode, "Failed to parse service restart mode");
bf760801 146DEFINE_CONFIG_PARSE_ENUM(config_parse_service_timeout_failure_mode, service_timeout_failure_mode, ServiceTimeoutFailureMode, "Failed to parse timeout failure mode");
53577580 147DEFINE_CONFIG_PARSE_ENUM(config_parse_socket_bind, socket_address_bind_ipv6_only_or_bool, SocketAddressBindIPv6Only, "Failed to parse bind IPv6 only value");
afcfaa69 148DEFINE_CONFIG_PARSE_ENUM(config_parse_oom_policy, oom_policy, OOMPolicy, "Failed to parse OOM policy");
4e806bfa 149DEFINE_CONFIG_PARSE_ENUM(config_parse_managed_oom_preference, managed_oom_preference, ManagedOOMPreference, "Failed to parse ManagedOOMPreference=");
054749e4 150DEFINE_CONFIG_PARSE_ENUM(config_parse_memory_pressure_watch, cgroup_pressure_watch, CGroupPressureWatch, "Failed to parse memory pressure watch setting");
53577580
YW
151DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(config_parse_ip_tos, ip_tos, int, -1, "Failed to parse IP TOS value");
152DEFINE_CONFIG_PARSE_PTR(config_parse_blockio_weight, cg_blkio_weight_parse, uint64_t, "Invalid block IO weight");
153DEFINE_CONFIG_PARSE_PTR(config_parse_cg_weight, cg_weight_parse, uint64_t, "Invalid weight");
c8340822 154DEFINE_CONFIG_PARSE_PTR(config_parse_cg_cpu_weight, cg_cpu_weight_parse, uint64_t, "Invalid CPU weight");
c1e701e2 155static DEFINE_CONFIG_PARSE_PTR(config_parse_cpu_shares_internal, cg_cpu_shares_parse, uint64_t, "Invalid CPU shares");
874cdcbc 156DEFINE_CONFIG_PARSE_PTR(config_parse_exec_mount_propagation_flag, mount_propagation_flag_from_string, unsigned long, "Failed to parse mount propagation flag");
b070c7c0 157DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(config_parse_numa_policy, mpol, int, -1, "Invalid NUMA policy type");
6327aa9f 158DEFINE_CONFIG_PARSE_ENUM(config_parse_status_unit_format, status_unit_format, StatusUnitFormat, "Failed to parse status unit format");
9b191525 159DEFINE_CONFIG_PARSE_ENUM_FULL(config_parse_socket_timestamping, socket_timestamping_from_string_harder, SocketTimestamping, "Failed to parse timestamping precision");
5afe510c 160
c1e701e2
LP
161int config_parse_cpu_shares(
162 const char *unit,
163 const char *filename,
164 unsigned line,
165 const char *section,
166 unsigned section_line,
167 const char *lvalue,
168 int ltype,
169 const char *rvalue,
170 void *data,
171 void *userdata) {
172
173 assert(filename);
174 assert(lvalue);
175 assert(rvalue);
176
177
178 log_syntax(unit, LOG_WARNING, filename, line, 0,
179 "Unit uses %s=; please use CPUWeight= instead. Support for %s= will be removed soon.",
180 lvalue, lvalue);
181
182 return config_parse_cpu_shares_internal(unit, filename, line, section, section_line, lvalue, ltype, rvalue, data, userdata);
183}
184
88022148
DDM
185bool contains_instance_specifier_superset(const char *s) {
186 const char *p, *q;
187 bool percent = false;
188
189 assert(s);
190
191 p = strchr(s, '@');
192 if (!p)
193 return false;
194
195 p++; /* Skip '@' */
196
197 q = strrchr(p, '.');
198 if (!q)
199 q = p + strlen(p);
200
201 /* If the string is just the instance specifier, it's not a superset of the instance. */
202 if (memcmp_nn(p, q - p, "%i", strlen("%i")) == 0)
203 return false;
204
205 /* %i, %n and %N all expand to the instance or a superset of it. */
24aaf6c6 206 for (; p < q; p++)
88022148
DDM
207 if (*p == '%')
208 percent = !percent;
209 else if (percent) {
210 if (IN_SET(*p, 'n', 'N', 'i'))
211 return true;
212 percent = false;
213 }
88022148
DDM
214
215 return false;
216}
217
218/* `name` is the rendered version of `format` via `unit_printf` or similar functions. */
219int unit_is_likely_recursive_template_dependency(Unit *u, const char *name, const char *format) {
220 const char *fragment_path;
221 int r;
222
223 assert(u);
224 assert(name);
225
226 /* If a template unit has a direct dependency on itself that includes the unit instance as part of
227 * the template instance via a unit specifier (%i, %n or %N), this will almost certainly lead to
228 * infinite recursion as systemd will keep instantiating new instances of the template unit.
229 * https://github.com/systemd/systemd/issues/17602 shows a good example of how this can happen in
230 * practice. To guard against this, we check for templates that depend on themselves and have the
231 * instantiated unit instance included as part of the template instance of the dependency via a
232 * specifier.
233 *
234 * For example, if systemd-notify@.service depends on systemd-notify@%n.service, this will result in
235 * infinite recursion.
236 */
237
238 if (!unit_name_is_valid(name, UNIT_NAME_INSTANCE))
239 return false;
240
241 if (!unit_name_prefix_equal(u->id, name))
242 return false;
243
244 if (u->type != unit_name_to_type(name))
245 return false;
246
247 r = unit_file_find_fragment(u->manager->unit_id_map, u->manager->unit_name_map, name, &fragment_path, NULL);
248 if (r < 0)
249 return r;
250
251 /* Fragment paths should also be equal as a custom fragment for a specific template instance
252 * wouldn't necessarily lead to infinite recursion. */
253 if (!path_equal_ptr(u->fragment_path, fragment_path))
254 return false;
255
256 if (!contains_instance_specifier_superset(format))
257 return false;
258
259 return true;
260}
261
f32b43bd
LP
262int config_parse_unit_deps(
263 const char *unit,
264 const char *filename,
265 unsigned line,
266 const char *section,
267 unsigned section_line,
268 const char *lvalue,
269 int ltype,
270 const char *rvalue,
271 void *data,
272 void *userdata) {
3efd4195 273
f975e971 274 UnitDependency d = ltype;
87f0e418 275 Unit *u = userdata;
3efd4195
LP
276
277 assert(filename);
278 assert(lvalue);
279 assert(rvalue);
3efd4195 280
323dda78 281 for (const char *p = rvalue;;) {
3d793d29 282 _cleanup_free_ char *word = NULL, *k = NULL;
3efd4195 283 int r;
3efd4195 284
c89f52ac 285 r = extract_first_word(&p, &word, NULL, EXTRACT_RETAIN_ESCAPE);
3d793d29 286 if (r == 0)
323dda78 287 return 0;
3d793d29 288 if (r == -ENOMEM)
74051b9b 289 return log_oom();
3d793d29 290 if (r < 0) {
323dda78
YW
291 log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
292 return 0;
3d793d29 293 }
3efd4195 294
3d793d29 295 r = unit_name_printf(u, word, &k);
19f6d710 296 if (r < 0) {
323dda78 297 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", word);
19f6d710
LP
298 continue;
299 }
9e2f7c11 300
88022148
DDM
301 r = unit_is_likely_recursive_template_dependency(u, k, word);
302 if (r < 0) {
303 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to determine if '%s' is a recursive dependency, ignoring: %m", k);
304 continue;
305 }
306 if (r > 0) {
307 log_syntax(unit, LOG_DEBUG, filename, line, 0,
308 "Dropping dependency %s=%s that likely leads to infinite recursion.",
309 unit_dependency_to_string(d), word);
310 continue;
311 }
312
35d8c19a 313 r = unit_add_dependency_by_name(u, d, k, true, UNIT_DEPENDENCY_FILE);
57020a3a 314 if (r < 0)
323dda78 315 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
3efd4195 316 }
3efd4195
LP
317}
318
f32b43bd
LP
319int config_parse_obsolete_unit_deps(
320 const char *unit,
321 const char *filename,
322 unsigned line,
323 const char *section,
324 unsigned section_line,
325 const char *lvalue,
326 int ltype,
327 const char *rvalue,
328 void *data,
329 void *userdata) {
330
331 log_syntax(unit, LOG_WARNING, filename, line, 0,
332 "Unit dependency type %s= is obsolete, replacing by %s=, please update your unit file", lvalue, unit_dependency_to_string(ltype));
333
334 return config_parse_unit_deps(unit, filename, line, section, section_line, lvalue, ltype, rvalue, data, userdata);
335}
336
b02cb41c
LP
337int config_parse_unit_string_printf(
338 const char *unit,
339 const char *filename,
340 unsigned line,
341 const char *section,
342 unsigned section_line,
343 const char *lvalue,
344 int ltype,
345 const char *rvalue,
346 void *data,
347 void *userdata) {
932921b5 348
74051b9b 349 _cleanup_free_ char *k = NULL;
99534007 350 const Unit *u = ASSERT_PTR(userdata);
19f6d710 351 int r;
932921b5
LP
352
353 assert(filename);
354 assert(lvalue);
355 assert(rvalue);
932921b5 356
19f6d710 357 r = unit_full_printf(u, rvalue, &k);
b02cb41c 358 if (r < 0) {
323dda78 359 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
b02cb41c
LP
360 return 0;
361 }
932921b5 362
b02cb41c 363 return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
932921b5
LP
364}
365
12ca818f
LP
366int config_parse_unit_strv_printf(
367 const char *unit,
368 const char *filename,
369 unsigned line,
370 const char *section,
371 unsigned section_line,
372 const char *lvalue,
373 int ltype,
374 const char *rvalue,
375 void *data,
376 void *userdata) {
8fef7659 377
99534007 378 const Unit *u = ASSERT_PTR(userdata);
74051b9b 379 _cleanup_free_ char *k = NULL;
19f6d710 380 int r;
8fef7659
LP
381
382 assert(filename);
383 assert(lvalue);
384 assert(rvalue);
8fef7659 385
19f6d710 386 r = unit_full_printf(u, rvalue, &k);
12ca818f 387 if (r < 0) {
323dda78 388 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
12ca818f
LP
389 return 0;
390 }
8fef7659 391
12ca818f 392 return config_parse_strv(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
8fef7659
LP
393}
394
5f5d8eab
LP
395int config_parse_unit_path_printf(
396 const char *unit,
397 const char *filename,
398 unsigned line,
399 const char *section,
400 unsigned section_line,
401 const char *lvalue,
402 int ltype,
403 const char *rvalue,
404 void *data,
405 void *userdata) {
6ea832a2 406
74051b9b 407 _cleanup_free_ char *k = NULL;
99534007 408 const Unit *u = ASSERT_PTR(userdata);
19f6d710 409 int r;
2c75fb73 410 bool fatal = ltype;
6ea832a2
LP
411
412 assert(filename);
413 assert(lvalue);
414 assert(rvalue);
6ea832a2 415
06536492 416 r = unit_path_printf(u, rvalue, &k);
811ba7a0 417 if (r < 0) {
323dda78 418 log_syntax(unit, fatal ? LOG_ERR : LOG_WARNING, filename, line, r,
063c4b1a 419 "Failed to resolve unit specifiers in '%s'%s: %m",
e3c3d676 420 rvalue, fatal ? "" : ", ignoring");
2c75fb73 421 return fatal ? -ENOEXEC : 0;
811ba7a0 422 }
6ea832a2 423
811ba7a0
LP
424 return config_parse_path(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
425}
426
8c35c10d 427int config_parse_colon_separated_paths(
428 const char *unit,
429 const char *filename,
430 unsigned line,
431 const char *section,
432 unsigned section_line,
433 const char *lvalue,
434 int ltype,
435 const char *rvalue,
436 void *data,
437 void *userdata) {
99534007 438 char ***sv = ASSERT_PTR(data);
8c35c10d 439 const Unit *u = userdata;
440 int r;
441
442 assert(filename);
443 assert(lvalue);
444 assert(rvalue);
8c35c10d 445
446 if (isempty(rvalue)) {
447 /* Empty assignment resets the list */
448 *sv = strv_free(*sv);
449 return 0;
450 }
451
452 for (const char *p = rvalue;;) {
453 _cleanup_free_ char *word = NULL, *k = NULL;
454
455 r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
456 if (r == -ENOMEM)
457 return log_oom();
458 if (r < 0) {
459 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to extract first word, ignoring: %s", rvalue);
460 return 0;
461 }
462 if (r == 0)
463 break;
464
465 r = unit_path_printf(u, word, &k);
466 if (r < 0) {
467 log_syntax(unit, LOG_WARNING, filename, line, r,
468 "Failed to resolve unit specifiers in '%s', ignoring: %m", word);
469 return 0;
470 }
471
472 r = path_simplify_and_warn(k, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
473 if (r < 0)
474 return 0;
475
476 r = strv_consume(sv, TAKE_PTR(k));
477 if (r < 0)
478 return log_oom();
479 }
480
481 return 0;
482}
483
811ba7a0
LP
484int config_parse_unit_path_strv_printf(
485 const char *unit,
486 const char *filename,
487 unsigned line,
488 const char *section,
489 unsigned section_line,
490 const char *lvalue,
491 int ltype,
492 const char *rvalue,
493 void *data,
494 void *userdata) {
495
a2a5291b 496 char ***x = data;
99534007 497 const Unit *u = ASSERT_PTR(userdata);
811ba7a0
LP
498 int r;
499
500 assert(filename);
501 assert(lvalue);
502 assert(rvalue);
811ba7a0 503
499295fb 504 if (isempty(rvalue)) {
9f2d41a6 505 *x = strv_free(*x);
499295fb
YW
506 return 0;
507 }
508
323dda78 509 for (const char *p = rvalue;;) {
035fe294 510 _cleanup_free_ char *word = NULL, *k = NULL;
811ba7a0 511
4ec85141 512 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
035fe294
ZJS
513 if (r == 0)
514 return 0;
515 if (r == -ENOMEM)
516 return log_oom();
517 if (r < 0) {
518 log_syntax(unit, LOG_WARNING, filename, line, r,
519 "Invalid syntax, ignoring: %s", rvalue);
520 return 0;
521 }
811ba7a0 522
06536492 523 r = unit_path_printf(u, word, &k);
811ba7a0 524 if (r < 0) {
323dda78 525 log_syntax(unit, LOG_WARNING, filename, line, r,
063c4b1a 526 "Failed to resolve unit specifiers in '%s', ignoring: %m", word);
811ba7a0
LP
527 return 0;
528 }
529
2f4d31c1
YW
530 r = path_simplify_and_warn(k, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
531 if (r < 0)
811ba7a0 532 return 0;
811ba7a0 533
7d2c9c6b 534 r = strv_consume(x, TAKE_PTR(k));
811ba7a0
LP
535 if (r < 0)
536 return log_oom();
811ba7a0 537 }
6ea832a2
LP
538}
539
4a66b5c9
LP
540static int patch_var_run(
541 const char *unit,
542 const char *filename,
543 unsigned line,
544 const char *lvalue,
545 char **path) {
546
547 const char *e;
548 char *z;
549
550 e = path_startswith(*path, "/var/run/");
551 if (!e)
552 return 0;
553
554 z = path_join("/run/", e);
555 if (!z)
556 return log_oom();
557
558 log_syntax(unit, LOG_NOTICE, filename, line, 0,
559 "%s= references a path below legacy directory /var/run/, updating %s → %s; "
560 "please update the unit file accordingly.", lvalue, *path, z);
561
562 free_and_replace(*path, z);
563
564 return 1;
565}
566
567int config_parse_socket_listen(
568 const char *unit,
569 const char *filename,
570 unsigned line,
571 const char *section,
572 unsigned section_line,
573 const char *lvalue,
574 int ltype,
575 const char *rvalue,
576 void *data,
577 void *userdata) {
42f4e3c4 578
b1389b0d
ZJS
579 _cleanup_free_ SocketPort *p = NULL;
580 SocketPort *tail;
542563ba 581 Socket *s;
19f6d710 582 int r;
16354eff 583
42f4e3c4
LP
584 assert(filename);
585 assert(lvalue);
586 assert(rvalue);
587 assert(data);
588
595ed347 589 s = SOCKET(data);
542563ba 590
74051b9b
LP
591 if (isempty(rvalue)) {
592 /* An empty assignment removes all ports */
593 socket_free_ports(s);
594 return 0;
595 }
596
7f110ff9
LP
597 p = new0(SocketPort, 1);
598 if (!p)
74051b9b 599 return log_oom();
916abb21 600
74051b9b 601 if (ltype != SOCKET_SOCKET) {
2f4d31c1 602 _cleanup_free_ char *k = NULL;
916abb21 603
06536492 604 r = unit_path_printf(UNIT(s), rvalue, &k);
19f6d710 605 if (r < 0) {
323dda78 606 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
12ca818f 607 return 0;
916abb21
LP
608 }
609
2f4d31c1
YW
610 r = path_simplify_and_warn(k, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
611 if (r < 0)
612 return 0;
613
4a66b5c9
LP
614 if (ltype == SOCKET_FIFO) {
615 r = patch_var_run(unit, filename, line, lvalue, &k);
616 if (r < 0)
617 return r;
618 }
619
2f4d31c1
YW
620 free_and_replace(p->path, k);
621 p->type = ltype;
916abb21 622
7a22745a 623 } else if (streq(lvalue, "ListenNetlink")) {
74051b9b 624 _cleanup_free_ char *k = NULL;
1fd45a90 625
06536492 626 r = unit_path_printf(UNIT(s), rvalue, &k);
12ca818f 627 if (r < 0) {
323dda78 628 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
12ca818f
LP
629 return 0;
630 }
7a22745a 631
12ca818f 632 r = socket_address_parse_netlink(&p->address, k);
1fd45a90 633 if (r < 0) {
323dda78 634 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse address value in '%s', ignoring: %m", k);
7a22745a
LP
635 return 0;
636 }
637
2f4d31c1
YW
638 p->type = SOCKET_SOCKET;
639
542563ba 640 } else {
74051b9b 641 _cleanup_free_ char *k = NULL;
1fd45a90 642
06536492 643 r = unit_path_printf(UNIT(s), rvalue, &k);
12ca818f 644 if (r < 0) {
323dda78 645 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
12ca818f
LP
646 return 0;
647 }
542563ba 648
4a66b5c9
LP
649 if (k[0] == '/') { /* Only for AF_UNIX file system sockets… */
650 r = patch_var_run(unit, filename, line, lvalue, &k);
651 if (r < 0)
652 return r;
653 }
654
12ca818f 655 r = socket_address_parse_and_warn(&p->address, k);
1fd45a90 656 if (r < 0) {
f847b8b7 657 if (r != -EAFNOSUPPORT)
323dda78 658 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse address value in '%s', ignoring: %m", k);
c0b34696 659 return 0;
542563ba
LP
660 }
661
662 if (streq(lvalue, "ListenStream"))
663 p->address.type = SOCK_STREAM;
664 else if (streq(lvalue, "ListenDatagram"))
665 p->address.type = SOCK_DGRAM;
666 else {
667 assert(streq(lvalue, "ListenSequentialPacket"));
668 p->address.type = SOCK_SEQPACKET;
669 }
670
618b3642 671 if (socket_address_family(&p->address) != AF_UNIX && p->address.type == SOCK_SEQPACKET) {
323dda78 672 log_syntax(unit, LOG_WARNING, filename, line, 0, "Address family not supported, ignoring: %s", rvalue);
c0b34696 673 return 0;
542563ba 674 }
2f4d31c1
YW
675
676 p->type = SOCKET_SOCKET;
16354eff
LP
677 }
678
254d1313 679 p->fd = -EBADF;
15087cdb
PS
680 p->auxiliary_fds = NULL;
681 p->n_auxiliary_fds = 0;
2e41a51e 682 p->socket = s;
49f91047 683
cc232fa0 684 tail = LIST_FIND_TAIL(port, s->ports);
533f8a67
YW
685 LIST_INSERT_AFTER(port, s->ports, tail, p);
686
b1389b0d 687 p = NULL;
542563ba 688
16354eff 689 return 0;
42f4e3c4
LP
690}
691
41bf0590
LP
692int config_parse_exec_nice(
693 const char *unit,
694 const char *filename,
695 unsigned line,
696 const char *section,
697 unsigned section_line,
698 const char *lvalue,
699 int ltype,
700 const char *rvalue,
701 void *data,
702 void *userdata) {
034c6ed7 703
99534007 704 ExecContext *c = ASSERT_PTR(data);
e8e581bf 705 int priority, r;
034c6ed7
LP
706
707 assert(filename);
708 assert(lvalue);
709 assert(rvalue);
034c6ed7 710
de5e6038
YW
711 if (isempty(rvalue)) {
712 c->nice_set = false;
713 return 0;
714 }
715
41bf0590 716 r = parse_nice(rvalue, &priority);
e8e581bf 717 if (r < 0) {
41bf0590 718 if (r == -ERANGE)
323dda78 719 log_syntax(unit, LOG_WARNING, filename, line, r, "Nice priority out of range, ignoring: %s", rvalue);
41bf0590 720 else
323dda78 721 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse nice priority '%s', ignoring: %m", rvalue);
c0b34696 722 return 0;
034c6ed7
LP
723 }
724
fb33a393 725 c->nice = priority;
71155933 726 c->nice_set = true;
fb33a393 727
034c6ed7
LP
728 return 0;
729}
730
e9eb2c02
LP
731int config_parse_exec_oom_score_adjust(
732 const char* unit,
733 const char *filename,
734 unsigned line,
735 const char *section,
736 unsigned section_line,
737 const char *lvalue,
738 int ltype,
739 const char *rvalue,
740 void *data,
741 void *userdata) {
034c6ed7 742
99534007 743 ExecContext *c = ASSERT_PTR(data);
e8e581bf 744 int oa, r;
034c6ed7
LP
745
746 assert(filename);
747 assert(lvalue);
748 assert(rvalue);
034c6ed7 749
e9eb2c02
LP
750 if (isempty(rvalue)) {
751 c->oom_score_adjust_set = false;
c0b34696 752 return 0;
034c6ed7
LP
753 }
754
e9eb2c02 755 r = parse_oom_score_adjust(rvalue, &oa);
e9eb2c02 756 if (r < 0) {
063c4b1a 757 if (r == -ERANGE)
323dda78 758 log_syntax(unit, LOG_WARNING, filename, line, r, "OOM score adjust value out of range, ignoring: %s", rvalue);
063c4b1a 759 else
323dda78 760 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse the OOM score adjust value '%s', ignoring: %m", rvalue);
c0b34696 761 return 0;
034c6ed7
LP
762 }
763
dd6c17b1
LP
764 c->oom_score_adjust = oa;
765 c->oom_score_adjust_set = true;
fb33a393 766
034c6ed7
LP
767 return 0;
768}
769
ad21e542
ZJS
770int config_parse_exec_coredump_filter(
771 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
99534007 782 ExecContext *c = ASSERT_PTR(data);
ad21e542
ZJS
783 int r;
784
785 assert(filename);
786 assert(lvalue);
787 assert(rvalue);
ad21e542
ZJS
788
789 if (isempty(rvalue)) {
790 c->coredump_filter = 0;
791 c->coredump_filter_set = false;
792 return 0;
793 }
794
795 uint64_t f;
796 r = coredump_filter_mask_from_string(rvalue, &f);
797 if (r < 0) {
798 log_syntax(unit, LOG_WARNING, filename, line, r,
799 "Failed to parse the CoredumpFilter=%s, ignoring: %m", rvalue);
800 return 0;
801 }
802
803 c->coredump_filter |= f;
9c669abb 804 c->coredump_filter_set = true;
ad21e542
ZJS
805 return 0;
806}
807
d068765b
LP
808int config_parse_kill_mode(
809 const char* unit,
810 const char *filename,
811 unsigned line,
812 const char *section,
813 unsigned section_line,
814 const char *lvalue,
815 int ltype,
816 const char *rvalue,
817 void *data,
818 void *userdata) {
819
820 KillMode *k = data, m;
821
822 assert(filename);
823 assert(lvalue);
824 assert(rvalue);
825 assert(data);
826
827 if (isempty(rvalue)) {
828 *k = KILL_CONTROL_GROUP;
829 return 0;
830 }
831
832 m = kill_mode_from_string(rvalue);
833 if (m < 0) {
b98680b2 834 log_syntax(unit, LOG_WARNING, filename, line, m,
d068765b
LP
835 "Failed to parse kill mode specification, ignoring: %s", rvalue);
836 return 0;
837 }
838
839 if (m == KILL_NONE)
840 log_syntax(unit, LOG_WARNING, filename, line, 0,
af9d5d50 841 "Unit uses KillMode=none. "
15e6a6e8 842 "This is unsafe, as it disables systemd's process lifecycle management for the service. "
af9d5d50 843 "Please update the service to use a safer KillMode=, such as 'mixed' or 'control-group'. "
d068765b
LP
844 "Support for KillMode=none is deprecated and will eventually be removed.");
845
846 *k = m;
847 return 0;
848}
849
527b7a42
LP
850int config_parse_exec(
851 const char *unit,
852 const char *filename,
853 unsigned line,
854 const char *section,
855 unsigned section_line,
856 const char *lvalue,
857 int ltype,
858 const char *rvalue,
859 void *data,
860 void *userdata) {
034c6ed7 861
99534007 862 ExecCommand **e = ASSERT_PTR(data);
47538b76 863 const Unit *u = userdata;
46a0d98a
FB
864 const char *p;
865 bool semicolon;
7f110ff9 866 int r;
034c6ed7
LP
867
868 assert(filename);
869 assert(lvalue);
870 assert(rvalue);
034c6ed7 871
74051b9b 872 e += ltype;
c83f1f30 873
74051b9b
LP
874 if (isempty(rvalue)) {
875 /* An empty assignment resets the list */
f1acf85a 876 *e = exec_command_free_list(*e);
74051b9b
LP
877 return 0;
878 }
879
bd1b973f 880 p = rvalue;
46a0d98a 881 do {
dea7b6b0 882 _cleanup_free_ char *path = NULL, *firstword = NULL;
165a31c0
LP
883 ExecCommandFlags flags = 0;
884 bool ignore = false, separate_argv0 = false;
dea7b6b0 885 _cleanup_free_ ExecCommand *nce = NULL;
46a0d98a 886 _cleanup_strv_free_ char **n = NULL;
319a4f4b 887 size_t nlen = 0;
5125e762 888 const char *f;
6c666e26 889
46a0d98a
FB
890 semicolon = false;
891
4ec85141 892 r = extract_first_word_and_warn(&p, &firstword, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE, unit, filename, line, rvalue);
46a0d98a
FB
893 if (r <= 0)
894 return 0;
6c666e26 895
598c47c8
ZJS
896 /* A lone ";" is a separator. Let's make sure we don't treat it as an executable name. */
897 if (streq(firstword, ";")) {
898 semicolon = true;
899 continue;
900 }
901
46a0d98a 902 f = firstword;
007f48bb 903 for (;;) {
165a31c0
LP
904 /* We accept an absolute path as first argument. If it's prefixed with - and the path doesn't
905 * exist, we ignore it instead of erroring out; if it's prefixed with @, we allow overriding of
7ca69792
AZ
906 * argv[0]; if it's prefixed with :, we will not do environment variable substitution;
907 * if it's prefixed with +, it will be run with full privileges and no sandboxing; if
165a31c0
LP
908 * it's prefixed with '!' we apply sandboxing, but do not change user/group credentials; if
909 * it's prefixed with '!!', then we apply user/group credentials if the kernel supports ambient
910 * capabilities -- if it doesn't we don't apply the credentials themselves, but do apply most
911 * other sandboxing, with some special exceptions for changing UID.
912 *
913 * The idea is that '!!' may be used to write services that can take benefit of systemd's
914 * UID/GID dropping if the kernel supports ambient creds, but provide an automatic fallback to
915 * privilege dropping within the daemon if the kernel does not offer that. */
916
917 if (*f == '-' && !(flags & EXEC_COMMAND_IGNORE_FAILURE)) {
918 flags |= EXEC_COMMAND_IGNORE_FAILURE;
46a0d98a 919 ignore = true;
165a31c0 920 } else if (*f == '@' && !separate_argv0)
46a0d98a 921 separate_argv0 = true;
7ca69792
AZ
922 else if (*f == ':' && !(flags & EXEC_COMMAND_NO_ENV_EXPAND))
923 flags |= EXEC_COMMAND_NO_ENV_EXPAND;
165a31c0
LP
924 else if (*f == '+' && !(flags & (EXEC_COMMAND_FULLY_PRIVILEGED|EXEC_COMMAND_NO_SETUID|EXEC_COMMAND_AMBIENT_MAGIC)))
925 flags |= EXEC_COMMAND_FULLY_PRIVILEGED;
926 else if (*f == '!' && !(flags & (EXEC_COMMAND_FULLY_PRIVILEGED|EXEC_COMMAND_NO_SETUID|EXEC_COMMAND_AMBIENT_MAGIC)))
927 flags |= EXEC_COMMAND_NO_SETUID;
928 else if (*f == '!' && !(flags & (EXEC_COMMAND_FULLY_PRIVILEGED|EXEC_COMMAND_AMBIENT_MAGIC))) {
929 flags &= ~EXEC_COMMAND_NO_SETUID;
930 flags |= EXEC_COMMAND_AMBIENT_MAGIC;
931 } else
46a0d98a 932 break;
313cefa1 933 f++;
61e5d8ed 934 }
46a0d98a 935
06536492 936 r = unit_path_printf(u, f, &path);
5125e762 937 if (r < 0) {
323dda78 938 log_syntax(unit, ignore ? LOG_WARNING : LOG_ERR, filename, line, r,
063c4b1a 939 "Failed to resolve unit specifiers in '%s'%s: %m",
bb28e684
ZJS
940 f, ignore ? ", ignoring" : "");
941 return ignore ? 0 : -ENOEXEC;
5125e762
LP
942 }
943
944 if (isempty(path)) {
46a0d98a 945 /* First word is either "-" or "@" with no command. */
323dda78 946 log_syntax(unit, ignore ? LOG_WARNING : LOG_ERR, filename, line, 0,
063c4b1a 947 "Empty path in command line%s: '%s'",
bb28e684
ZJS
948 ignore ? ", ignoring" : "", rvalue);
949 return ignore ? 0 : -ENOEXEC;
b2fadec6 950 }
5125e762 951 if (!string_is_safe(path)) {
323dda78 952 log_syntax(unit, ignore ? LOG_WARNING : LOG_ERR, filename, line, 0,
5008da1e
ZJS
953 "Executable name contains special characters%s: %s",
954 ignore ? ", ignoring" : "", path);
bb28e684 955 return ignore ? 0 : -ENOEXEC;
46a0d98a 956 }
5125e762 957 if (endswith(path, "/")) {
323dda78 958 log_syntax(unit, ignore ? LOG_WARNING : LOG_ERR, filename, line, 0,
bb28e684 959 "Executable path specifies a directory%s: %s",
5008da1e 960 ignore ? ", ignoring" : "", path);
bb28e684 961 return ignore ? 0 : -ENOEXEC;
46a0d98a 962 }
61e5d8ed 963
108144ad 964 if (!(path_is_absolute(path) ? path_is_valid(path) : filename_is_valid(path))) {
9f71ba8d
ZJS
965 log_syntax(unit, ignore ? LOG_WARNING : LOG_ERR, filename, line, 0,
966 "Neither a valid executable name nor an absolute path%s: %s",
967 ignore ? ", ignoring" : "", path);
968 return ignore ? 0 : -ENOEXEC;
5008da1e
ZJS
969 }
970
46a0d98a 971 if (!separate_argv0) {
5125e762
LP
972 char *w = NULL;
973
15092743 974 if (!GREEDY_REALLOC0(n, nlen + 2))
46a0d98a 975 return log_oom();
5125e762
LP
976
977 w = strdup(path);
978 if (!w)
46a0d98a 979 return log_oom();
5125e762 980 n[nlen++] = w;
46a0d98a
FB
981 n[nlen] = NULL;
982 }
7f110ff9 983
4ff361cc 984 path_simplify(path);
46a0d98a 985
4b1c1753 986 while (!isempty(p)) {
5125e762 987 _cleanup_free_ char *word = NULL, *resolved = NULL;
46a0d98a
FB
988
989 /* Check explicitly for an unquoted semicolon as
990 * command separator token. */
991 if (p[0] == ';' && (!p[1] || strchr(WHITESPACE, p[1]))) {
313cefa1 992 p++;
46a0d98a
FB
993 p += strspn(p, WHITESPACE);
994 semicolon = true;
995 break;
c8539536 996 }
7f110ff9 997
5125e762
LP
998 /* Check for \; explicitly, to not confuse it with \\; or "\;" or "\\;" etc.
999 * extract_first_word() would return the same for all of those. */
46a0d98a 1000 if (p[0] == '\\' && p[1] == ';' && (!p[2] || strchr(WHITESPACE, p[2]))) {
5125e762
LP
1001 char *w;
1002
46a0d98a
FB
1003 p += 2;
1004 p += strspn(p, WHITESPACE);
5125e762 1005
15092743 1006 if (!GREEDY_REALLOC0(n, nlen + 2))
46a0d98a 1007 return log_oom();
5125e762
LP
1008
1009 w = strdup(";");
1010 if (!w)
46a0d98a 1011 return log_oom();
5125e762 1012 n[nlen++] = w;
46a0d98a
FB
1013 n[nlen] = NULL;
1014 continue;
61e5d8ed 1015 }
c8539536 1016
4ec85141 1017 r = extract_first_word_and_warn(&p, &word, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE, unit, filename, line, rvalue);
46a0d98a
FB
1018 if (r == 0)
1019 break;
5125e762 1020 if (r < 0)
bb28e684 1021 return ignore ? 0 : -ENOEXEC;
5125e762 1022
58dd4999 1023 r = unit_full_printf(u, word, &resolved);
5125e762 1024 if (r < 0) {
323dda78 1025 log_syntax(unit, ignore ? LOG_WARNING : LOG_ERR, filename, line, r,
063c4b1a 1026 "Failed to resolve unit specifiers in %s%s: %m",
bb28e684
ZJS
1027 word, ignore ? ", ignoring" : "");
1028 return ignore ? 0 : -ENOEXEC;
5125e762 1029 }
46a0d98a 1030
319a4f4b 1031 if (!GREEDY_REALLOC(n, nlen + 2))
46a0d98a 1032 return log_oom();
1cc6c93a
YW
1033
1034 n[nlen++] = TAKE_PTR(resolved);
46a0d98a 1035 n[nlen] = NULL;
61e5d8ed
LP
1036 }
1037
46a0d98a 1038 if (!n || !n[0]) {
323dda78 1039 log_syntax(unit, ignore ? LOG_WARNING : LOG_ERR, filename, line, 0,
bb28e684
ZJS
1040 "Empty executable name or zeroeth argument%s: %s",
1041 ignore ? ", ignoring" : "", rvalue);
1042 return ignore ? 0 : -ENOEXEC;
7f110ff9 1043 }
6c666e26 1044
7f110ff9 1045 nce = new0(ExecCommand, 1);
46a0d98a
FB
1046 if (!nce)
1047 return log_oom();
61e5d8ed 1048
1cc6c93a
YW
1049 nce->argv = TAKE_PTR(n);
1050 nce->path = TAKE_PTR(path);
165a31c0 1051 nce->flags = flags;
034c6ed7 1052
61e5d8ed 1053 exec_command_append_list(e, nce);
01f78473 1054
46a0d98a 1055 /* Do not _cleanup_free_ these. */
46a0d98a 1056 nce = NULL;
034c6ed7 1057
46a0d98a
FB
1058 rvalue = p;
1059 } while (semicolon);
034c6ed7 1060
46a0d98a 1061 return 0;
034c6ed7
LP
1062}
1063
d31645ad
LP
1064int config_parse_socket_bindtodevice(
1065 const char* unit,
1066 const char *filename,
1067 unsigned line,
1068 const char *section,
1069 unsigned section_line,
1070 const char *lvalue,
1071 int ltype,
1072 const char *rvalue,
1073 void *data,
1074 void *userdata) {
acbb0225 1075
99534007 1076 Socket *s = ASSERT_PTR(data);
acbb0225
LP
1077
1078 assert(filename);
1079 assert(lvalue);
1080 assert(rvalue);
acbb0225 1081
063c4b1a
YW
1082 if (isempty(rvalue) || streq(rvalue, "*")) {
1083 s->bind_to_device = mfree(s->bind_to_device);
1084 return 0;
1085 }
d31645ad 1086
063c4b1a 1087 if (!ifname_valid(rvalue)) {
323dda78 1088 log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid interface name, ignoring: %s", rvalue);
063c4b1a
YW
1089 return 0;
1090 }
acbb0225 1091
b3f9c17a 1092 return free_and_strdup_warn(&s->bind_to_device, rvalue);
acbb0225
LP
1093}
1094
9bd6a50e
LP
1095int config_parse_exec_input(
1096 const char *unit,
1097 const char *filename,
1098 unsigned line,
1099 const char *section,
1100 unsigned section_line,
1101 const char *lvalue,
1102 int ltype,
1103 const char *rvalue,
1104 void *data,
1105 void *userdata) {
52c239d7 1106
99534007 1107 ExecContext *c = ASSERT_PTR(data);
47538b76 1108 const Unit *u = userdata;
2038c3f5
LP
1109 const char *n;
1110 ExecInput ei;
52c239d7
LB
1111 int r;
1112
52c239d7
LB
1113 assert(filename);
1114 assert(line);
1115 assert(rvalue);
1116
2038c3f5
LP
1117 n = startswith(rvalue, "fd:");
1118 if (n) {
1119 _cleanup_free_ char *resolved = NULL;
1120
06536492 1121 r = unit_fd_printf(u, n, &resolved);
323dda78
YW
1122 if (r < 0) {
1123 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", n);
1124 return 0;
1125 }
2038c3f5
LP
1126
1127 if (isempty(resolved))
1128 resolved = mfree(resolved);
1129 else if (!fdname_is_valid(resolved)) {
323dda78
YW
1130 log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid file descriptor name, ignoring: %s", resolved);
1131 return 0;
52c239d7 1132 }
9bd6a50e 1133
2038c3f5
LP
1134 free_and_replace(c->stdio_fdname[STDIN_FILENO], resolved);
1135
1136 ei = EXEC_INPUT_NAMED_FD;
1137
1138 } else if ((n = startswith(rvalue, "file:"))) {
1139 _cleanup_free_ char *resolved = NULL;
1140
06536492 1141 r = unit_path_printf(u, n, &resolved);
323dda78
YW
1142 if (r < 0) {
1143 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", n);
1144 return 0;
1145 }
9bd6a50e 1146
2f4d31c1
YW
1147 r = path_simplify_and_warn(resolved, PATH_CHECK_ABSOLUTE | PATH_CHECK_FATAL, unit, filename, line, lvalue);
1148 if (r < 0)
323dda78 1149 return 0;
2038c3f5
LP
1150
1151 free_and_replace(c->stdio_file[STDIN_FILENO], resolved);
1152
1153 ei = EXEC_INPUT_FILE;
9bd6a50e 1154
52c239d7 1155 } else {
9bd6a50e
LP
1156 ei = exec_input_from_string(rvalue);
1157 if (ei < 0) {
b98680b2 1158 log_syntax(unit, LOG_WARNING, filename, line, ei, "Failed to parse input specifier, ignoring: %s", rvalue);
9bd6a50e
LP
1159 return 0;
1160 }
52c239d7 1161 }
9bd6a50e 1162
2038c3f5 1163 c->std_input = ei;
9bd6a50e 1164 return 0;
52c239d7
LB
1165}
1166
08f3be7a
LP
1167int config_parse_exec_input_text(
1168 const char *unit,
1169 const char *filename,
1170 unsigned line,
1171 const char *section,
1172 unsigned section_line,
1173 const char *lvalue,
1174 int ltype,
1175 const char *rvalue,
1176 void *data,
1177 void *userdata) {
1178
1179 _cleanup_free_ char *unescaped = NULL, *resolved = NULL;
99534007 1180 ExecContext *c = ASSERT_PTR(data);
47538b76 1181 const Unit *u = userdata;
08f3be7a
LP
1182 int r;
1183
08f3be7a
LP
1184 assert(filename);
1185 assert(line);
1186 assert(rvalue);
1187
1188 if (isempty(rvalue)) {
1189 /* Reset if the empty string is assigned */
1190 c->stdin_data = mfree(c->stdin_data);
1191 c->stdin_data_size = 0;
52c239d7
LB
1192 return 0;
1193 }
08f3be7a 1194
e437538f
ZJS
1195 ssize_t l = cunescape(rvalue, 0, &unescaped);
1196 if (l < 0) {
1197 log_syntax(unit, LOG_WARNING, filename, line, l,
323dda78
YW
1198 "Failed to decode C escaped text '%s', ignoring: %m", rvalue);
1199 return 0;
1200 }
08f3be7a 1201
06536492 1202 r = unit_full_printf_full(u, unescaped, EXEC_STDIN_DATA_MAX, &resolved);
323dda78
YW
1203 if (r < 0) {
1204 log_syntax(unit, LOG_WARNING, filename, line, r,
1205 "Failed to resolve unit specifiers in '%s', ignoring: %m", unescaped);
1206 return 0;
1207 }
08f3be7a 1208
e437538f 1209 size_t sz = strlen(resolved);
08f3be7a
LP
1210 if (c->stdin_data_size + sz + 1 < c->stdin_data_size || /* check for overflow */
1211 c->stdin_data_size + sz + 1 > EXEC_STDIN_DATA_MAX) {
323dda78
YW
1212 log_syntax(unit, LOG_WARNING, filename, line, 0,
1213 "Standard input data too large (%zu), maximum of %zu permitted, ignoring.",
1214 c->stdin_data_size + sz, (size_t) EXEC_STDIN_DATA_MAX);
1215 return 0;
08f3be7a
LP
1216 }
1217
e437538f 1218 void *p = realloc(c->stdin_data, c->stdin_data_size + sz + 1);
08f3be7a
LP
1219 if (!p)
1220 return log_oom();
1221
1222 *((char*) mempcpy((char*) p + c->stdin_data_size, resolved, sz)) = '\n';
1223
1224 c->stdin_data = p;
1225 c->stdin_data_size += sz + 1;
1226
1227 return 0;
52c239d7
LB
1228}
1229
08f3be7a
LP
1230int config_parse_exec_input_data(
1231 const char *unit,
1232 const char *filename,
1233 unsigned line,
1234 const char *section,
1235 unsigned section_line,
1236 const char *lvalue,
1237 int ltype,
1238 const char *rvalue,
1239 void *data,
1240 void *userdata) {
1241
08f3be7a 1242 _cleanup_free_ void *p = NULL;
99534007 1243 ExecContext *c = ASSERT_PTR(data);
08f3be7a
LP
1244 size_t sz;
1245 void *q;
1246 int r;
1247
08f3be7a
LP
1248 assert(filename);
1249 assert(line);
1250 assert(rvalue);
1251
1252 if (isempty(rvalue)) {
1253 /* Reset if the empty string is assigned */
1254 c->stdin_data = mfree(c->stdin_data);
1255 c->stdin_data_size = 0;
1256 return 0;
1257 }
1258
f5fbe71d 1259 r = unbase64mem(rvalue, SIZE_MAX, &p, &sz);
323dda78
YW
1260 if (r < 0) {
1261 log_syntax(unit, LOG_WARNING, filename, line, r,
1262 "Failed to decode base64 data, ignoring: %s", rvalue);
1263 return 0;
1264 }
08f3be7a
LP
1265
1266 assert(sz > 0);
1267
1268 if (c->stdin_data_size + sz < c->stdin_data_size || /* check for overflow */
1269 c->stdin_data_size + sz > EXEC_STDIN_DATA_MAX) {
323dda78
YW
1270 log_syntax(unit, LOG_WARNING, filename, line, 0,
1271 "Standard input data too large (%zu), maximum of %zu permitted, ignoring.",
1272 c->stdin_data_size + sz, (size_t) EXEC_STDIN_DATA_MAX);
1273 return 0;
08f3be7a
LP
1274 }
1275
1276 q = realloc(c->stdin_data, c->stdin_data_size + sz);
1277 if (!q)
1278 return log_oom();
1279
1280 memcpy((uint8_t*) q + c->stdin_data_size, p, sz);
1281
1282 c->stdin_data = q;
1283 c->stdin_data_size += sz;
1284
1285 return 0;
1286}
1287
2038c3f5
LP
1288int config_parse_exec_output(
1289 const char *unit,
1290 const char *filename,
1291 unsigned line,
1292 const char *section,
1293 unsigned section_line,
1294 const char *lvalue,
1295 int ltype,
1296 const char *rvalue,
1297 void *data,
1298 void *userdata) {
1299
1300 _cleanup_free_ char *resolved = NULL;
1301 const char *n;
99534007 1302 ExecContext *c = ASSERT_PTR(data);
47538b76 1303 const Unit *u = userdata;
f3dc6af2 1304 bool obsolete = false;
52c239d7 1305 ExecOutput eo;
52c239d7
LB
1306 int r;
1307
52c239d7
LB
1308 assert(filename);
1309 assert(line);
1310 assert(lvalue);
1311 assert(rvalue);
1312
2038c3f5
LP
1313 n = startswith(rvalue, "fd:");
1314 if (n) {
06536492 1315 r = unit_fd_printf(u, n, &resolved);
323dda78
YW
1316 if (r < 0) {
1317 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in %s: %m", n);
1318 return 0;
1319 }
2038c3f5
LP
1320
1321 if (isempty(resolved))
1322 resolved = mfree(resolved);
1323 else if (!fdname_is_valid(resolved)) {
323dda78
YW
1324 log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid file descriptor name, ignoring: %s", resolved);
1325 return 0;
52c239d7 1326 }
2038c3f5 1327
52c239d7 1328 eo = EXEC_OUTPUT_NAMED_FD;
2038c3f5 1329
f3dc6af2
LP
1330 } else if (streq(rvalue, "syslog")) {
1331 eo = EXEC_OUTPUT_JOURNAL;
1332 obsolete = true;
1333
1334 } else if (streq(rvalue, "syslog+console")) {
1335 eo = EXEC_OUTPUT_JOURNAL_AND_CONSOLE;
1336 obsolete = true;
1337
2038c3f5
LP
1338 } else if ((n = startswith(rvalue, "file:"))) {
1339
06536492 1340 r = unit_path_printf(u, n, &resolved);
323dda78
YW
1341 if (r < 0) {
1342 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", n);
1343 return 0;
1344 }
2038c3f5 1345
2f4d31c1
YW
1346 r = path_simplify_and_warn(resolved, PATH_CHECK_ABSOLUTE | PATH_CHECK_FATAL, unit, filename, line, lvalue);
1347 if (r < 0)
323dda78 1348 return 0;
2038c3f5
LP
1349
1350 eo = EXEC_OUTPUT_FILE;
1351
566b7d23
ZD
1352 } else if ((n = startswith(rvalue, "append:"))) {
1353
06536492 1354 r = unit_path_printf(u, n, &resolved);
323dda78
YW
1355 if (r < 0) {
1356 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", n);
1357 return 0;
1358 }
566b7d23
ZD
1359
1360 r = path_simplify_and_warn(resolved, PATH_CHECK_ABSOLUTE | PATH_CHECK_FATAL, unit, filename, line, lvalue);
1361 if (r < 0)
323dda78 1362 return 0;
566b7d23
ZD
1363
1364 eo = EXEC_OUTPUT_FILE_APPEND;
8d7dab1f
LW
1365
1366 } else if ((n = startswith(rvalue, "truncate:"))) {
1367
06536492 1368 r = unit_path_printf(u, n, &resolved);
8d7dab1f
LW
1369 if (r < 0) {
1370 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", n);
1371 return 0;
1372 }
1373
1374 r = path_simplify_and_warn(resolved, PATH_CHECK_ABSOLUTE | PATH_CHECK_FATAL, unit, filename, line, lvalue);
1375 if (r < 0)
1376 return 0;
1377
1378 eo = EXEC_OUTPUT_FILE_TRUNCATE;
52c239d7
LB
1379 } else {
1380 eo = exec_output_from_string(rvalue);
2038c3f5 1381 if (eo < 0) {
b98680b2 1382 log_syntax(unit, LOG_WARNING, filename, line, eo, "Failed to parse output specifier, ignoring: %s", rvalue);
52c239d7
LB
1383 return 0;
1384 }
1385 }
1386
f3dc6af2
LP
1387 if (obsolete)
1388 log_syntax(unit, LOG_NOTICE, filename, line, 0,
1389 "Standard output type %s is obsolete, automatically updating to %s. Please update your unit file, and consider removing the setting altogether.",
1390 rvalue, exec_output_to_string(eo));
1391
52c239d7 1392 if (streq(lvalue, "StandardOutput")) {
2038c3f5
LP
1393 if (eo == EXEC_OUTPUT_NAMED_FD)
1394 free_and_replace(c->stdio_fdname[STDOUT_FILENO], resolved);
1395 else
1396 free_and_replace(c->stdio_file[STDOUT_FILENO], resolved);
1397
52c239d7 1398 c->std_output = eo;
2038c3f5 1399
52c239d7 1400 } else {
2038c3f5
LP
1401 assert(streq(lvalue, "StandardError"));
1402
1403 if (eo == EXEC_OUTPUT_NAMED_FD)
1404 free_and_replace(c->stdio_fdname[STDERR_FILENO], resolved);
1405 else
1406 free_and_replace(c->stdio_file[STDERR_FILENO], resolved);
1407
1408 c->std_error = eo;
52c239d7 1409 }
2038c3f5
LP
1410
1411 return 0;
52c239d7 1412}
87f0e418 1413
e8e581bf
ZJS
1414int config_parse_exec_io_class(const char *unit,
1415 const char *filename,
1416 unsigned line,
1417 const char *section,
71a61510 1418 unsigned section_line,
e8e581bf
ZJS
1419 const char *lvalue,
1420 int ltype,
1421 const char *rvalue,
1422 void *data,
1423 void *userdata) {
94f04347 1424
99534007 1425 ExecContext *c = ASSERT_PTR(data);
94f04347
LP
1426 int x;
1427
1428 assert(filename);
1429 assert(lvalue);
1430 assert(rvalue);
94f04347 1431
617d253a
YW
1432 if (isempty(rvalue)) {
1433 c->ioprio_set = false;
0692548c 1434 c->ioprio = IOPRIO_DEFAULT_CLASS_AND_PRIO;
617d253a
YW
1435 return 0;
1436 }
1437
f8b69d1d
MS
1438 x = ioprio_class_from_string(rvalue);
1439 if (x < 0) {
b98680b2 1440 log_syntax(unit, LOG_WARNING, filename, line, x, "Failed to parse IO scheduling class, ignoring: %s", rvalue);
c0b34696 1441 return 0;
0d87eb42 1442 }
94f04347 1443
ba7772fe 1444 c->ioprio = ioprio_normalize(ioprio_prio_value(x, ioprio_prio_data(c->ioprio)));
94f04347
LP
1445 c->ioprio_set = true;
1446
1447 return 0;
1448}
1449
e8e581bf
ZJS
1450int config_parse_exec_io_priority(const char *unit,
1451 const char *filename,
1452 unsigned line,
1453 const char *section,
71a61510 1454 unsigned section_line,
e8e581bf
ZJS
1455 const char *lvalue,
1456 int ltype,
1457 const char *rvalue,
1458 void *data,
1459 void *userdata) {
94f04347 1460
99534007 1461 ExecContext *c = ASSERT_PTR(data);
e8e581bf 1462 int i, r;
94f04347
LP
1463
1464 assert(filename);
1465 assert(lvalue);
1466 assert(rvalue);
94f04347 1467
617d253a
YW
1468 if (isempty(rvalue)) {
1469 c->ioprio_set = false;
0692548c 1470 c->ioprio = IOPRIO_DEFAULT_CLASS_AND_PRIO;
617d253a
YW
1471 return 0;
1472 }
1473
7f452159
LP
1474 r = ioprio_parse_priority(rvalue, &i);
1475 if (r < 0) {
323dda78 1476 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse IO priority, ignoring: %s", rvalue);
c0b34696 1477 return 0;
071830ff
LP
1478 }
1479
ba7772fe 1480 c->ioprio = ioprio_normalize(ioprio_prio_value(ioprio_prio_class(c->ioprio), i));
94f04347
LP
1481 c->ioprio_set = true;
1482
071830ff
LP
1483 return 0;
1484}
1485
e8e581bf
ZJS
1486int config_parse_exec_cpu_sched_policy(const char *unit,
1487 const char *filename,
1488 unsigned line,
1489 const char *section,
71a61510 1490 unsigned section_line,
e8e581bf
ZJS
1491 const char *lvalue,
1492 int ltype,
1493 const char *rvalue,
1494 void *data,
1495 void *userdata) {
9eba9da4 1496
99534007 1497 ExecContext *c = ASSERT_PTR(data);
94f04347
LP
1498 int x;
1499
1500 assert(filename);
1501 assert(lvalue);
1502 assert(rvalue);
94f04347 1503
b00e1a9e
YW
1504 if (isempty(rvalue)) {
1505 c->cpu_sched_set = false;
1506 c->cpu_sched_policy = SCHED_OTHER;
1507 c->cpu_sched_priority = 0;
1508 return 0;
1509 }
1510
f8b69d1d
MS
1511 x = sched_policy_from_string(rvalue);
1512 if (x < 0) {
b98680b2 1513 log_syntax(unit, LOG_WARNING, filename, line, x, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
c0b34696 1514 return 0;
0d87eb42 1515 }
94f04347
LP
1516
1517 c->cpu_sched_policy = x;
bb112710
HHPF
1518 /* Moving to or from real-time policy? We need to adjust the priority */
1519 c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x));
94f04347
LP
1520 c->cpu_sched_set = true;
1521
1522 return 0;
1523}
1524
5e98086d
ZJS
1525int config_parse_exec_mount_apivfs(const char *unit,
1526 const char *filename,
1527 unsigned line,
1528 const char *section,
1529 unsigned section_line,
1530 const char *lvalue,
1531 int ltype,
1532 const char *rvalue,
1533 void *data,
1534 void *userdata) {
1535
99534007 1536 ExecContext *c = ASSERT_PTR(data);
5e98086d
ZJS
1537 int k;
1538
1539 assert(filename);
1540 assert(lvalue);
1541 assert(rvalue);
5e98086d
ZJS
1542
1543 if (isempty(rvalue)) {
1544 c->mount_apivfs_set = false;
1545 c->mount_apivfs = false;
1546 return 0;
1547 }
1548
1549 k = parse_boolean(rvalue);
1550 if (k < 0) {
1551 log_syntax(unit, LOG_WARNING, filename, line, k,
1552 "Failed to parse boolean value, ignoring: %s",
1553 rvalue);
1554 return 0;
1555 }
1556
1557 c->mount_apivfs_set = true;
1558 c->mount_apivfs = k;
1559 return 0;
1560}
1561
b070c7c0
MS
1562int config_parse_numa_mask(const char *unit,
1563 const char *filename,
1564 unsigned line,
1565 const char *section,
1566 unsigned section_line,
1567 const char *lvalue,
1568 int ltype,
1569 const char *rvalue,
1570 void *data,
1571 void *userdata) {
1572 int r;
99534007 1573 NUMAPolicy *p = ASSERT_PTR(data);
b070c7c0
MS
1574
1575 assert(filename);
1576 assert(lvalue);
1577 assert(rvalue);
b070c7c0 1578
332d387f
MS
1579 if (streq(rvalue, "all")) {
1580 r = numa_mask_add_all(&p->nodes);
323dda78
YW
1581 if (r < 0)
1582 log_syntax(unit, LOG_WARNING, filename, line, r,
1583 "Failed to create NUMA mask representing \"all\" NUMA nodes, ignoring: %m");
332d387f
MS
1584 } else {
1585 r = parse_cpu_set_extend(rvalue, &p->nodes, true, unit, filename, line, lvalue);
323dda78
YW
1586 if (r < 0)
1587 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse NUMA node mask, ignoring: %s", rvalue);
b070c7c0
MS
1588 }
1589
323dda78 1590 return 0;
b070c7c0
MS
1591}
1592
e8e581bf
ZJS
1593int config_parse_exec_cpu_sched_prio(const char *unit,
1594 const char *filename,
1595 unsigned line,
1596 const char *section,
71a61510 1597 unsigned section_line,
e8e581bf
ZJS
1598 const char *lvalue,
1599 int ltype,
1600 const char *rvalue,
1601 void *data,
1602 void *userdata) {
9eba9da4 1603
99534007 1604 ExecContext *c = ASSERT_PTR(data);
40c05a34 1605 int i, r;
9eba9da4
LP
1606
1607 assert(filename);
1608 assert(lvalue);
1609 assert(rvalue);
9eba9da4 1610
e8e581bf
ZJS
1611 r = safe_atoi(rvalue, &i);
1612 if (r < 0) {
323dda78 1613 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse CPU scheduling priority, ignoring: %s", rvalue);
c0b34696 1614 return 0;
94f04347 1615 }
9eba9da4 1616
40c05a34
LB
1617 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0. Policy might be set later so
1618 * we do not check the precise range, but only the generic outer bounds. */
1619 if (i < 0 || i > 99) {
323dda78 1620 log_syntax(unit, LOG_WARNING, filename, line, 0, "CPU scheduling priority is out of range, ignoring: %s", rvalue);
bb112710
HHPF
1621 return 0;
1622 }
1623
94f04347
LP
1624 c->cpu_sched_priority = i;
1625 c->cpu_sched_set = true;
1626
1627 return 0;
1628}
1629
18d73705
LB
1630int config_parse_root_image_options(
1631 const char *unit,
1632 const char *filename,
1633 unsigned line,
1634 const char *section,
1635 unsigned section_line,
1636 const char *lvalue,
1637 int ltype,
1638 const char *rvalue,
1639 void *data,
1640 void *userdata) {
1641
1642 _cleanup_(mount_options_free_allp) MountOptions *options = NULL;
bc8d56d3 1643 _cleanup_strv_free_ char **l = NULL;
99534007 1644 ExecContext *c = ASSERT_PTR(data);
18d73705 1645 const Unit *u = userdata;
18d73705
LB
1646 int r;
1647
1648 assert(filename);
1649 assert(lvalue);
1650 assert(rvalue);
18d73705
LB
1651
1652 if (isempty(rvalue)) {
1653 c->root_image_options = mount_options_free_all(c->root_image_options);
1654 return 0;
1655 }
1656
bc8d56d3
LB
1657 r = strv_split_colon_pairs(&l, rvalue);
1658 if (r == -ENOMEM)
1659 return log_oom();
1660 if (r < 0) {
323dda78 1661 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse %s, ignoring: %s", lvalue, rvalue);
bc8d56d3
LB
1662 return 0;
1663 }
18d73705 1664
bc8d56d3 1665 STRV_FOREACH_PAIR(first, second, l) {
18d73705 1666 MountOptions *o = NULL;
9ece6444
LB
1667 _cleanup_free_ char *mount_options_resolved = NULL;
1668 const char *mount_options = NULL, *partition = "root";
569a0e42 1669 PartitionDesignator partition_designator;
18d73705 1670
9ece6444 1671 /* Format is either 'root:foo' or 'foo' (root is implied) */
bc8d56d3 1672 if (!isempty(*second)) {
9ece6444 1673 partition = *first;
bc8d56d3 1674 mount_options = *second;
18d73705 1675 } else
bc8d56d3 1676 mount_options = *first;
18d73705 1677
9ece6444
LB
1678 partition_designator = partition_designator_from_string(partition);
1679 if (partition_designator < 0) {
b98680b2
YW
1680 log_syntax(unit, LOG_WARNING, filename, line, partition_designator,
1681 "Invalid partition name %s, ignoring", partition);
18d73705
LB
1682 continue;
1683 }
18d73705
LB
1684 r = unit_full_printf(u, mount_options, &mount_options_resolved);
1685 if (r < 0) {
323dda78 1686 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", mount_options);
18d73705
LB
1687 continue;
1688 }
1689
1690 o = new(MountOptions, 1);
1691 if (!o)
1692 return log_oom();
1693 *o = (MountOptions) {
9ece6444 1694 .partition_designator = partition_designator,
18d73705
LB
1695 .options = TAKE_PTR(mount_options_resolved),
1696 };
9ece6444 1697 LIST_APPEND(mount_options, options, TAKE_PTR(o));
18d73705
LB
1698 }
1699
64903d18 1700 if (options)
18d73705 1701 LIST_JOIN(mount_options, c->root_image_options, options);
64903d18
ZJS
1702 else
1703 /* empty spaces/separators only */
1704 c->root_image_options = mount_options_free_all(c->root_image_options);
18d73705
LB
1705
1706 return 0;
1707}
1708
0389f4fa
LB
1709int config_parse_exec_root_hash(
1710 const char *unit,
1711 const char *filename,
1712 unsigned line,
1713 const char *section,
1714 unsigned section_line,
1715 const char *lvalue,
1716 int ltype,
1717 const char *rvalue,
1718 void *data,
1719 void *userdata) {
1720
1721 _cleanup_free_ void *roothash_decoded = NULL;
99534007 1722 ExecContext *c = ASSERT_PTR(data);
0389f4fa
LB
1723 size_t roothash_decoded_size = 0;
1724 int r;
1725
0389f4fa
LB
1726 assert(filename);
1727 assert(line);
1728 assert(rvalue);
1729
1730 if (isempty(rvalue)) {
1731 /* Reset if the empty string is assigned */
1732 c->root_hash_path = mfree(c->root_hash_path);
1733 c->root_hash = mfree(c->root_hash);
1734 c->root_hash_size = 0;
1735 return 0;
1736 }
1737
1738 if (path_is_absolute(rvalue)) {
1739 /* We have the path to a roothash to load and decode, eg: RootHash=/foo/bar.roothash */
1740 _cleanup_free_ char *p = NULL;
1741
1742 p = strdup(rvalue);
1743 if (!p)
1744 return -ENOMEM;
1745
1746 free_and_replace(c->root_hash_path, p);
1747 c->root_hash = mfree(c->root_hash);
1748 c->root_hash_size = 0;
1749 return 0;
1750 }
1751
1752 /* We have a roothash to decode, eg: RootHash=012345789abcdef */
1753 r = unhexmem(rvalue, strlen(rvalue), &roothash_decoded, &roothash_decoded_size);
323dda78
YW
1754 if (r < 0) {
1755 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to decode RootHash=, ignoring: %s", rvalue);
1756 return 0;
1757 }
1758 if (roothash_decoded_size < sizeof(sd_id128_t)) {
1759 log_syntax(unit, LOG_WARNING, filename, line, 0, "RootHash= is too short, ignoring: %s", rvalue);
1760 return 0;
1761 }
0389f4fa
LB
1762
1763 free_and_replace(c->root_hash, roothash_decoded);
1764 c->root_hash_size = roothash_decoded_size;
1765 c->root_hash_path = mfree(c->root_hash_path);
1766
1767 return 0;
1768}
1769
d4d55b0d
LB
1770int config_parse_exec_root_hash_sig(
1771 const char *unit,
1772 const char *filename,
1773 unsigned line,
1774 const char *section,
1775 unsigned section_line,
1776 const char *lvalue,
1777 int ltype,
1778 const char *rvalue,
1779 void *data,
1780 void *userdata) {
1781
1782 _cleanup_free_ void *roothash_sig_decoded = NULL;
1783 char *value;
99534007 1784 ExecContext *c = ASSERT_PTR(data);
d4d55b0d
LB
1785 size_t roothash_sig_decoded_size = 0;
1786 int r;
1787
d4d55b0d
LB
1788 assert(filename);
1789 assert(line);
1790 assert(rvalue);
1791
1792 if (isempty(rvalue)) {
1793 /* Reset if the empty string is assigned */
1794 c->root_hash_sig_path = mfree(c->root_hash_sig_path);
1795 c->root_hash_sig = mfree(c->root_hash_sig);
1796 c->root_hash_sig_size = 0;
1797 return 0;
1798 }
1799
1800 if (path_is_absolute(rvalue)) {
1801 /* We have the path to a roothash signature to load and decode, eg: RootHashSignature=/foo/bar.roothash.p7s */
1802 _cleanup_free_ char *p = NULL;
1803
1804 p = strdup(rvalue);
1805 if (!p)
323dda78 1806 return log_oom();
d4d55b0d
LB
1807
1808 free_and_replace(c->root_hash_sig_path, p);
1809 c->root_hash_sig = mfree(c->root_hash_sig);
1810 c->root_hash_sig_size = 0;
1811 return 0;
1812 }
1813
323dda78
YW
1814 if (!(value = startswith(rvalue, "base64:"))) {
1815 log_syntax(unit, LOG_WARNING, filename, line, 0,
1816 "Failed to decode RootHashSignature=, not a path but doesn't start with 'base64:', ignoring: %s", rvalue);
1817 return 0;
1818 }
d4d55b0d
LB
1819
1820 /* We have a roothash signature to decode, eg: RootHashSignature=base64:012345789abcdef */
1821 r = unbase64mem(value, strlen(value), &roothash_sig_decoded, &roothash_sig_decoded_size);
323dda78
YW
1822 if (r < 0) {
1823 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to decode RootHashSignature=, ignoring: %s", rvalue);
1824 return 0;
1825 }
d4d55b0d
LB
1826
1827 free_and_replace(c->root_hash_sig, roothash_sig_decoded);
1828 c->root_hash_sig_size = roothash_sig_decoded_size;
1829 c->root_hash_sig_path = mfree(c->root_hash_sig_path);
1830
1831 return 0;
1832}
1833
ca9169f4
YW
1834int config_parse_exec_cpu_affinity(
1835 const char *unit,
1836 const char *filename,
1837 unsigned line,
1838 const char *section,
1839 unsigned section_line,
1840 const char *lvalue,
1841 int ltype,
1842 const char *rvalue,
1843 void *data,
1844 void *userdata) {
94f04347 1845
99534007 1846 ExecContext *c = ASSERT_PTR(data);
54cfe9a7
FG
1847 const Unit *u = userdata;
1848 _cleanup_free_ char *k = NULL;
e2b2fb7f 1849 int r;
94f04347
LP
1850
1851 assert(filename);
1852 assert(lvalue);
1853 assert(rvalue);
94f04347 1854
e2b2fb7f
MS
1855 if (streq(rvalue, "numa")) {
1856 c->cpu_affinity_from_numa = true;
1857 cpu_set_reset(&c->cpu_set);
1858
1859 return 0;
1860 }
1861
54cfe9a7
FG
1862 r = unit_full_printf(u, rvalue, &k);
1863 if (r < 0) {
1864 log_syntax(unit, LOG_WARNING, filename, line, r,
1865 "Failed to resolve unit specifiers in '%s', ignoring: %m",
1866 rvalue);
1867 return 0;
1868 }
1869
1870 r = parse_cpu_set_extend(k, &c->cpu_set, true, unit, filename, line, lvalue);
e2b2fb7f
MS
1871 if (r >= 0)
1872 c->cpu_affinity_from_numa = false;
1873
ca9169f4 1874 return 0;
94f04347
LP
1875}
1876
a103496c 1877int config_parse_capability_set(
65dce264
LP
1878 const char *unit,
1879 const char *filename,
1880 unsigned line,
1881 const char *section,
1882 unsigned section_line,
1883 const char *lvalue,
1884 int ltype,
1885 const char *rvalue,
1886 void *data,
1887 void *userdata) {
94f04347 1888
99534007 1889 uint64_t *capability_set = ASSERT_PTR(data);
3fd5190b 1890 uint64_t sum = 0, initial, def;
260abb78 1891 bool invert = false;
dd1f5bd0 1892 int r;
94f04347
LP
1893
1894 assert(filename);
1895 assert(lvalue);
1896 assert(rvalue);
94f04347 1897
260abb78
LP
1898 if (rvalue[0] == '~') {
1899 invert = true;
1900 rvalue++;
1901 }
1902
3fd5190b
LP
1903 if (streq(lvalue, "CapabilityBoundingSet")) {
1904 initial = CAP_MASK_ALL; /* initialized to all bits on */
1905 def = CAP_MASK_UNSET; /* not set */
1906 } else
1907 def = initial = 0; /* All bits off */
260abb78 1908
dd1f5bd0 1909 r = capability_set_from_string(rvalue, &sum);
dd1f5bd0 1910 if (r < 0) {
323dda78 1911 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse %s= specifier '%s', ignoring: %m", lvalue, rvalue);
dd1f5bd0 1912 return 0;
94f04347 1913 }
9eba9da4 1914
3fd5190b 1915 if (sum == 0 || *capability_set == def)
c792ec2e
IP
1916 /* "", "~" or uninitialized data -> replace */
1917 *capability_set = invert ? ~sum : sum;
1918 else {
a103496c 1919 /* previous data -> merge */
c792ec2e
IP
1920 if (invert)
1921 *capability_set &= ~sum;
1922 else
1923 *capability_set |= sum;
1924 }
260abb78 1925
9eba9da4
LP
1926 return 0;
1927}
1928
5f8640fb
LP
1929int config_parse_exec_selinux_context(
1930 const char *unit,
1931 const char *filename,
1932 unsigned line,
1933 const char *section,
1934 unsigned section_line,
1935 const char *lvalue,
1936 int ltype,
1937 const char *rvalue,
1938 void *data,
1939 void *userdata) {
1940
99534007 1941 ExecContext *c = ASSERT_PTR(data);
47538b76 1942 const Unit *u = userdata;
5f8640fb
LP
1943 bool ignore;
1944 char *k;
1945 int r;
1946
1947 assert(filename);
1948 assert(lvalue);
1949 assert(rvalue);
5f8640fb
LP
1950
1951 if (isempty(rvalue)) {
a1e58e8e 1952 c->selinux_context = mfree(c->selinux_context);
5f8640fb
LP
1953 c->selinux_context_ignore = false;
1954 return 0;
1955 }
1956
1957 if (rvalue[0] == '-') {
1958 ignore = true;
1959 rvalue++;
1960 } else
1961 ignore = false;
1962
18913df9 1963 r = unit_full_printf(u, rvalue, &k);
5f8640fb 1964 if (r < 0) {
323dda78 1965 log_syntax(unit, ignore ? LOG_WARNING : LOG_ERR, filename, line, r,
063c4b1a
YW
1966 "Failed to resolve unit specifiers in '%s'%s: %m",
1967 rvalue, ignore ? ", ignoring" : "");
bb28e684 1968 return ignore ? 0 : -ENOEXEC;
5f8640fb
LP
1969 }
1970
063c4b1a 1971 free_and_replace(c->selinux_context, k);
5f8640fb
LP
1972 c->selinux_context_ignore = ignore;
1973
1974 return 0;
1975}
1976
eef65bf3
MS
1977int config_parse_exec_apparmor_profile(
1978 const char *unit,
1979 const char *filename,
1980 unsigned line,
1981 const char *section,
1982 unsigned section_line,
1983 const char *lvalue,
1984 int ltype,
1985 const char *rvalue,
1986 void *data,
1987 void *userdata) {
1988
99534007 1989 ExecContext *c = ASSERT_PTR(data);
47538b76 1990 const Unit *u = userdata;
eef65bf3
MS
1991 bool ignore;
1992 char *k;
1993 int r;
1994
1995 assert(filename);
1996 assert(lvalue);
1997 assert(rvalue);
eef65bf3
MS
1998
1999 if (isempty(rvalue)) {
a1e58e8e 2000 c->apparmor_profile = mfree(c->apparmor_profile);
eef65bf3
MS
2001 c->apparmor_profile_ignore = false;
2002 return 0;
2003 }
2004
2005 if (rvalue[0] == '-') {
2006 ignore = true;
2007 rvalue++;
2008 } else
2009 ignore = false;
2010
18913df9 2011 r = unit_full_printf(u, rvalue, &k);
eef65bf3 2012 if (r < 0) {
323dda78 2013 log_syntax(unit, ignore ? LOG_WARNING : LOG_ERR, filename, line, r,
063c4b1a
YW
2014 "Failed to resolve unit specifiers in '%s'%s: %m",
2015 rvalue, ignore ? ", ignoring" : "");
bb28e684 2016 return ignore ? 0 : -ENOEXEC;
eef65bf3
MS
2017 }
2018
063c4b1a 2019 free_and_replace(c->apparmor_profile, k);
eef65bf3
MS
2020 c->apparmor_profile_ignore = ignore;
2021
2022 return 0;
2023}
2024
2ca620c4
WC
2025int config_parse_exec_smack_process_label(
2026 const char *unit,
2027 const char *filename,
2028 unsigned line,
2029 const char *section,
2030 unsigned section_line,
2031 const char *lvalue,
2032 int ltype,
2033 const char *rvalue,
2034 void *data,
2035 void *userdata) {
2036
99534007 2037 ExecContext *c = ASSERT_PTR(data);
47538b76 2038 const Unit *u = userdata;
2ca620c4
WC
2039 bool ignore;
2040 char *k;
2041 int r;
2042
2043 assert(filename);
2044 assert(lvalue);
2045 assert(rvalue);
2ca620c4
WC
2046
2047 if (isempty(rvalue)) {
a1e58e8e 2048 c->smack_process_label = mfree(c->smack_process_label);
2ca620c4
WC
2049 c->smack_process_label_ignore = false;
2050 return 0;
2051 }
2052
2053 if (rvalue[0] == '-') {
2054 ignore = true;
2055 rvalue++;
2056 } else
2057 ignore = false;
2058
18913df9 2059 r = unit_full_printf(u, rvalue, &k);
2ca620c4 2060 if (r < 0) {
323dda78 2061 log_syntax(unit, ignore ? LOG_WARNING : LOG_ERR, filename, line, r,
063c4b1a
YW
2062 "Failed to resolve unit specifiers in '%s'%s: %m",
2063 rvalue, ignore ? ", ignoring" : "");
bb28e684 2064 return ignore ? 0 : -ENOEXEC;
2ca620c4
WC
2065 }
2066
063c4b1a 2067 free_and_replace(c->smack_process_label, k);
2ca620c4
WC
2068 c->smack_process_label_ignore = ignore;
2069
2070 return 0;
2071}
2072
25a04ae5
LP
2073int config_parse_timer(
2074 const char *unit,
2075 const char *filename,
2076 unsigned line,
2077 const char *section,
2078 unsigned section_line,
2079 const char *lvalue,
2080 int ltype,
2081 const char *rvalue,
2082 void *data,
2083 void *userdata) {
871d7de4 2084
25a04ae5
LP
2085 _cleanup_(calendar_spec_freep) CalendarSpec *c = NULL;
2086 _cleanup_free_ char *k = NULL;
47538b76 2087 const Unit *u = userdata;
99534007 2088 Timer *t = ASSERT_PTR(data);
2507992f 2089 usec_t usec = 0;
871d7de4 2090 TimerValue *v;
2507992f 2091 int r;
871d7de4
LP
2092
2093 assert(filename);
2094 assert(lvalue);
2095 assert(rvalue);
871d7de4 2096
74051b9b
LP
2097 if (isempty(rvalue)) {
2098 /* Empty assignment resets list */
2099 timer_free_values(t);
2100 return 0;
2101 }
2102
2507992f
DC
2103 r = unit_full_printf(u, rvalue, &k);
2104 if (r < 0) {
323dda78 2105 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
2507992f
DC
2106 return 0;
2107 }
2108
25a04ae5 2109 if (ltype == TIMER_CALENDAR) {
dc44c96d
LP
2110 r = calendar_spec_from_string(k, &c);
2111 if (r < 0) {
323dda78 2112 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse calendar specification, ignoring: %s", k);
36697dc0
LP
2113 return 0;
2114 }
dc44c96d
LP
2115 } else {
2116 r = parse_sec(k, &usec);
2117 if (r < 0) {
323dda78 2118 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse timer value, ignoring: %s", k);
36697dc0
LP
2119 return 0;
2120 }
dc44c96d 2121 }
871d7de4 2122
25a04ae5 2123 v = new(TimerValue, 1);
921b5987 2124 if (!v)
74051b9b 2125 return log_oom();
871d7de4 2126
25a04ae5
LP
2127 *v = (TimerValue) {
2128 .base = ltype,
2129 .value = usec,
2130 .calendar_spec = TAKE_PTR(c),
2131 };
871d7de4 2132
71fda00f 2133 LIST_PREPEND(value, t->values, v);
871d7de4
LP
2134
2135 return 0;
2136}
2137
3ecaa09b
LP
2138int config_parse_trigger_unit(
2139 const char *unit,
2140 const char *filename,
2141 unsigned line,
2142 const char *section,
71a61510 2143 unsigned section_line,
3ecaa09b
LP
2144 const char *lvalue,
2145 int ltype,
2146 const char *rvalue,
2147 void *data,
2148 void *userdata) {
871d7de4 2149
74051b9b 2150 _cleanup_free_ char *p = NULL;
99534007 2151 Unit *u = ASSERT_PTR(data);
3ecaa09b
LP
2152 UnitType type;
2153 int r;
398ef8ba
LP
2154
2155 assert(filename);
2156 assert(lvalue);
2157 assert(rvalue);
398ef8ba 2158
bc32241e 2159 if (UNIT_TRIGGER(u)) {
323dda78 2160 log_syntax(unit, LOG_WARNING, filename, line, 0, "Multiple units to trigger specified, ignoring: %s", rvalue);
3ecaa09b
LP
2161 return 0;
2162 }
871d7de4 2163
19f6d710 2164 r = unit_name_printf(u, rvalue, &p);
12ca818f 2165 if (r < 0) {
323dda78 2166 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue);
12ca818f
LP
2167 return 0;
2168 }
74051b9b 2169
12ca818f 2170 type = unit_name_to_type(p);
3ecaa09b 2171 if (type < 0) {
b98680b2 2172 log_syntax(unit, LOG_WARNING, filename, line, type, "Unit type not valid, ignoring: %s", rvalue);
c0b34696 2173 return 0;
871d7de4 2174 }
49219a1c 2175 if (unit_has_name(u, p)) {
323dda78 2176 log_syntax(unit, LOG_WARNING, filename, line, 0, "Units cannot trigger themselves, ignoring: %s", rvalue);
3ecaa09b
LP
2177 return 0;
2178 }
2179
5a724170 2180 r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p, true, UNIT_DEPENDENCY_FILE);
57020a3a 2181 if (r < 0) {
323dda78 2182 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to add trigger on %s, ignoring: %m", p);
c0b34696 2183 return 0;
871d7de4
LP
2184 }
2185
2186 return 0;
2187}
2188
e8e581bf
ZJS
2189int config_parse_path_spec(const char *unit,
2190 const char *filename,
2191 unsigned line,
2192 const char *section,
71a61510 2193 unsigned section_line,
e8e581bf
ZJS
2194 const char *lvalue,
2195 int ltype,
2196 const char *rvalue,
2197 void *data,
2198 void *userdata) {
01f78473 2199
99534007 2200 Path *p = ASSERT_PTR(data);
01f78473
LP
2201 PathSpec *s;
2202 PathType b;
7fd1b19b 2203 _cleanup_free_ char *k = NULL;
19f6d710 2204 int r;
01f78473
LP
2205
2206 assert(filename);
2207 assert(lvalue);
2208 assert(rvalue);
01f78473 2209
74051b9b
LP
2210 if (isempty(rvalue)) {
2211 /* Empty assignment clears list */
2212 path_free_specs(p);
2213 return 0;
2214 }
2215
93e4c84b
LP
2216 b = path_type_from_string(lvalue);
2217 if (b < 0) {
b98680b2 2218 log_syntax(unit, LOG_WARNING, filename, line, b, "Failed to parse path type, ignoring: %s", lvalue);
c0b34696 2219 return 0;
01f78473
LP
2220 }
2221
06536492 2222 r = unit_path_printf(UNIT(p), rvalue, &k);
19f6d710 2223 if (r < 0) {
323dda78 2224 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue);
12ca818f 2225 return 0;
487060c2 2226 }
93e4c84b 2227
2f4d31c1
YW
2228 r = path_simplify_and_warn(k, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
2229 if (r < 0)
c0b34696 2230 return 0;
01f78473 2231
93e4c84b 2232 s = new0(PathSpec, 1);
543295ad 2233 if (!s)
93e4c84b 2234 return log_oom();
01f78473 2235
718db961 2236 s->unit = UNIT(p);
063c4b1a 2237 s->path = TAKE_PTR(k);
01f78473 2238 s->type = b;
254d1313 2239 s->inotify_fd = -EBADF;
01f78473 2240
71fda00f 2241 LIST_PREPEND(spec, p->specs, s);
01f78473
LP
2242
2243 return 0;
2244}
2245
b02cb41c
LP
2246int config_parse_socket_service(
2247 const char *unit,
2248 const char *filename,
2249 unsigned line,
2250 const char *section,
2251 unsigned section_line,
2252 const char *lvalue,
2253 int ltype,
2254 const char *rvalue,
2255 void *data,
2256 void *userdata) {
d9ff321a 2257
4afd3348 2258 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
8dd4c05b 2259 _cleanup_free_ char *p = NULL;
99534007 2260 Socket *s = ASSERT_PTR(data);
4ff77f66 2261 Unit *x;
8dd4c05b 2262 int r;
d9ff321a
LP
2263
2264 assert(filename);
2265 assert(lvalue);
2266 assert(rvalue);
d9ff321a 2267
19f6d710 2268 r = unit_name_printf(UNIT(s), rvalue, &p);
613b411c 2269 if (r < 0) {
323dda78
YW
2270 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue);
2271 return 0;
613b411c 2272 }
74051b9b 2273
613b411c 2274 if (!endswith(p, ".service")) {
323dda78
YW
2275 log_syntax(unit, LOG_WARNING, filename, line, 0, "Unit must be of type service, ignoring: %s", rvalue);
2276 return 0;
d9ff321a
LP
2277 }
2278
613b411c 2279 r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
4ff77f66 2280 if (r < 0) {
323dda78
YW
2281 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
2282 return 0;
d9ff321a
LP
2283 }
2284
7f7d01ed 2285 unit_ref_set(&s->service, UNIT(s), x);
4ff77f66 2286
d9ff321a
LP
2287 return 0;
2288}
2289
8dd4c05b
LP
2290int config_parse_fdname(
2291 const char *unit,
2292 const char *filename,
2293 unsigned line,
2294 const char *section,
2295 unsigned section_line,
2296 const char *lvalue,
2297 int ltype,
2298 const char *rvalue,
2299 void *data,
2300 void *userdata) {
2301
2302 _cleanup_free_ char *p = NULL;
99534007 2303 Socket *s = ASSERT_PTR(data);
8dd4c05b
LP
2304 int r;
2305
2306 assert(filename);
2307 assert(lvalue);
2308 assert(rvalue);
8dd4c05b
LP
2309
2310 if (isempty(rvalue)) {
2311 s->fdname = mfree(s->fdname);
2312 return 0;
2313 }
2314
06536492 2315 r = unit_fd_printf(UNIT(s), rvalue, &p);
8dd4c05b 2316 if (r < 0) {
323dda78 2317 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
8dd4c05b
LP
2318 return 0;
2319 }
2320
2321 if (!fdname_is_valid(p)) {
323dda78 2322 log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid file descriptor name, ignoring: %s", p);
8dd4c05b
LP
2323 return 0;
2324 }
2325
3b319885 2326 return free_and_replace(s->fdname, p);
8dd4c05b
LP
2327}
2328
b02cb41c
LP
2329int config_parse_service_sockets(
2330 const char *unit,
2331 const char *filename,
2332 unsigned line,
2333 const char *section,
2334 unsigned section_line,
2335 const char *lvalue,
2336 int ltype,
2337 const char *rvalue,
2338 void *data,
2339 void *userdata) {
f976f3f6 2340
99534007 2341 Service *s = ASSERT_PTR(data);
b02cb41c 2342 int r;
f976f3f6
LP
2343
2344 assert(filename);
2345 assert(lvalue);
2346 assert(rvalue);
f976f3f6 2347
323dda78 2348 for (const char *p = rvalue;;) {
6a0f3175 2349 _cleanup_free_ char *word = NULL, *k = NULL;
f976f3f6 2350
7b2313f5 2351 r = extract_first_word(&p, &word, NULL, 0);
7b2313f5 2352 if (r == -ENOMEM)
74051b9b 2353 return log_oom();
7b2313f5 2354 if (r < 0) {
323dda78
YW
2355 log_syntax(unit, LOG_WARNING, filename, line, r, "Trailing garbage in sockets, ignoring: %s", rvalue);
2356 return 0;
7b2313f5 2357 }
a687f500
ZJS
2358 if (r == 0)
2359 return 0;
f976f3f6 2360
7b2313f5 2361 r = unit_name_printf(UNIT(s), word, &k);
b02cb41c 2362 if (r < 0) {
323dda78 2363 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", word);
b02cb41c
LP
2364 continue;
2365 }
57020a3a 2366
b02cb41c 2367 if (!endswith(k, ".socket")) {
323dda78 2368 log_syntax(unit, LOG_WARNING, filename, line, 0, "Unit must be of type socket, ignoring: %s", k);
f976f3f6
LP
2369 continue;
2370 }
2371
5a724170 2372 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, true, UNIT_DEPENDENCY_FILE);
57020a3a 2373 if (r < 0)
323dda78 2374 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
f976f3f6 2375
35d8c19a 2376 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, true, UNIT_DEPENDENCY_FILE);
57020a3a 2377 if (r < 0)
323dda78 2378 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
f976f3f6 2379 }
f976f3f6
LP
2380}
2381
b02cb41c
LP
2382int config_parse_bus_name(
2383 const char *unit,
2384 const char *filename,
2385 unsigned line,
2386 const char *section,
2387 unsigned section_line,
2388 const char *lvalue,
2389 int ltype,
2390 const char *rvalue,
2391 void *data,
2392 void *userdata) {
2393
2394 _cleanup_free_ char *k = NULL;
99534007 2395 const Unit *u = ASSERT_PTR(userdata);
b02cb41c
LP
2396 int r;
2397
2398 assert(filename);
2399 assert(lvalue);
2400 assert(rvalue);
b02cb41c 2401
06536492 2402 r = unit_full_printf_full(u, rvalue, SD_BUS_MAXIMUM_NAME_LENGTH, &k);
b02cb41c 2403 if (r < 0) {
323dda78 2404 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue);
b02cb41c
LP
2405 return 0;
2406 }
2407
5453a4b1 2408 if (!sd_bus_service_name_is_valid(k)) {
323dda78 2409 log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid bus name, ignoring: %s", k);
b02cb41c
LP
2410 return 0;
2411 }
2412
2413 return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
2414}
2415
aad41f08
LP
2416int config_parse_service_timeout(
2417 const char *unit,
2418 const char *filename,
2419 unsigned line,
2420 const char *section,
2421 unsigned section_line,
2422 const char *lvalue,
2423 int ltype,
2424 const char *rvalue,
2425 void *data,
2426 void *userdata) {
98709151 2427
99534007 2428 Service *s = ASSERT_PTR(userdata);
aad41f08 2429 usec_t usec;
98709151
LN
2430 int r;
2431
2432 assert(filename);
2433 assert(lvalue);
2434 assert(rvalue);
98709151 2435
6c58305a 2436 /* This is called for two cases: TimeoutSec= and TimeoutStartSec=. */
98709151 2437
fb27be3f
YW
2438 /* Traditionally, these options accepted 0 to disable the timeouts. However, a timeout of 0 suggests it happens
2439 * immediately, hence fix this to become USEC_INFINITY instead. This is in-line with how we internally handle
2440 * all other timeouts. */
2441 r = parse_sec_fix_0(rvalue, &usec);
aad41f08 2442 if (r < 0) {
323dda78 2443 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse %s= parameter, ignoring: %s", lvalue, rvalue);
aad41f08
LP
2444 return 0;
2445 }
d568a335 2446
6c58305a
YW
2447 s->start_timeout_defined = true;
2448 s->timeout_start_usec = usec;
36c16a7c 2449
6c58305a 2450 if (streq(lvalue, "TimeoutSec"))
aad41f08 2451 s->timeout_stop_usec = usec;
36c16a7c 2452
d568a335 2453 return 0;
98709151
LN
2454}
2455
a61d6874 2456int config_parse_timeout_abort(
dc653bf4
JK
2457 const char *unit,
2458 const char *filename,
2459 unsigned line,
2460 const char *section,
2461 unsigned section_line,
2462 const char *lvalue,
2463 int ltype,
2464 const char *rvalue,
2465 void *data,
2466 void *userdata) {
2467
99534007 2468 usec_t *ret = ASSERT_PTR(data);
dc653bf4
JK
2469 int r;
2470
2471 assert(filename);
2472 assert(lvalue);
2473 assert(rvalue);
a61d6874
ZJS
2474
2475 /* Note: apart from setting the arg, this returns an extra bit of information in the return value. */
dc653bf4 2476
dc653bf4 2477 if (isempty(rvalue)) {
a61d6874
ZJS
2478 *ret = 0;
2479 return 0; /* "not set" */
dc653bf4
JK
2480 }
2481
a61d6874
ZJS
2482 r = parse_sec(rvalue, ret);
2483 if (r < 0)
323dda78 2484 return log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse %s= setting, ignoring: %s", lvalue, rvalue);
a61d6874
ZJS
2485
2486 return 1; /* "set" */
2487}
2488
2489int config_parse_service_timeout_abort(
2490 const char *unit,
2491 const char *filename,
2492 unsigned line,
2493 const char *section,
2494 unsigned section_line,
2495 const char *lvalue,
2496 int ltype,
2497 const char *rvalue,
2498 void *data,
2499 void *userdata) {
2500
99534007 2501 Service *s = ASSERT_PTR(userdata);
a61d6874 2502 int r;
dc653bf4 2503
a61d6874
ZJS
2504 r = config_parse_timeout_abort(unit, filename, line, section, section_line, lvalue, ltype, rvalue,
2505 &s->timeout_abort_usec, s);
2506 if (r >= 0)
2507 s->timeout_abort_set = r;
dc653bf4
JK
2508 return 0;
2509}
2510
ae480f0b 2511int config_parse_user_group_compat(
66dccd8d
LP
2512 const char *unit,
2513 const char *filename,
2514 unsigned line,
2515 const char *section,
2516 unsigned section_line,
2517 const char *lvalue,
2518 int ltype,
2519 const char *rvalue,
2520 void *data,
2521 void *userdata) {
2522
063c4b1a
YW
2523 _cleanup_free_ char *k = NULL;
2524 char **user = data;
99534007 2525 const Unit *u = ASSERT_PTR(userdata);
66dccd8d
LP
2526 int r;
2527
2528 assert(filename);
2529 assert(lvalue);
2530 assert(rvalue);
66dccd8d 2531
063c4b1a
YW
2532 if (isempty(rvalue)) {
2533 *user = mfree(*user);
2534 return 0;
2535 }
66dccd8d 2536
063c4b1a
YW
2537 r = unit_full_printf(u, rvalue, &k);
2538 if (r < 0) {
2539 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s: %m", rvalue);
2540 return -ENOEXEC;
66dccd8d
LP
2541 }
2542
7a8867ab 2543 if (!valid_user_group_name(k, VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX|VALID_USER_WARN)) {
063c4b1a
YW
2544 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid user/group name or numeric ID: %s", k);
2545 return -ENOEXEC;
2546 }
66dccd8d 2547
bed0b7df
LP
2548 if (strstr(lvalue, "User") && streq(k, NOBODY_USER_NAME))
2549 log_struct(LOG_NOTICE,
2550 "MESSAGE=%s:%u: Special user %s configured, this is not safe!", filename, line, k,
2551 "UNIT=%s", unit,
2552 "MESSAGE_ID=" SD_MESSAGE_NOBODY_USER_UNSUITABLE_STR,
2553 "OFFENDING_USER=%s", k,
2554 "CONFIG_FILE=%s", filename,
2555 "CONFIG_LINE=%u", line);
2556
063c4b1a 2557 return free_and_replace(*user, k);
66dccd8d
LP
2558}
2559
ae480f0b 2560int config_parse_user_group_strv_compat(
66dccd8d
LP
2561 const char *unit,
2562 const char *filename,
2563 unsigned line,
2564 const char *section,
2565 unsigned section_line,
2566 const char *lvalue,
2567 int ltype,
2568 const char *rvalue,
2569 void *data,
2570 void *userdata) {
2571
2572 char ***users = data;
99534007 2573 const Unit *u = ASSERT_PTR(userdata);
66dccd8d
LP
2574 int r;
2575
2576 assert(filename);
2577 assert(lvalue);
2578 assert(rvalue);
66dccd8d
LP
2579
2580 if (isempty(rvalue)) {
9f2d41a6 2581 *users = strv_free(*users);
66dccd8d
LP
2582 return 0;
2583 }
2584
323dda78 2585 for (const char *p = rvalue;;) {
66dccd8d
LP
2586 _cleanup_free_ char *word = NULL, *k = NULL;
2587
9a82ab95 2588 r = extract_first_word(&p, &word, NULL, 0);
66dccd8d
LP
2589 if (r == -ENOMEM)
2590 return log_oom();
2591 if (r < 0) {
bb28e684
ZJS
2592 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax: %s", rvalue);
2593 return -ENOEXEC;
66dccd8d 2594 }
a687f500
ZJS
2595 if (r == 0)
2596 return 0;
66dccd8d
LP
2597
2598 r = unit_full_printf(u, word, &k);
2599 if (r < 0) {
bb28e684
ZJS
2600 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s: %m", word);
2601 return -ENOEXEC;
66dccd8d
LP
2602 }
2603
7a8867ab 2604 if (!valid_user_group_name(k, VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX|VALID_USER_WARN)) {
bb28e684
ZJS
2605 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid user/group name or numeric ID: %s", k);
2606 return -ENOEXEC;
66dccd8d
LP
2607 }
2608
2609 r = strv_push(users, k);
2610 if (r < 0)
2611 return log_oom();
2612
2613 k = NULL;
2614 }
66dccd8d
LP
2615}
2616
5f5d8eab
LP
2617int config_parse_working_directory(
2618 const char *unit,
2619 const char *filename,
2620 unsigned line,
2621 const char *section,
2622 unsigned section_line,
2623 const char *lvalue,
2624 int ltype,
2625 const char *rvalue,
2626 void *data,
2627 void *userdata) {
2628
99534007
DT
2629 ExecContext *c = ASSERT_PTR(data);
2630 const Unit *u = ASSERT_PTR(userdata);
5f5d8eab
LP
2631 bool missing_ok;
2632 int r;
2633
2634 assert(filename);
2635 assert(lvalue);
2636 assert(rvalue);
5f5d8eab 2637
862fcffd
YW
2638 if (isempty(rvalue)) {
2639 c->working_directory_home = false;
2640 c->working_directory = mfree(c->working_directory);
2641 return 0;
2642 }
2643
5f5d8eab
LP
2644 if (rvalue[0] == '-') {
2645 missing_ok = true;
2646 rvalue++;
2647 } else
2648 missing_ok = false;
2649
2650 if (streq(rvalue, "~")) {
2651 c->working_directory_home = true;
2652 c->working_directory = mfree(c->working_directory);
2653 } else {
2654 _cleanup_free_ char *k = NULL;
2655
06536492 2656 r = unit_path_printf(u, rvalue, &k);
5f5d8eab 2657 if (r < 0) {
323dda78 2658 log_syntax(unit, missing_ok ? LOG_WARNING : LOG_ERR, filename, line, r,
bb28e684
ZJS
2659 "Failed to resolve unit specifiers in working directory path '%s'%s: %m",
2660 rvalue, missing_ok ? ", ignoring" : "");
2661 return missing_ok ? 0 : -ENOEXEC;
5f5d8eab
LP
2662 }
2663
2f4d31c1
YW
2664 r = path_simplify_and_warn(k, PATH_CHECK_ABSOLUTE | (missing_ok ? 0 : PATH_CHECK_FATAL), unit, filename, line, lvalue);
2665 if (r < 0)
bb28e684 2666 return missing_ok ? 0 : -ENOEXEC;
5f5d8eab 2667
5f5d8eab 2668 c->working_directory_home = false;
bb28e684 2669 free_and_replace(c->working_directory, k);
5f5d8eab
LP
2670 }
2671
2672 c->working_directory_missing_ok = missing_ok;
2673 return 0;
2674}
2675
e8e581bf
ZJS
2676int config_parse_unit_env_file(const char *unit,
2677 const char *filename,
2678 unsigned line,
2679 const char *section,
71a61510 2680 unsigned section_line,
e8e581bf
ZJS
2681 const char *lvalue,
2682 int ltype,
2683 const char *rvalue,
2684 void *data,
2685 void *userdata) {
ddb26e18 2686
99534007 2687 char ***env = ASSERT_PTR(data);
47538b76 2688 const Unit *u = userdata;
19f6d710 2689 _cleanup_free_ char *n = NULL;
853b8397 2690 int r;
ddb26e18
LP
2691
2692 assert(filename);
2693 assert(lvalue);
2694 assert(rvalue);
ddb26e18 2695
74051b9b
LP
2696 if (isempty(rvalue)) {
2697 /* Empty assignment frees the list */
6796073e 2698 *env = strv_free(*env);
74051b9b
LP
2699 return 0;
2700 }
2701
06536492 2702 r = unit_full_printf_full(u, rvalue, PATH_MAX, &n);
12ca818f 2703 if (r < 0) {
323dda78 2704 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
12ca818f
LP
2705 return 0;
2706 }
8fef7659 2707
2f4d31c1
YW
2708 r = path_simplify_and_warn(n[0] == '-' ? n + 1 : n, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
2709 if (r < 0)
afe4bfe2 2710 return 0;
afe4bfe2 2711
2f4d31c1 2712 r = strv_push(env, n);
853b8397
LP
2713 if (r < 0)
2714 return log_oom();
2715
2f4d31c1
YW
2716 n = NULL;
2717
853b8397
LP
2718 return 0;
2719}
2720
f7f3f5c3
LP
2721int config_parse_environ(
2722 const char *unit,
2723 const char *filename,
2724 unsigned line,
2725 const char *section,
2726 unsigned section_line,
2727 const char *lvalue,
2728 int ltype,
2729 const char *rvalue,
2730 void *data,
2731 void *userdata) {
853b8397 2732
47538b76 2733 const Unit *u = userdata;
99534007 2734 char ***env = ASSERT_PTR(data);
19f6d710 2735 int r;
853b8397
LP
2736
2737 assert(filename);
2738 assert(lvalue);
2739 assert(rvalue);
853b8397
LP
2740
2741 if (isempty(rvalue)) {
2742 /* Empty assignment resets the list */
6796073e 2743 *env = strv_free(*env);
853b8397
LP
2744 return 0;
2745 }
2746
4870133b
LP
2747 /* If 'u' is set, we operate on the regular unit specifier table. Otherwise we use a manager-specific
2748 * specifier table (in which case ltype must contain the runtime scope). */
2749 const Specifier *table = u ? NULL : (const Specifier[]) {
0b40688d
RP
2750 COMMON_SYSTEM_SPECIFIERS,
2751 COMMON_TMP_SPECIFIERS,
4870133b 2752 COMMON_CREDS_SPECIFIERS(ltype),
0b40688d
RP
2753 { 'h', specifier_user_home, NULL },
2754 { 's', specifier_user_shell, NULL },
2755 };
2756
323dda78 2757 for (const char *p = rvalue;; ) {
13734c75 2758 _cleanup_free_ char *word = NULL, *resolved = NULL;
035fe294 2759
4ec85141 2760 r = extract_first_word(&p, &word, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE);
035fe294
ZJS
2761 if (r == -ENOMEM)
2762 return log_oom();
12ca818f 2763 if (r < 0) {
035fe294
ZJS
2764 log_syntax(unit, LOG_WARNING, filename, line, r,
2765 "Invalid syntax, ignoring: %s", rvalue);
12ca818f
LP
2766 return 0;
2767 }
a687f500
ZJS
2768 if (r == 0)
2769 return 0;
97d0e5f8 2770
4870133b 2771 if (table)
0b40688d 2772 r = specifier_printf(word, sc_arg_max(), table, NULL, NULL, &resolved);
4870133b
LP
2773 else
2774 r = unit_env_printf(u, word, &resolved);
46a9ee5d
LP
2775 if (r < 0) {
2776 log_syntax(unit, LOG_WARNING, filename, line, r,
2777 "Failed to resolve specifiers in %s, ignoring: %m", word);
2778 continue;
2779 }
853b8397 2780
13734c75 2781 if (!env_assignment_is_valid(resolved)) {
323dda78 2782 log_syntax(unit, LOG_WARNING, filename, line, 0,
13734c75 2783 "Invalid environment assignment, ignoring: %s", resolved);
853b8397
LP
2784 continue;
2785 }
2786
13734c75 2787 r = strv_env_replace_consume(env, TAKE_PTR(resolved));
54ac3494 2788 if (r < 0)
13734c75 2789 return log_error_errno(r, "Failed to update environment: %m");
853b8397 2790 }
ddb26e18
LP
2791}
2792
00819cc1
LP
2793int config_parse_pass_environ(
2794 const char *unit,
2795 const char *filename,
2796 unsigned line,
2797 const char *section,
2798 unsigned section_line,
2799 const char *lvalue,
2800 int ltype,
2801 const char *rvalue,
2802 void *data,
2803 void *userdata) {
b4c14404 2804
b4c14404 2805 _cleanup_strv_free_ char **n = NULL;
47538b76 2806 const Unit *u = userdata;
99534007 2807 char*** passenv = ASSERT_PTR(data);
319a4f4b 2808 size_t nlen = 0;
b4c14404
FB
2809 int r;
2810
2811 assert(filename);
2812 assert(lvalue);
2813 assert(rvalue);
b4c14404
FB
2814
2815 if (isempty(rvalue)) {
2816 /* Empty assignment resets the list */
2817 *passenv = strv_free(*passenv);
2818 return 0;
2819 }
2820
323dda78 2821 for (const char *p = rvalue;;) {
41de9cc2 2822 _cleanup_free_ char *word = NULL, *k = NULL;
b4c14404 2823
4ec85141 2824 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
b4c14404
FB
2825 if (r == -ENOMEM)
2826 return log_oom();
2827 if (r < 0) {
323dda78 2828 log_syntax(unit, LOG_WARNING, filename, line, r,
063c4b1a 2829 "Trailing garbage in %s, ignoring: %s", lvalue, rvalue);
b4c14404
FB
2830 break;
2831 }
a687f500
ZJS
2832 if (r == 0)
2833 break;
b4c14404 2834
41de9cc2 2835 if (u) {
06536492 2836 r = unit_env_printf(u, word, &k);
41de9cc2 2837 if (r < 0) {
323dda78 2838 log_syntax(unit, LOG_WARNING, filename, line, r,
063c4b1a 2839 "Failed to resolve specifiers in %s, ignoring: %m", word);
41de9cc2
LP
2840 continue;
2841 }
ae2a15bc
LP
2842 } else
2843 k = TAKE_PTR(word);
41de9cc2
LP
2844
2845 if (!env_name_is_valid(k)) {
323dda78 2846 log_syntax(unit, LOG_WARNING, filename, line, 0,
41de9cc2 2847 "Invalid environment name for %s, ignoring: %s", lvalue, k);
b4c14404
FB
2848 continue;
2849 }
2850
319a4f4b 2851 if (!GREEDY_REALLOC(n, nlen + 2))
b4c14404 2852 return log_oom();
41de9cc2 2853
1cc6c93a 2854 n[nlen++] = TAKE_PTR(k);
b4c14404 2855 n[nlen] = NULL;
b4c14404
FB
2856 }
2857
2858 if (n) {
2859 r = strv_extend_strv(passenv, n, true);
2860 if (r < 0)
16eb0c4a 2861 return log_oom();
b4c14404
FB
2862 }
2863
2864 return 0;
2865}
2866
00819cc1
LP
2867int config_parse_unset_environ(
2868 const char *unit,
2869 const char *filename,
2870 unsigned line,
2871 const char *section,
2872 unsigned section_line,
2873 const char *lvalue,
2874 int ltype,
2875 const char *rvalue,
2876 void *data,
2877 void *userdata) {
2878
2879 _cleanup_strv_free_ char **n = NULL;
99534007 2880 char*** unsetenv = ASSERT_PTR(data);
47538b76 2881 const Unit *u = userdata;
319a4f4b 2882 size_t nlen = 0;
00819cc1
LP
2883 int r;
2884
2885 assert(filename);
2886 assert(lvalue);
2887 assert(rvalue);
00819cc1
LP
2888
2889 if (isempty(rvalue)) {
2890 /* Empty assignment resets the list */
2891 *unsetenv = strv_free(*unsetenv);
2892 return 0;
2893 }
2894
323dda78 2895 for (const char *p = rvalue;;) {
00819cc1
LP
2896 _cleanup_free_ char *word = NULL, *k = NULL;
2897
4ec85141 2898 r = extract_first_word(&p, &word, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE);
00819cc1
LP
2899 if (r == -ENOMEM)
2900 return log_oom();
2901 if (r < 0) {
323dda78 2902 log_syntax(unit, LOG_WARNING, filename, line, r,
063c4b1a 2903 "Trailing garbage in %s, ignoring: %s", lvalue, rvalue);
00819cc1
LP
2904 break;
2905 }
a687f500
ZJS
2906 if (r == 0)
2907 break;
00819cc1
LP
2908
2909 if (u) {
06536492 2910 r = unit_env_printf(u, word, &k);
00819cc1 2911 if (r < 0) {
323dda78 2912 log_syntax(unit, LOG_WARNING, filename, line, r,
063c4b1a 2913 "Failed to resolve unit specifiers in %s, ignoring: %m", word);
00819cc1
LP
2914 continue;
2915 }
ae2a15bc
LP
2916 } else
2917 k = TAKE_PTR(word);
00819cc1
LP
2918
2919 if (!env_assignment_is_valid(k) && !env_name_is_valid(k)) {
323dda78 2920 log_syntax(unit, LOG_WARNING, filename, line, 0,
00819cc1
LP
2921 "Invalid environment name or assignment %s, ignoring: %s", lvalue, k);
2922 continue;
2923 }
2924
319a4f4b 2925 if (!GREEDY_REALLOC(n, nlen + 2))
00819cc1
LP
2926 return log_oom();
2927
1cc6c93a 2928 n[nlen++] = TAKE_PTR(k);
00819cc1 2929 n[nlen] = NULL;
00819cc1
LP
2930 }
2931
2932 if (n) {
2933 r = strv_extend_strv(unsetenv, n, true);
2934 if (r < 0)
16eb0c4a 2935 return log_oom();
00819cc1
LP
2936 }
2937
2938 return 0;
2939}
2940
d3070fbd
LP
2941int config_parse_log_extra_fields(
2942 const char *unit,
2943 const char *filename,
2944 unsigned line,
2945 const char *section,
2946 unsigned section_line,
2947 const char *lvalue,
2948 int ltype,
2949 const char *rvalue,
2950 void *data,
2951 void *userdata) {
2952
99534007 2953 ExecContext *c = ASSERT_PTR(data);
47538b76 2954 const Unit *u = userdata;
d3070fbd
LP
2955 int r;
2956
2957 assert(filename);
2958 assert(lvalue);
2959 assert(rvalue);
d3070fbd
LP
2960
2961 if (isempty(rvalue)) {
2962 exec_context_free_log_extra_fields(c);
2963 return 0;
2964 }
2965
323dda78 2966 for (const char *p = rvalue;;) {
d3070fbd
LP
2967 _cleanup_free_ char *word = NULL, *k = NULL;
2968 struct iovec *t;
2969 const char *eq;
2970
4ec85141 2971 r = extract_first_word(&p, &word, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE);
d3070fbd
LP
2972 if (r == -ENOMEM)
2973 return log_oom();
2974 if (r < 0) {
2975 log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
2976 return 0;
2977 }
a687f500
ZJS
2978 if (r == 0)
2979 return 0;
d3070fbd
LP
2980
2981 r = unit_full_printf(u, word, &k);
2982 if (r < 0) {
323dda78 2983 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", word);
d3070fbd
LP
2984 continue;
2985 }
2986
2987 eq = strchr(k, '=');
2988 if (!eq) {
323dda78 2989 log_syntax(unit, LOG_WARNING, filename, line, 0, "Log field lacks '=' character, ignoring: %s", k);
d3070fbd
LP
2990 continue;
2991 }
2992
2993 if (!journal_field_valid(k, eq-k, false)) {
323dda78 2994 log_syntax(unit, LOG_WARNING, filename, line, 0, "Log field name is invalid, ignoring: %s", k);
d3070fbd
LP
2995 continue;
2996 }
2997
aa484f35 2998 t = reallocarray(c->log_extra_fields, c->n_log_extra_fields+1, sizeof(struct iovec));
d3070fbd
LP
2999 if (!t)
3000 return log_oom();
3001
3002 c->log_extra_fields = t;
3003 c->log_extra_fields[c->n_log_extra_fields++] = IOVEC_MAKE_STRING(k);
3004
3005 k = NULL;
3006 }
d3070fbd
LP
3007}
3008
91dd5f7c
LP
3009int config_parse_log_namespace(
3010 const char *unit,
3011 const char *filename,
3012 unsigned line,
3013 const char *section,
3014 unsigned section_line,
3015 const char *lvalue,
3016 int ltype,
3017 const char *rvalue,
3018 void *data,
3019 void *userdata) {
3020
3021 _cleanup_free_ char *k = NULL;
99534007 3022 ExecContext *c = ASSERT_PTR(data);
91dd5f7c
LP
3023 const Unit *u = userdata;
3024 int r;
3025
3026 assert(filename);
3027 assert(lvalue);
3028 assert(rvalue);
91dd5f7c
LP
3029
3030 if (isempty(rvalue)) {
3031 c->log_namespace = mfree(c->log_namespace);
3032 return 0;
3033 }
3034
06536492 3035 r = unit_full_printf_full(u, rvalue, NAME_MAX, &k);
91dd5f7c 3036 if (r < 0) {
323dda78 3037 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue);
91dd5f7c
LP
3038 return 0;
3039 }
3040
3041 if (!log_namespace_name_valid(k)) {
323dda78 3042 log_syntax(unit, LOG_WARNING, filename, line, 0, "Specified log namespace name is not valid, ignoring: %s", k);
91dd5f7c
LP
3043 return 0;
3044 }
3045
3046 free_and_replace(c->log_namespace, k);
3047 return 0;
3048}
3049
59fccdc5
LP
3050int config_parse_unit_condition_path(
3051 const char *unit,
3052 const char *filename,
3053 unsigned line,
3054 const char *section,
3055 unsigned section_line,
3056 const char *lvalue,
3057 int ltype,
3058 const char *rvalue,
3059 void *data,
3060 void *userdata) {
52661efd 3061
2fbe635a 3062 _cleanup_free_ char *p = NULL;
99534007 3063 Condition **list = ASSERT_PTR(data), *c;
59fccdc5
LP
3064 ConditionType t = ltype;
3065 bool trigger, negate;
47538b76 3066 const Unit *u = userdata;
19f6d710 3067 int r;
52661efd
LP
3068
3069 assert(filename);
3070 assert(lvalue);
3071 assert(rvalue);
52661efd 3072
74051b9b
LP
3073 if (isempty(rvalue)) {
3074 /* Empty assignment resets the list */
447021aa 3075 *list = condition_free_list(*list);
74051b9b
LP
3076 return 0;
3077 }
3078
ab7f148f
LP
3079 trigger = rvalue[0] == '|';
3080 if (trigger)
267632f0
LP
3081 rvalue++;
3082
ab7f148f
LP
3083 negate = rvalue[0] == '!';
3084 if (negate)
52661efd
LP
3085 rvalue++;
3086
06536492 3087 r = unit_path_printf(u, rvalue, &p);
59fccdc5 3088 if (r < 0) {
323dda78 3089 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue);
59fccdc5 3090 return 0;
19f6d710 3091 }
095b2d7a 3092
2f4d31c1
YW
3093 r = path_simplify_and_warn(p, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
3094 if (r < 0)
52661efd 3095 return 0;
52661efd 3096
59fccdc5 3097 c = condition_new(t, p, trigger, negate);
ab7f148f 3098 if (!c)
74051b9b 3099 return log_oom();
52661efd 3100
59fccdc5 3101 LIST_PREPEND(conditions, *list, c);
52661efd
LP
3102 return 0;
3103}
3104
59fccdc5
LP
3105int config_parse_unit_condition_string(
3106 const char *unit,
3107 const char *filename,
3108 unsigned line,
3109 const char *section,
3110 unsigned section_line,
3111 const char *lvalue,
3112 int ltype,
3113 const char *rvalue,
3114 void *data,
3115 void *userdata) {
039655a4 3116
2fbe635a 3117 _cleanup_free_ char *s = NULL;
99534007 3118 Condition **list = ASSERT_PTR(data), *c;
59fccdc5
LP
3119 ConditionType t = ltype;
3120 bool trigger, negate;
47538b76 3121 const Unit *u = userdata;
19f6d710 3122 int r;
039655a4
LP
3123
3124 assert(filename);
3125 assert(lvalue);
3126 assert(rvalue);
039655a4 3127
74051b9b
LP
3128 if (isempty(rvalue)) {
3129 /* Empty assignment resets the list */
447021aa 3130 *list = condition_free_list(*list);
74051b9b
LP
3131 return 0;
3132 }
3133
9266f31e 3134 trigger = *rvalue == '|';
c0d6e764 3135 if (trigger)
9266f31e 3136 rvalue += 1 + strspn(rvalue + 1, WHITESPACE);
267632f0 3137
9266f31e 3138 negate = *rvalue == '!';
c0d6e764 3139 if (negate)
9266f31e 3140 rvalue += 1 + strspn(rvalue + 1, WHITESPACE);
039655a4 3141
19f6d710 3142 r = unit_full_printf(u, rvalue, &s);
59fccdc5 3143 if (r < 0) {
323dda78 3144 log_syntax(unit, LOG_WARNING, filename, line, r,
cae90de3 3145 "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
59fccdc5 3146 return 0;
19f6d710 3147 }
095b2d7a 3148
59fccdc5 3149 c = condition_new(t, s, trigger, negate);
c0d6e764
LP
3150 if (!c)
3151 return log_oom();
039655a4 3152
59fccdc5 3153 LIST_PREPEND(conditions, *list, c);
039655a4
LP
3154 return 0;
3155}
3156
a57f7e2c
LP
3157int config_parse_unit_requires_mounts_for(
3158 const char *unit,
3159 const char *filename,
3160 unsigned line,
3161 const char *section,
71a61510 3162 unsigned section_line,
a57f7e2c
LP
3163 const char *lvalue,
3164 int ltype,
3165 const char *rvalue,
3166 void *data,
3167 void *userdata) {
7c8fa05c
LP
3168
3169 Unit *u = userdata;
035fe294 3170 int r;
7c8fa05c
LP
3171
3172 assert(filename);
3173 assert(lvalue);
3174 assert(rvalue);
3175 assert(data);
3176
323dda78 3177 for (const char *p = rvalue;;) {
744bb5b1 3178 _cleanup_free_ char *word = NULL, *resolved = NULL;
a57f7e2c 3179
4ec85141 3180 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
035fe294 3181 if (r == -ENOMEM)
a57f7e2c 3182 return log_oom();
035fe294
ZJS
3183 if (r < 0) {
3184 log_syntax(unit, LOG_WARNING, filename, line, r,
3185 "Invalid syntax, ignoring: %s", rvalue);
3186 return 0;
3187 }
a687f500
ZJS
3188 if (r == 0)
3189 return 0;
7c8fa05c 3190
06536492 3191 r = unit_path_printf(u, word, &resolved);
744bb5b1 3192 if (r < 0) {
323dda78 3193 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", word);
744bb5b1
LP
3194 continue;
3195 }
3196
2f4d31c1
YW
3197 r = path_simplify_and_warn(resolved, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
3198 if (r < 0)
3199 continue;
3200
eef85c4a 3201 r = unit_require_mounts_for(u, resolved, UNIT_DEPENDENCY_FILE);
a57f7e2c 3202 if (r < 0) {
323dda78 3203 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to add required mount '%s', ignoring: %m", resolved);
a57f7e2c
LP
3204 continue;
3205 }
3206 }
7c8fa05c 3207}
9e372868 3208
8c6493e5
YW
3209int config_parse_documentation(
3210 const char *unit,
3211 const char *filename,
3212 unsigned line,
3213 const char *section,
3214 unsigned section_line,
3215 const char *lvalue,
3216 int ltype,
3217 const char *rvalue,
3218 void *data,
3219 void *userdata) {
49dbfa7b 3220
99534007 3221 Unit *u = ASSERT_PTR(userdata);
49dbfa7b
LP
3222 int r;
3223 char **a, **b;
3224
3225 assert(filename);
3226 assert(lvalue);
3227 assert(rvalue);
49dbfa7b 3228
74051b9b
LP
3229 if (isempty(rvalue)) {
3230 /* Empty assignment resets the list */
6796073e 3231 u->documentation = strv_free(u->documentation);
74051b9b
LP
3232 return 0;
3233 }
3234
71a61510 3235 r = config_parse_unit_strv_printf(unit, filename, line, section, section_line, lvalue, ltype,
e8e581bf 3236 rvalue, data, userdata);
49dbfa7b
LP
3237 if (r < 0)
3238 return r;
3239
3240 for (a = b = u->documentation; a && *a; a++) {
3241
a2e03378 3242 if (documentation_url_is_valid(*a))
49dbfa7b
LP
3243 *(b++) = *a;
3244 else {
323dda78 3245 log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid URL, ignoring: %s", *a);
49dbfa7b
LP
3246 free(*a);
3247 }
3248 }
f6d2d421
ZJS
3249 if (b)
3250 *b = NULL;
49dbfa7b 3251
8c6493e5 3252 return 0;
49dbfa7b
LP
3253}
3254
349cc4a5 3255#if HAVE_SECCOMP
17df7223
LP
3256int config_parse_syscall_filter(
3257 const char *unit,
3258 const char *filename,
3259 unsigned line,
3260 const char *section,
3261 unsigned section_line,
3262 const char *lvalue,
3263 int ltype,
3264 const char *rvalue,
3265 void *data,
3266 void *userdata) {
3267
8351ceae 3268 ExecContext *c = data;
99534007 3269 _unused_ const Unit *u = ASSERT_PTR(userdata);
b5fb3789 3270 bool invert = false;
17df7223 3271 int r;
8351ceae
LP
3272
3273 assert(filename);
3274 assert(lvalue);
3275 assert(rvalue);
8351ceae 3276
74051b9b
LP
3277 if (isempty(rvalue)) {
3278 /* Empty assignment resets the list */
8cfa775f 3279 c->syscall_filter = hashmap_free(c->syscall_filter);
6b000af4 3280 c->syscall_allow_list = false;
74051b9b
LP
3281 return 0;
3282 }
3283
8351ceae
LP
3284 if (rvalue[0] == '~') {
3285 invert = true;
3286 rvalue++;
3287 }
3288
17df7223 3289 if (!c->syscall_filter) {
8cfa775f 3290 c->syscall_filter = hashmap_new(NULL);
17df7223
LP
3291 if (!c->syscall_filter)
3292 return log_oom();
3293
c0467cf3 3294 if (invert)
17df7223 3295 /* Allow everything but the ones listed */
6b000af4 3296 c->syscall_allow_list = false;
c0467cf3 3297 else {
17df7223 3298 /* Allow nothing but the ones listed */
6b000af4 3299 c->syscall_allow_list = true;
8351ceae 3300
387f6955 3301 /* Accept default syscalls if we are on an allow_list */
2f6b9110
LP
3302 r = seccomp_parse_syscall_filter(
3303 "@default", -1, c->syscall_filter,
6b000af4 3304 SECCOMP_PARSE_PERMISSIVE|SECCOMP_PARSE_ALLOW_LIST,
58f6ab44
ZJS
3305 unit,
3306 NULL, 0);
201c1cc2
TM
3307 if (r < 0)
3308 return r;
c0467cf3 3309 }
8351ceae
LP
3310 }
3311
323dda78 3312 for (const char *p = rvalue;;) {
8cfa775f
YW
3313 _cleanup_free_ char *word = NULL, *name = NULL;
3314 int num;
8351ceae 3315
8130926d 3316 r = extract_first_word(&p, &word, NULL, 0);
8130926d 3317 if (r == -ENOMEM)
74051b9b 3318 return log_oom();
8130926d 3319 if (r < 0) {
084a46d7
YW
3320 log_syntax(unit, LOG_WARNING, filename, line, r,
3321 "Invalid syntax, ignoring: %s", rvalue);
063c4b1a 3322 return 0;
8130926d 3323 }
a687f500
ZJS
3324 if (r == 0)
3325 return 0;
8351ceae 3326
8cfa775f
YW
3327 r = parse_syscall_and_errno(word, &name, &num);
3328 if (r < 0) {
084a46d7
YW
3329 log_syntax(unit, LOG_WARNING, filename, line, r,
3330 "Failed to parse syscall:errno, ignoring: %s", word);
3331 continue;
3332 }
3333 if (!invert && num >= 0) {
3334 log_syntax(unit, LOG_WARNING, filename, line, 0,
3335 "Allow-listed system calls cannot take error number, ignoring: %s", word);
8cfa775f
YW
3336 continue;
3337 }
3338
58f6ab44 3339 r = seccomp_parse_syscall_filter(
acd142af
LP
3340 name, num, c->syscall_filter,
3341 SECCOMP_PARSE_LOG|SECCOMP_PARSE_PERMISSIVE|
3342 (invert ? SECCOMP_PARSE_INVERT : 0)|
6b000af4 3343 (c->syscall_allow_list ? SECCOMP_PARSE_ALLOW_LIST : 0),
acd142af 3344 unit, filename, line);
201c1cc2
TM
3345 if (r < 0)
3346 return r;
c0467cf3 3347 }
17df7223
LP
3348}
3349
9df2cdd8
TM
3350int config_parse_syscall_log(
3351 const char *unit,
3352 const char *filename,
3353 unsigned line,
3354 const char *section,
3355 unsigned section_line,
3356 const char *lvalue,
3357 int ltype,
3358 const char *rvalue,
3359 void *data,
3360 void *userdata) {
3361
3362 ExecContext *c = data;
99534007 3363 _unused_ const Unit *u = ASSERT_PTR(userdata);
9df2cdd8
TM
3364 bool invert = false;
3365 const char *p;
3366 int r;
3367
3368 assert(filename);
3369 assert(lvalue);
3370 assert(rvalue);
9df2cdd8
TM
3371
3372 if (isempty(rvalue)) {
3373 /* Empty assignment resets the list */
3374 c->syscall_log = hashmap_free(c->syscall_log);
3375 c->syscall_log_allow_list = false;
3376 return 0;
3377 }
3378
3379 if (rvalue[0] == '~') {
3380 invert = true;
3381 rvalue++;
3382 }
3383
3384 if (!c->syscall_log) {
3385 c->syscall_log = hashmap_new(NULL);
3386 if (!c->syscall_log)
3387 return log_oom();
3388
3389 if (invert)
3390 /* Log everything but the ones listed */
3391 c->syscall_log_allow_list = false;
3392 else
3393 /* Log nothing but the ones listed */
3394 c->syscall_log_allow_list = true;
3395 }
3396
3397 p = rvalue;
3398 for (;;) {
696a13ba 3399 _cleanup_free_ char *word = NULL;
9df2cdd8
TM
3400
3401 r = extract_first_word(&p, &word, NULL, 0);
9df2cdd8
TM
3402 if (r == -ENOMEM)
3403 return log_oom();
3404 if (r < 0) {
3405 log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
3406 return 0;
3407 }
a687f500
ZJS
3408 if (r == 0)
3409 return 0;
9df2cdd8 3410
9df2cdd8 3411 r = seccomp_parse_syscall_filter(
696a13ba 3412 word, -1, c->syscall_log,
9df2cdd8
TM
3413 SECCOMP_PARSE_LOG|SECCOMP_PARSE_PERMISSIVE|
3414 (invert ? SECCOMP_PARSE_INVERT : 0)|
3415 (c->syscall_log_allow_list ? SECCOMP_PARSE_ALLOW_LIST : 0),
3416 unit, filename, line);
3417 if (r < 0)
3418 return r;
3419 }
3420}
3421
57183d11
LP
3422int config_parse_syscall_archs(
3423 const char *unit,
3424 const char *filename,
3425 unsigned line,
3426 const char *section,
3427 unsigned section_line,
3428 const char *lvalue,
3429 int ltype,
3430 const char *rvalue,
3431 void *data,
3432 void *userdata) {
3433
d3b1c508 3434 Set **archs = data;
57183d11
LP
3435 int r;
3436
3437 if (isempty(rvalue)) {
525d3cc7 3438 *archs = set_free(*archs);
57183d11
LP
3439 return 0;
3440 }
3441
323dda78 3442 for (const char *p = rvalue;;) {
035fe294 3443 _cleanup_free_ char *word = NULL;
57183d11
LP
3444 uint32_t a;
3445
4ec85141 3446 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
035fe294 3447 if (r == -ENOMEM)
57183d11 3448 return log_oom();
035fe294
ZJS
3449 if (r < 0) {
3450 log_syntax(unit, LOG_WARNING, filename, line, r,
3451 "Invalid syntax, ignoring: %s", rvalue);
3452 return 0;
3453 }
a687f500
ZJS
3454 if (r == 0)
3455 return 0;
57183d11 3456
035fe294 3457 r = seccomp_arch_from_string(word, &a);
57183d11 3458 if (r < 0) {
323dda78 3459 log_syntax(unit, LOG_WARNING, filename, line, r,
035fe294 3460 "Failed to parse system call architecture \"%s\", ignoring: %m", word);
57183d11
LP
3461 continue;
3462 }
3463
de7fef4b 3464 r = set_ensure_put(archs, NULL, UINT32_TO_PTR(a + 1));
57183d11
LP
3465 if (r < 0)
3466 return log_oom();
3467 }
57183d11
LP
3468}
3469
17df7223
LP
3470int config_parse_syscall_errno(
3471 const char *unit,
3472 const char *filename,
3473 unsigned line,
3474 const char *section,
3475 unsigned section_line,
3476 const char *lvalue,
3477 int ltype,
3478 const char *rvalue,
3479 void *data,
3480 void *userdata) {
3481
3482 ExecContext *c = data;
3483 int e;
3484
3485 assert(filename);
3486 assert(lvalue);
3487 assert(rvalue);
3488
005bfaf1 3489 if (isempty(rvalue) || streq(rvalue, "kill")) {
17df7223 3490 /* Empty assignment resets to KILL */
005bfaf1 3491 c->syscall_errno = SECCOMP_ERROR_NUMBER_KILL;
17df7223 3492 return 0;
8351ceae
LP
3493 }
3494
3df90f24 3495 e = parse_errno(rvalue);
b98680b2
YW
3496 if (e < 0) {
3497 log_syntax(unit, LOG_WARNING, filename, line, e, "Failed to parse error number, ignoring: %s", rvalue);
3498 return 0;
3499 }
3500 if (e == 0) {
3501 log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid error number, ignoring: %s", rvalue);
17df7223
LP
3502 return 0;
3503 }
8351ceae 3504
17df7223 3505 c->syscall_errno = e;
8351ceae
LP
3506 return 0;
3507}
4298d0b5
LP
3508
3509int config_parse_address_families(
3510 const char *unit,
3511 const char *filename,
3512 unsigned line,
3513 const char *section,
3514 unsigned section_line,
3515 const char *lvalue,
3516 int ltype,
3517 const char *rvalue,
3518 void *data,
3519 void *userdata) {
3520
3521 ExecContext *c = data;
4298d0b5 3522 bool invert = false;
4298d0b5
LP
3523 int r;
3524
3525 assert(filename);
3526 assert(lvalue);
3527 assert(rvalue);
4298d0b5
LP
3528
3529 if (isempty(rvalue)) {
3530 /* Empty assignment resets the list */
525d3cc7 3531 c->address_families = set_free(c->address_families);
6b000af4 3532 c->address_families_allow_list = false;
4298d0b5
LP
3533 return 0;
3534 }
3535
4e6c50a5
YW
3536 if (streq(rvalue, "none")) {
3537 /* Forbid all address families. */
3538 c->address_families = set_free(c->address_families);
3539 c->address_families_allow_list = true;
3540 return 0;
3541 }
3542
4298d0b5
LP
3543 if (rvalue[0] == '~') {
3544 invert = true;
3545 rvalue++;
3546 }
3547
3548 if (!c->address_families) {
d5099efc 3549 c->address_families = set_new(NULL);
4298d0b5
LP
3550 if (!c->address_families)
3551 return log_oom();
3552
6b000af4 3553 c->address_families_allow_list = !invert;
4298d0b5
LP
3554 }
3555
323dda78 3556 for (const char *p = rvalue;;) {
035fe294 3557 _cleanup_free_ char *word = NULL;
4298d0b5
LP
3558 int af;
3559
4ec85141 3560 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
035fe294 3561 if (r == -ENOMEM)
4298d0b5 3562 return log_oom();
035fe294
ZJS
3563 if (r < 0) {
3564 log_syntax(unit, LOG_WARNING, filename, line, r,
3565 "Invalid syntax, ignoring: %s", rvalue);
3566 return 0;
3567 }
a687f500
ZJS
3568 if (r == 0)
3569 return 0;
4298d0b5 3570
035fe294 3571 af = af_from_name(word);
acf4d158 3572 if (af < 0) {
323dda78 3573 log_syntax(unit, LOG_WARNING, filename, line, af,
063c4b1a 3574 "Failed to parse address family, ignoring: %s", word);
4298d0b5
LP
3575 continue;
3576 }
3577
3578 /* If we previously wanted to forbid an address family and now
035fe294 3579 * we want to allow it, then just remove it from the list.
4298d0b5 3580 */
6b000af4 3581 if (!invert == c->address_families_allow_list) {
4298d0b5 3582 r = set_put(c->address_families, INT_TO_PTR(af));
4298d0b5
LP
3583 if (r < 0)
3584 return log_oom();
3585 } else
3586 set_remove(c->address_families, INT_TO_PTR(af));
3587 }
4298d0b5 3588}
add00535
LP
3589
3590int config_parse_restrict_namespaces(
3591 const char *unit,
3592 const char *filename,
3593 unsigned line,
3594 const char *section,
3595 unsigned section_line,
3596 const char *lvalue,
3597 int ltype,
3598 const char *rvalue,
3599 void *data,
3600 void *userdata) {
3601
3602 ExecContext *c = data;
aa9d574d 3603 unsigned long flags;
add00535
LP
3604 bool invert = false;
3605 int r;
3606
3607 if (isempty(rvalue)) {
3608 /* Reset to the default. */
aa9d574d
YW
3609 c->restrict_namespaces = NAMESPACE_FLAGS_INITIAL;
3610 return 0;
3611 }
3612
3613 /* Boolean parameter ignores the previous settings */
3614 r = parse_boolean(rvalue);
3615 if (r > 0) {
3616 c->restrict_namespaces = 0;
3617 return 0;
3618 } else if (r == 0) {
add00535
LP
3619 c->restrict_namespaces = NAMESPACE_FLAGS_ALL;
3620 return 0;
3621 }
3622
3623 if (rvalue[0] == '~') {
3624 invert = true;
3625 rvalue++;
3626 }
3627
aa9d574d
YW
3628 /* Not a boolean argument, in this case it's a list of namespace types. */
3629 r = namespace_flags_from_string(rvalue, &flags);
3630 if (r < 0) {
323dda78 3631 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse namespace type string, ignoring: %s", rvalue);
aa9d574d 3632 return 0;
add00535
LP
3633 }
3634
aa9d574d
YW
3635 if (c->restrict_namespaces == NAMESPACE_FLAGS_INITIAL)
3636 /* Initial assignment. Just set the value. */
3637 c->restrict_namespaces = invert ? (~flags) & NAMESPACE_FLAGS_ALL : flags;
3638 else
3639 /* Merge the value with the previous one. */
3640 SET_FLAG(c->restrict_namespaces, flags, !invert);
add00535
LP
3641
3642 return 0;
3643}
c0467cf3 3644#endif
8351ceae 3645
e59ccd03
ILG
3646int config_parse_restrict_filesystems(
3647 const char *unit,
3648 const char *filename,
3649 unsigned line,
3650 const char *section,
3651 unsigned section_line,
3652 const char *lvalue,
3653 int ltype,
3654 const char *rvalue,
3655 void *data,
3656 void *userdata) {
99534007 3657 ExecContext *c = ASSERT_PTR(data);
e59ccd03
ILG
3658 bool invert = false;
3659 int r;
3660
3661 assert(filename);
3662 assert(lvalue);
3663 assert(rvalue);
e59ccd03
ILG
3664
3665 if (isempty(rvalue)) {
3666 /* Empty assignment resets the list */
3667 c->restrict_filesystems = set_free(c->restrict_filesystems);
3668 c->restrict_filesystems_allow_list = false;
3669 return 0;
3670 }
3671
3672 if (rvalue[0] == '~') {
3673 invert = true;
3674 rvalue++;
3675 }
3676
3677 if (!c->restrict_filesystems) {
3678 if (invert)
3679 /* Allow everything but the ones listed */
3680 c->restrict_filesystems_allow_list = false;
3681 else
3682 /* Allow nothing but the ones listed */
3683 c->restrict_filesystems_allow_list = true;
3684 }
3685
3686 for (const char *p = rvalue;;) {
3687 _cleanup_free_ char *word = NULL;
3688
3689 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
3690 if (r == 0)
3691 break;
3692 if (r == -ENOMEM)
3693 return log_oom();
3694 if (r < 0) {
3695 log_syntax(unit, LOG_WARNING, filename, line, r,
3696 "Trailing garbage in %s, ignoring: %s", lvalue, rvalue);
3697 break;
3698 }
3699
3700 r = lsm_bpf_parse_filesystem(
3701 word,
3702 &c->restrict_filesystems,
3703 FILESYSTEM_PARSE_LOG|
3704 (invert ? FILESYSTEM_PARSE_INVERT : 0)|
3705 (c->restrict_filesystems_allow_list ? FILESYSTEM_PARSE_ALLOW_LIST : 0),
3706 unit, filename, line);
3707
3708 if (r < 0)
3709 return r;
3710 }
3711
3712 return 0;
3713}
3714
a016b922
LP
3715int config_parse_unit_slice(
3716 const char *unit,
3717 const char *filename,
3718 unsigned line,
3719 const char *section,
71a61510 3720 unsigned section_line,
a016b922
LP
3721 const char *lvalue,
3722 int ltype,
3723 const char *rvalue,
3724 void *data,
3725 void *userdata) {
3726
063c4b1a 3727 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
a016b922 3728 _cleanup_free_ char *k = NULL;
abc9fa1c 3729 Unit *u = userdata, *slice;
a016b922
LP
3730 int r;
3731
3732 assert(filename);
3733 assert(lvalue);
3734 assert(rvalue);
3735 assert(u);
3736
19f6d710 3737 r = unit_name_printf(u, rvalue, &k);
d79200e2 3738 if (r < 0) {
323dda78 3739 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue);
d79200e2 3740 return 0;
19f6d710 3741 }
a016b922 3742
063c4b1a 3743 r = manager_load_unit(u->manager, k, NULL, &error, &slice);
a016b922 3744 if (r < 0) {
323dda78 3745 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to load slice unit %s, ignoring: %s", k, bus_error_message(&error, r));
a016b922
LP
3746 return 0;
3747 }
3748
899acf5c 3749 r = unit_set_slice(u, slice);
d79200e2 3750 if (r < 0) {
323dda78 3751 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to assign slice %s to unit %s, ignoring: %m", slice->id, u->id);
a016b922
LP
3752 return 0;
3753 }
3754
a016b922
LP
3755 return 0;
3756}
3757
b2f8b02e
LP
3758int config_parse_cpu_quota(
3759 const char *unit,
3760 const char *filename,
3761 unsigned line,
3762 const char *section,
3763 unsigned section_line,
3764 const char *lvalue,
3765 int ltype,
3766 const char *rvalue,
3767 void *data,
3768 void *userdata) {
3769
3770 CGroupContext *c = data;
9184ca48 3771 int r;
b2f8b02e
LP
3772
3773 assert(filename);
3774 assert(lvalue);
3775 assert(rvalue);
3776
3777 if (isempty(rvalue)) {
3a43da28 3778 c->cpu_quota_per_sec_usec = USEC_INFINITY;
b2f8b02e
LP
3779 return 0;
3780 }
3781
fe845b5e 3782 r = parse_permyriad_unbounded(rvalue);
9184ca48 3783 if (r <= 0) {
323dda78 3784 log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid CPU quota '%s', ignoring.", rvalue);
9a054909 3785 return 0;
b2f8b02e
LP
3786 }
3787
fe845b5e 3788 c->cpu_quota_per_sec_usec = ((usec_t) r * USEC_PER_SEC) / 10000U;
b2f8b02e
LP
3789 return 0;
3790}
3791
31d3a520 3792int config_parse_allowed_cpuset(
047f5d63
PH
3793 const char *unit,
3794 const char *filename,
3795 unsigned line,
3796 const char *section,
3797 unsigned section_line,
3798 const char *lvalue,
3799 int ltype,
3800 const char *rvalue,
3801 void *data,
3802 void *userdata) {
3803
31d3a520 3804 CPUSet *c = data;
047f5d63 3805
31d3a520 3806 (void) parse_cpu_set_extend(rvalue, c, true, unit, filename, line, lvalue);
047f5d63
PH
3807 return 0;
3808}
3809
4ad49000
LP
3810int config_parse_memory_limit(
3811 const char *unit,
3812 const char *filename,
3813 unsigned line,
3814 const char *section,
71a61510 3815 unsigned section_line,
4ad49000
LP
3816 const char *lvalue,
3817 int ltype,
3818 const char *rvalue,
3819 void *data,
3820 void *userdata) {
3821
3822 CGroupContext *c = data;
da4d897e 3823 uint64_t bytes = CGROUP_LIMIT_MAX;
4ad49000
LP
3824 int r;
3825
67e2baff
MK
3826 if (isempty(rvalue) && STR_IN_SET(lvalue, "DefaultMemoryLow",
3827 "DefaultMemoryMin",
3828 "MemoryLow",
53fda560 3829 "StartupMemoryLow",
67e2baff 3830 "MemoryMin"))
db2b8d2e 3831 bytes = CGROUP_LIMIT_MIN;
67e2baff 3832 else if (!isempty(rvalue) && !streq(rvalue, "infinity")) {
875ae566 3833
fe845b5e 3834 r = parse_permyriad(rvalue);
875ae566
LP
3835 if (r < 0) {
3836 r = parse_size(rvalue, 1024, &bytes);
3837 if (r < 0) {
323dda78 3838 log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid memory limit '%s', ignoring: %m", rvalue);
875ae566
LP
3839 return 0;
3840 }
3841 } else
fe845b5e 3842 bytes = physical_memory_scale(r, 10000U);
875ae566 3843
906bdbf5 3844 if (bytes >= UINT64_MAX ||
53fda560
LB
3845 (bytes <= 0 && !STR_IN_SET(lvalue,
3846 "MemorySwapMax",
3847 "StartupMemorySwapMax",
3848 "MemoryZSwapMax",
3849 "StartupMemoryZSwapMax",
3850 "MemoryLow",
3851 "StartupMemoryLow",
3852 "MemoryMin",
3853 "DefaultMemoryLow",
3854 "DefaultstartupMemoryLow",
3855 "DefaultMemoryMin"))) {
323dda78 3856 log_syntax(unit, LOG_WARNING, filename, line, 0, "Memory limit '%s' out of range, ignoring.", rvalue);
da4d897e
TH
3857 return 0;
3858 }
4ad49000
LP
3859 }
3860
c52db42b 3861 if (streq(lvalue, "DefaultMemoryLow")) {
db2b8d2e 3862 c->default_memory_low = bytes;
c52db42b 3863 c->default_memory_low_set = true;
53fda560
LB
3864 } else if (streq(lvalue, "DefaultStartupMemoryLow")) {
3865 c->default_startup_memory_low = bytes;
3866 c->default_startup_memory_low_set = true;
7ad5439e 3867 } else if (streq(lvalue, "DefaultMemoryMin")) {
db2b8d2e 3868 c->default_memory_min = bytes;
7ad5439e 3869 c->default_memory_min_set = true;
7ad5439e 3870 } else if (streq(lvalue, "MemoryMin")) {
48422635 3871 c->memory_min = bytes;
311a0e2e 3872 c->memory_min_set = true;
7ad5439e 3873 } else if (streq(lvalue, "MemoryLow")) {
da4d897e 3874 c->memory_low = bytes;
311a0e2e 3875 c->memory_low_set = true;
53fda560
LB
3876 } else if (streq(lvalue, "StartupMemoryLow")) {
3877 c->startup_memory_low = bytes;
3878 c->startup_memory_low_set = true;
c52db42b 3879 } else if (streq(lvalue, "MemoryHigh"))
da4d897e 3880 c->memory_high = bytes;
53fda560
LB
3881 else if (streq(lvalue, "StartupMemoryHigh")) {
3882 c->startup_memory_high = bytes;
3883 c->startup_memory_high_set = true;
3884 } else if (streq(lvalue, "MemoryMax"))
da4d897e 3885 c->memory_max = bytes;
53fda560
LB
3886 else if (streq(lvalue, "StartupMemoryMax")) {
3887 c->startup_memory_max = bytes;
3888 c->startup_memory_max_set = true;
3889 } else if (streq(lvalue, "MemorySwapMax"))
96e131ea 3890 c->memory_swap_max = bytes;
53fda560
LB
3891 else if (streq(lvalue, "StartupMemorySwapMax")) {
3892 c->startup_memory_swap_max = bytes;
3893 c->startup_memory_swap_max_set = true;
3894 } else if (streq(lvalue, "MemoryZSwapMax"))
d7fe0a67 3895 c->memory_zswap_max = bytes;
53fda560
LB
3896 else if (streq(lvalue, "StartupMemoryZSwapMax")) {
3897 c->startup_memory_zswap_max = bytes;
3898 c->startup_memory_zswap_max_set = true;
3899 } else if (streq(lvalue, "MemoryLimit")) {
c1e701e2
LP
3900 log_syntax(unit, LOG_WARNING, filename, line, 0,
3901 "Unit uses MemoryLimit=; please use MemoryMax= instead. Support for MemoryLimit= will be removed soon.");
da4d897e 3902 c->memory_limit = bytes;
c1e701e2 3903 } else
96e131ea 3904 return -EINVAL;
4ad49000 3905
4ad49000
LP
3906 return 0;
3907}
3908
03a7b521
LP
3909int config_parse_tasks_max(
3910 const char *unit,
3911 const char *filename,
3912 unsigned line,
3913 const char *section,
3914 unsigned section_line,
3915 const char *lvalue,
3916 int ltype,
3917 const char *rvalue,
3918 void *data,
3919 void *userdata) {
3920
47538b76 3921 const Unit *u = userdata;
3a0f06c4
ZJS
3922 TasksMax *tasks_max = data;
3923 uint64_t v;
03a7b521
LP
3924 int r;
3925
f5058264 3926 if (isempty(rvalue)) {
3a0f06c4 3927 *tasks_max = u ? u->manager->default_tasks_max : TASKS_MAX_UNSET;
f5058264
TH
3928 return 0;
3929 }
3930
3931 if (streq(rvalue, "infinity")) {
3a0f06c4 3932 *tasks_max = TASKS_MAX_UNSET;
03a7b521
LP
3933 return 0;
3934 }
3935
fe845b5e 3936 r = parse_permyriad(rvalue);
3a0f06c4 3937 if (r >= 0)
fe845b5e 3938 *tasks_max = (TasksMax) { r, 10000U }; /* r‱ */
3a0f06c4 3939 else {
f5058264 3940 r = safe_atou64(rvalue, &v);
83f8e808 3941 if (r < 0) {
323dda78 3942 log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid maximum tasks value '%s', ignoring: %m", rvalue);
83f8e808
LP
3943 return 0;
3944 }
83f8e808 3945
3a0f06c4 3946 if (v <= 0 || v >= UINT64_MAX) {
323dda78 3947 log_syntax(unit, LOG_WARNING, filename, line, 0, "Maximum tasks value '%s' out of range, ignoring.", rvalue);
3a0f06c4
ZJS
3948 return 0;
3949 }
3950
3951 *tasks_max = (TasksMax) { v };
03a7b521
LP
3952 }
3953
3954 return 0;
3955}
3956
02638280
LP
3957int config_parse_delegate(
3958 const char *unit,
3959 const char *filename,
3960 unsigned line,
3961 const char *section,
3962 unsigned section_line,
3963 const char *lvalue,
3964 int ltype,
3965 const char *rvalue,
3966 void *data,
3967 void *userdata) {
3968
3969 CGroupContext *c = data;
ecae73d7 3970 UnitType t;
02638280
LP
3971 int r;
3972
ecae73d7
ZJS
3973 t = unit_name_to_type(unit);
3974 assert(t != _UNIT_TYPE_INVALID);
3975
3976 if (!unit_vtable[t]->can_delegate) {
323dda78 3977 log_syntax(unit, LOG_WARNING, filename, line, 0, "Delegate= setting not supported for this unit type, ignoring.");
ecae73d7
ZJS
3978 return 0;
3979 }
3980
449172f9
ZJS
3981 /* We either accept a boolean value, which may be used to turn on delegation for all controllers, or
3982 * turn it off for all. Or it takes a list of controller names, in which case we add the specified
3983 * controllers to the mask to delegate. Delegate= enables delegation without any controllers. */
02638280 3984
1bdfc7b9 3985 if (isempty(rvalue)) {
449172f9 3986 /* An empty string resets controllers and sets Delegate=yes. */
d48013f8 3987 c->delegate = true;
1bdfc7b9
YW
3988 c->delegate_controllers = 0;
3989 return 0;
3990 }
3991
02638280
LP
3992 r = parse_boolean(rvalue);
3993 if (r < 0) {
02638280
LP
3994 CGroupMask mask = 0;
3995
323dda78 3996 for (const char *p = rvalue;;) {
02638280
LP
3997 _cleanup_free_ char *word = NULL;
3998 CGroupController cc;
3999
4ec85141 4000 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
02638280
LP
4001 if (r == -ENOMEM)
4002 return log_oom();
4003 if (r < 0) {
323dda78 4004 log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
ff1b8455 4005 return 0;
02638280 4006 }
a687f500
ZJS
4007 if (r == 0)
4008 break;
02638280
LP
4009
4010 cc = cgroup_controller_from_string(word);
4011 if (cc < 0) {
323dda78 4012 log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid controller name '%s', ignoring", word);
02638280
LP
4013 continue;
4014 }
4015
4016 mask |= CGROUP_CONTROLLER_TO_MASK(cc);
4017 }
4018
4019 c->delegate = true;
4020 c->delegate_controllers |= mask;
4021
4022 } else if (r > 0) {
4023 c->delegate = true;
4024 c->delegate_controllers = _CGROUP_MASK_ALL;
4025 } else {
4026 c->delegate = false;
4027 c->delegate_controllers = 0;
4028 }
4029
4030 return 0;
4031}
4032
a8b993dc
LP
4033int config_parse_delegate_subgroup(
4034 const char *unit,
4035 const char *filename,
4036 unsigned line,
4037 const char *section,
4038 unsigned section_line,
4039 const char *lvalue,
4040 int ltype,
4041 const char *rvalue,
4042 void *data,
4043 void *userdata) {
4044
4045 CGroupContext *c = ASSERT_PTR(data);
4046 UnitType t;
4047
4048 t = unit_name_to_type(unit);
4049 assert(t >= 0);
4050
4051 if (!unit_vtable[t]->can_delegate) {
4052 log_syntax(unit, LOG_WARNING, filename, line, 0, "DelegateSubgroup= setting not supported for this unit type, ignoring.");
4053 return 0;
4054 }
4055
4056 if (isempty(rvalue)) {
4057 c->delegate_subgroup = mfree(c->delegate_subgroup);
4058 return 0;
4059 }
4060
4061 if (cg_needs_escape(rvalue)) { /* Insist that specified names don't need escaping */
4062 log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid control group name, ignoring: %s", rvalue);
4063 return 0;
4064 }
4065
4066 return free_and_strdup_warn(&c->delegate_subgroup, rvalue);
4067}
4068
4d824a4e
AZ
4069int config_parse_managed_oom_mode(
4070 const char *unit,
4071 const char *filename,
4072 unsigned line,
4073 const char *section,
4074 unsigned section_line,
4075 const char *lvalue,
4076 int ltype,
4077 const char *rvalue,
4078 void *data,
4079 void *userdata) {
ed5033fd 4080
4d824a4e
AZ
4081 ManagedOOMMode *mode = data, m;
4082 UnitType t;
4083
4084 t = unit_name_to_type(unit);
4085 assert(t != _UNIT_TYPE_INVALID);
4086
4087 if (!unit_vtable[t]->can_set_managed_oom)
4088 return log_syntax(unit, LOG_WARNING, filename, line, 0, "%s= is not supported for this unit type, ignoring.", lvalue);
4089
4090 if (isempty(rvalue)) {
4091 *mode = MANAGED_OOM_AUTO;
f561e8c6 4092 return 0;
4d824a4e
AZ
4093 }
4094
4095 m = managed_oom_mode_from_string(rvalue);
4096 if (m < 0) {
b98680b2 4097 log_syntax(unit, LOG_WARNING, filename, line, m, "Invalid syntax, ignoring: %s", rvalue);
4d824a4e
AZ
4098 return 0;
4099 }
ed5033fd 4100
4d824a4e
AZ
4101 *mode = m;
4102 return 0;
4103}
4104
4105int config_parse_managed_oom_mem_pressure_limit(
4106 const char *unit,
4107 const char *filename,
4108 unsigned line,
4109 const char *section,
4110 unsigned section_line,
4111 const char *lvalue,
4112 int ltype,
4113 const char *rvalue,
4114 void *data,
4115 void *userdata) {
ed5033fd 4116
0a9f9344 4117 uint32_t *limit = data;
4d824a4e
AZ
4118 UnitType t;
4119 int r;
4120
4121 t = unit_name_to_type(unit);
4122 assert(t != _UNIT_TYPE_INVALID);
4123
4124 if (!unit_vtable[t]->can_set_managed_oom)
4125 return log_syntax(unit, LOG_WARNING, filename, line, 0, "%s= is not supported for this unit type, ignoring.", lvalue);
4126
4127 if (isempty(rvalue)) {
f561e8c6
AZ
4128 *limit = 0;
4129 return 0;
4d824a4e
AZ
4130 }
4131
0a9f9344 4132 r = parse_permyriad(rvalue);
4d824a4e 4133 if (r < 0) {
0a9f9344 4134 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse memory pressure limit value, ignoring: %s", rvalue);
4d824a4e
AZ
4135 return 0;
4136 }
4137
d9d3f05d
LP
4138 /* Normalize to 2^32-1 == 100% */
4139 *limit = UINT32_SCALE_FROM_PERMYRIAD(r);
4d824a4e
AZ
4140 return 0;
4141}
4142
4ad49000
LP
4143int config_parse_device_allow(
4144 const char *unit,
4145 const char *filename,
4146 unsigned line,
4147 const char *section,
71a61510 4148 unsigned section_line,
4ad49000
LP
4149 const char *lvalue,
4150 int ltype,
4151 const char *rvalue,
4152 void *data,
4153 void *userdata) {
4154
c9f620bf 4155 _cleanup_free_ char *path = NULL, *resolved = NULL;
4ad49000 4156 CGroupContext *c = data;
c9f620bf 4157 const char *p = rvalue;
1116e14c 4158 int r;
4ad49000
LP
4159
4160 if (isempty(rvalue)) {
4161 while (c->device_allow)
4162 cgroup_context_free_device_allow(c, c->device_allow);
4163
4164 return 0;
4165 }
4166
4ec85141 4167 r = extract_first_word(&p, &path, NULL, EXTRACT_UNQUOTE);
c9f620bf
YW
4168 if (r == -ENOMEM)
4169 return log_oom();
a687f500 4170 if (r <= 0) {
1116e14c 4171 log_syntax(unit, LOG_WARNING, filename, line, r,
c9f620bf 4172 "Failed to extract device path and rights from '%s', ignoring.", rvalue);
20d52ab6 4173 return 0;
1116e14c
NBS
4174 }
4175
06536492 4176 r = unit_path_printf(userdata, path, &resolved);
c9f620bf
YW
4177 if (r < 0) {
4178 log_syntax(unit, LOG_WARNING, filename, line, r,
4179 "Failed to resolve unit specifiers in '%s', ignoring: %m", path);
4ad49000
LP
4180 return 0;
4181 }
4182
49fe5c09 4183 if (!STARTSWITH_SET(resolved, "block-", "char-")) {
2f4d31c1 4184
57e84e75
LP
4185 r = path_simplify_and_warn(resolved, 0, unit, filename, line, lvalue);
4186 if (r < 0)
4187 return 0;
4188
4189 if (!valid_device_node_path(resolved)) {
323dda78 4190 log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid device node path '%s', ignoring.", resolved);
57e84e75
LP
4191 return 0;
4192 }
c9f620bf 4193 }
4ad49000 4194
c9f620bf 4195 if (!isempty(p) && !in_charset(p, "rwm")) {
323dda78 4196 log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid device rights '%s', ignoring.", p);
4ad49000
LP
4197 return 0;
4198 }
4199
fd870bac 4200 return cgroup_add_device_allow(c, resolved, p);
4ad49000
LP
4201}
4202
13c31542
TH
4203int config_parse_io_device_weight(
4204 const char *unit,
4205 const char *filename,
4206 unsigned line,
4207 const char *section,
4208 unsigned section_line,
4209 const char *lvalue,
4210 int ltype,
4211 const char *rvalue,
4212 void *data,
4213 void *userdata) {
4214
c9f620bf 4215 _cleanup_free_ char *path = NULL, *resolved = NULL;
13c31542
TH
4216 CGroupIODeviceWeight *w;
4217 CGroupContext *c = data;
99534007 4218 const char *p = ASSERT_PTR(rvalue);
13c31542 4219 uint64_t u;
13c31542
TH
4220 int r;
4221
4222 assert(filename);
4223 assert(lvalue);
13c31542
TH
4224
4225 if (isempty(rvalue)) {
4226 while (c->io_device_weights)
4227 cgroup_context_free_io_device_weight(c, c->io_device_weights);
4228
4229 return 0;
4230 }
4231
4ec85141 4232 r = extract_first_word(&p, &path, NULL, EXTRACT_UNQUOTE);
c9f620bf
YW
4233 if (r == -ENOMEM)
4234 return log_oom();
6a35d52d 4235 if (r < 0) {
c9f620bf 4236 log_syntax(unit, LOG_WARNING, filename, line, r,
c9f620bf 4237 "Failed to extract device path and weight from '%s', ignoring.", rvalue);
13c31542
TH
4238 return 0;
4239 }
6a35d52d
YW
4240 if (r == 0 || isempty(p)) {
4241 log_syntax(unit, LOG_WARNING, filename, line, 0,
4242 "Invalid device path or weight specified in '%s', ignoring.", rvalue);
4243 return 0;
4244 }
13c31542 4245
06536492 4246 r = unit_path_printf(userdata, path, &resolved);
c9f620bf
YW
4247 if (r < 0) {
4248 log_syntax(unit, LOG_WARNING, filename, line, r,
4249 "Failed to resolve unit specifiers in '%s', ignoring: %m", path);
4250 return 0;
4251 }
13c31542 4252
2f4d31c1
YW
4253 r = path_simplify_and_warn(resolved, 0, unit, filename, line, lvalue);
4254 if (r < 0)
4255 return 0;
4256
c9f620bf 4257 r = cg_weight_parse(p, &u);
13c31542 4258 if (r < 0) {
323dda78 4259 log_syntax(unit, LOG_WARNING, filename, line, r, "IO weight '%s' invalid, ignoring: %m", p);
13c31542
TH
4260 return 0;
4261 }
4262
4263 assert(u != CGROUP_WEIGHT_INVALID);
4264
4265 w = new0(CGroupIODeviceWeight, 1);
4266 if (!w)
4267 return log_oom();
4268
c9f620bf 4269 w->path = TAKE_PTR(resolved);
13c31542
TH
4270 w->weight = u;
4271
4272 LIST_PREPEND(device_weights, c->io_device_weights, w);
4273 return 0;
4274}
4275
6ae4283c
TH
4276int config_parse_io_device_latency(
4277 const char *unit,
4278 const char *filename,
4279 unsigned line,
4280 const char *section,
4281 unsigned section_line,
4282 const char *lvalue,
4283 int ltype,
4284 const char *rvalue,
4285 void *data,
4286 void *userdata) {
4287
4288 _cleanup_free_ char *path = NULL, *resolved = NULL;
4289 CGroupIODeviceLatency *l;
4290 CGroupContext *c = data;
99534007 4291 const char *p = ASSERT_PTR(rvalue);
6ae4283c
TH
4292 usec_t usec;
4293 int r;
4294
4295 assert(filename);
4296 assert(lvalue);
6ae4283c
TH
4297
4298 if (isempty(rvalue)) {
4299 while (c->io_device_latencies)
4300 cgroup_context_free_io_device_latency(c, c->io_device_latencies);
4301
4302 return 0;
4303 }
4304
4ec85141 4305 r = extract_first_word(&p, &path, NULL, EXTRACT_UNQUOTE);
6ae4283c
TH
4306 if (r == -ENOMEM)
4307 return log_oom();
6a35d52d 4308 if (r < 0) {
6ae4283c 4309 log_syntax(unit, LOG_WARNING, filename, line, r,
6ae4283c
TH
4310 "Failed to extract device path and latency from '%s', ignoring.", rvalue);
4311 return 0;
4312 }
6a35d52d
YW
4313 if (r == 0 || isempty(p)) {
4314 log_syntax(unit, LOG_WARNING, filename, line, 0,
4315 "Invalid device path or latency specified in '%s', ignoring.", rvalue);
4316 return 0;
4317 }
6ae4283c 4318
06536492 4319 r = unit_path_printf(userdata, path, &resolved);
6ae4283c
TH
4320 if (r < 0) {
4321 log_syntax(unit, LOG_WARNING, filename, line, r,
4322 "Failed to resolve unit specifiers in '%s', ignoring: %m", path);
4323 return 0;
4324 }
4325
4326 r = path_simplify_and_warn(resolved, 0, unit, filename, line, lvalue);
4327 if (r < 0)
4328 return 0;
4329
323dda78
YW
4330 r = parse_sec(p, &usec);
4331 if (r < 0) {
4332 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse timer value, ignoring: %s", p);
6ae4283c
TH
4333 return 0;
4334 }
4335
4336 l = new0(CGroupIODeviceLatency, 1);
4337 if (!l)
4338 return log_oom();
4339
4340 l->path = TAKE_PTR(resolved);
4341 l->target_usec = usec;
4342
4343 LIST_PREPEND(device_latencies, c->io_device_latencies, l);
4344 return 0;
4345}
4346
13c31542
TH
4347int config_parse_io_limit(
4348 const char *unit,
4349 const char *filename,
4350 unsigned line,
4351 const char *section,
4352 unsigned section_line,
4353 const char *lvalue,
4354 int ltype,
4355 const char *rvalue,
4356 void *data,
4357 void *userdata) {
4358
c9f620bf 4359 _cleanup_free_ char *path = NULL, *resolved = NULL;
03677889 4360 CGroupIODeviceLimit *l = NULL;
13c31542 4361 CGroupContext *c = data;
9be57249 4362 CGroupIOLimitType type;
99534007 4363 const char *p = ASSERT_PTR(rvalue);
13c31542 4364 uint64_t num;
13c31542
TH
4365 int r;
4366
4367 assert(filename);
4368 assert(lvalue);
13c31542 4369
9be57249
TH
4370 type = cgroup_io_limit_type_from_string(lvalue);
4371 assert(type >= 0);
13c31542
TH
4372
4373 if (isempty(rvalue)) {
03677889
YW
4374 LIST_FOREACH(device_limits, t, c->io_device_limits)
4375 t->limits[type] = cgroup_io_limit_defaults[type];
13c31542
TH
4376 return 0;
4377 }
4378
4ec85141 4379 r = extract_first_word(&p, &path, NULL, EXTRACT_UNQUOTE);
c9f620bf
YW
4380 if (r == -ENOMEM)
4381 return log_oom();
6a35d52d 4382 if (r < 0) {
c9f620bf 4383 log_syntax(unit, LOG_WARNING, filename, line, r,
c9f620bf 4384 "Failed to extract device node and bandwidth from '%s', ignoring.", rvalue);
13c31542
TH
4385 return 0;
4386 }
6a35d52d
YW
4387 if (r == 0 || isempty(p)) {
4388 log_syntax(unit, LOG_WARNING, filename, line, 0,
4389 "Invalid device node or bandwidth specified in '%s', ignoring.", rvalue);
4390 return 0;
4391 }
13c31542 4392
06536492 4393 r = unit_path_printf(userdata, path, &resolved);
c9f620bf
YW
4394 if (r < 0) {
4395 log_syntax(unit, LOG_WARNING, filename, line, r,
4396 "Failed to resolve unit specifiers in '%s', ignoring: %m", path);
4397 return 0;
4398 }
13c31542 4399
2f4d31c1
YW
4400 r = path_simplify_and_warn(resolved, 0, unit, filename, line, lvalue);
4401 if (r < 0)
4402 return 0;
4403
9d5e9b4a 4404 if (streq("infinity", p))
13c31542 4405 num = CGROUP_LIMIT_MAX;
9d5e9b4a 4406 else {
c9f620bf 4407 r = parse_size(p, 1000, &num);
13c31542 4408 if (r < 0 || num <= 0) {
323dda78 4409 log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid IO limit '%s', ignoring.", p);
13c31542
TH
4410 return 0;
4411 }
4412 }
4413
03677889 4414 LIST_FOREACH(device_limits, t, c->io_device_limits)
c9f620bf 4415 if (path_equal(resolved, t->path)) {
13c31542
TH
4416 l = t;
4417 break;
4418 }
13c31542
TH
4419
4420 if (!l) {
4421 l = new0(CGroupIODeviceLimit, 1);
4422 if (!l)
4423 return log_oom();
4424
c9f620bf 4425 l->path = TAKE_PTR(resolved);
24aaf6c6
ZJS
4426 for (CGroupIOLimitType i = 0; i < _CGROUP_IO_LIMIT_TYPE_MAX; i++)
4427 l->limits[i] = cgroup_io_limit_defaults[i];
13c31542
TH
4428
4429 LIST_PREPEND(device_limits, c->io_device_limits, l);
4430 }
4431
9be57249 4432 l->limits[type] = num;
13c31542
TH
4433
4434 return 0;
4435}
4436
8e7076ca
LP
4437int config_parse_blockio_device_weight(
4438 const char *unit,
4439 const char *filename,
4440 unsigned line,
4441 const char *section,
71a61510 4442 unsigned section_line,
8e7076ca
LP
4443 const char *lvalue,
4444 int ltype,
4445 const char *rvalue,
4446 void *data,
4447 void *userdata) {
4448
c9f620bf 4449 _cleanup_free_ char *path = NULL, *resolved = NULL;
8e7076ca 4450 CGroupBlockIODeviceWeight *w;
4ad49000 4451 CGroupContext *c = data;
99534007 4452 const char *p = ASSERT_PTR(rvalue);
d53d9474 4453 uint64_t u;
4ad49000
LP
4454 int r;
4455
4456 assert(filename);
4457 assert(lvalue);
4ad49000 4458
c1e701e2
LP
4459 log_syntax(unit, LOG_WARNING, filename, line, 0,
4460 "Unit uses %s=; please use IO*= settings instead. Support for %s= will be removed soon.",
4461 lvalue, lvalue);
4462
4ad49000 4463 if (isempty(rvalue)) {
4ad49000
LP
4464 while (c->blockio_device_weights)
4465 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
4466
4467 return 0;
4468 }
4469
4ec85141 4470 r = extract_first_word(&p, &path, NULL, EXTRACT_UNQUOTE);
c9f620bf
YW
4471 if (r == -ENOMEM)
4472 return log_oom();
6a35d52d 4473 if (r < 0) {
c9f620bf 4474 log_syntax(unit, LOG_WARNING, filename, line, r,
c9f620bf 4475 "Failed to extract device node and weight from '%s', ignoring.", rvalue);
8e7076ca
LP
4476 return 0;
4477 }
6a35d52d
YW
4478 if (r == 0 || isempty(p)) {
4479 log_syntax(unit, LOG_WARNING, filename, line, 0,
4480 "Invalid device node or weight specified in '%s', ignoring.", rvalue);
4481 return 0;
4482 }
4ad49000 4483
06536492 4484 r = unit_path_printf(userdata, path, &resolved);
c9f620bf
YW
4485 if (r < 0) {
4486 log_syntax(unit, LOG_WARNING, filename, line, r,
4487 "Failed to resolve unit specifiers in '%s', ignoring: %m", path);
4488 return 0;
4489 }
4ad49000 4490
2f4d31c1
YW
4491 r = path_simplify_and_warn(resolved, 0, unit, filename, line, lvalue);
4492 if (r < 0)
4493 return 0;
4494
c9f620bf 4495 r = cg_blkio_weight_parse(p, &u);
d53d9474 4496 if (r < 0) {
323dda78 4497 log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid block IO weight '%s', ignoring: %m", p);
4ad49000
LP
4498 return 0;
4499 }
4500
d53d9474
LP
4501 assert(u != CGROUP_BLKIO_WEIGHT_INVALID);
4502
8e7076ca
LP
4503 w = new0(CGroupBlockIODeviceWeight, 1);
4504 if (!w)
4505 return log_oom();
4ad49000 4506
c9f620bf 4507 w->path = TAKE_PTR(resolved);
d53d9474 4508 w->weight = u;
4ad49000 4509
71fda00f 4510 LIST_PREPEND(device_weights, c->blockio_device_weights, w);
4ad49000
LP
4511 return 0;
4512}
4513
4514int config_parse_blockio_bandwidth(
4515 const char *unit,
4516 const char *filename,
4517 unsigned line,
4518 const char *section,
71a61510 4519 unsigned section_line,
4ad49000
LP
4520 const char *lvalue,
4521 int ltype,
4522 const char *rvalue,
4523 void *data,
4524 void *userdata) {
4525
c9f620bf 4526 _cleanup_free_ char *path = NULL, *resolved = NULL;
03677889 4527 CGroupBlockIODeviceBandwidth *b = NULL;
4ad49000 4528 CGroupContext *c = data;
99534007 4529 const char *p = ASSERT_PTR(rvalue);
59f448cf 4530 uint64_t bytes;
47c0980d 4531 bool read;
4ad49000
LP
4532 int r;
4533
4534 assert(filename);
4535 assert(lvalue);
4ad49000 4536
c1e701e2
LP
4537 log_syntax(unit, LOG_WARNING, filename, line, 0,
4538 "Unit uses %s=; please use IO*= settings instead. Support for %s= will be removed soon.",
4539 lvalue, lvalue);
4540
47c0980d
G
4541 read = streq("BlockIOReadBandwidth", lvalue);
4542
4ad49000 4543 if (isempty(rvalue)) {
03677889
YW
4544 LIST_FOREACH(device_bandwidths, t, c->blockio_device_bandwidths) {
4545 t->rbps = CGROUP_LIMIT_MAX;
4546 t->wbps = CGROUP_LIMIT_MAX;
979d0311 4547 }
4ad49000
LP
4548 return 0;
4549 }
4550
4ec85141 4551 r = extract_first_word(&p, &path, NULL, EXTRACT_UNQUOTE);
c9f620bf
YW
4552 if (r == -ENOMEM)
4553 return log_oom();
6a35d52d 4554 if (r < 0) {
c9f620bf 4555 log_syntax(unit, LOG_WARNING, filename, line, r,
c9f620bf 4556 "Failed to extract device node and bandwidth from '%s', ignoring.", rvalue);
4ad49000
LP
4557 return 0;
4558 }
6a35d52d
YW
4559 if (r == 0 || isempty(p)) {
4560 log_syntax(unit, LOG_WARNING, filename, line, 0,
4561 "Invalid device node or bandwidth specified in '%s', ignoring.", rvalue);
4562 return 0;
4563 }
4ad49000 4564
06536492 4565 r = unit_path_printf(userdata, path, &resolved);
c9f620bf
YW
4566 if (r < 0) {
4567 log_syntax(unit, LOG_WARNING, filename, line, r,
4568 "Failed to resolve unit specifiers in '%s', ignoring: %m", path);
4569 return 0;
4570 }
4ad49000 4571
2f4d31c1
YW
4572 r = path_simplify_and_warn(resolved, 0, unit, filename, line, lvalue);
4573 if (r < 0)
4574 return 0;
4575
c9f620bf 4576 r = parse_size(p, 1000, &bytes);
4ad49000 4577 if (r < 0 || bytes <= 0) {
323dda78 4578 log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid Block IO Bandwidth '%s', ignoring.", p);
4ad49000
LP
4579 return 0;
4580 }
4581
03677889 4582 LIST_FOREACH(device_bandwidths, t, c->blockio_device_bandwidths)
c9f620bf 4583 if (path_equal(resolved, t->path)) {
979d0311
TH
4584 b = t;
4585 break;
4586 }
4ad49000 4587
03677889 4588 if (!b) {
979d0311
TH
4589 b = new0(CGroupBlockIODeviceBandwidth, 1);
4590 if (!b)
4591 return log_oom();
4592
c9f620bf 4593 b->path = TAKE_PTR(resolved);
979d0311
TH
4594 b->rbps = CGROUP_LIMIT_MAX;
4595 b->wbps = CGROUP_LIMIT_MAX;
4596
4597 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
4598 }
4ad49000 4599
979d0311
TH
4600 if (read)
4601 b->rbps = bytes;
4602 else
4603 b->wbps = bytes;
4ad49000
LP
4604
4605 return 0;
4606}
4607
d420282b
LP
4608int config_parse_job_mode_isolate(
4609 const char *unit,
4610 const char *filename,
4611 unsigned line,
4612 const char *section,
4613 unsigned section_line,
4614 const char *lvalue,
4615 int ltype,
4616 const char *rvalue,
4617 void *data,
4618 void *userdata) {
4619
4620 JobMode *m = data;
4621 int r;
4622
4623 assert(filename);
4624 assert(lvalue);
4625 assert(rvalue);
4626
4627 r = parse_boolean(rvalue);
4628 if (r < 0) {
323dda78 4629 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse boolean, ignoring: %s", rvalue);
d420282b
LP
4630 return 0;
4631 }
4632
8ab39347
YW
4633 log_notice("%s is deprecated. Please use OnFailureJobMode= instead", lvalue);
4634
d420282b
LP
4635 *m = r ? JOB_ISOLATE : JOB_REPLACE;
4636 return 0;
4637}
4638
3536f49e 4639int config_parse_exec_directories(
e66cf1a3
LP
4640 const char *unit,
4641 const char *filename,
4642 unsigned line,
4643 const char *section,
4644 unsigned section_line,
4645 const char *lvalue,
4646 int ltype,
4647 const char *rvalue,
4648 void *data,
4649 void *userdata) {
4650
99534007 4651 ExecDirectory *ed = ASSERT_PTR(data);
47538b76 4652 const Unit *u = userdata;
e66cf1a3
LP
4653 int r;
4654
4655 assert(filename);
4656 assert(lvalue);
4657 assert(rvalue);
e66cf1a3
LP
4658
4659 if (isempty(rvalue)) {
4660 /* Empty assignment resets the list */
211a3d87 4661 exec_directory_done(ed);
e66cf1a3
LP
4662 return 0;
4663 }
4664
323dda78 4665 for (const char *p = rvalue;;) {
211a3d87 4666 _cleanup_free_ char *tuple = NULL;
e66cf1a3 4667
211a3d87 4668 r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
035fe294 4669 if (r == -ENOMEM)
e66cf1a3 4670 return log_oom();
035fe294
ZJS
4671 if (r < 0) {
4672 log_syntax(unit, LOG_WARNING, filename, line, r,
211a3d87 4673 "Invalid syntax %s=%s, ignoring: %m", lvalue, rvalue);
035fe294
ZJS
4674 return 0;
4675 }
091e9efe
LP
4676 if (r == 0)
4677 return 0;
e66cf1a3 4678
211a3d87
LB
4679 _cleanup_free_ char *src = NULL, *dest = NULL;
4680 const char *q = tuple;
4681 r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &src, &dest, NULL);
4682 if (r == -ENOMEM)
4683 return log_oom();
4684 if (r <= 0) {
5afdb462 4685 log_syntax(unit, LOG_WARNING, filename, line, r,
211a3d87
LB
4686 "Invalid syntax in %s=, ignoring: %s", lvalue, tuple);
4687 return 0;
4688 }
4689
4690 _cleanup_free_ char *sresolved = NULL;
4691 r = unit_path_printf(u, src, &sresolved);
9b5864d9 4692 if (r < 0) {
330f8990 4693 log_syntax(unit, LOG_WARNING, filename, line, r,
211a3d87 4694 "Failed to resolve unit specifiers in \"%s\", ignoring: %m", src);
9b5864d9
MG
4695 continue;
4696 }
4697
211a3d87 4698 r = path_simplify_and_warn(sresolved, PATH_CHECK_RELATIVE, unit, filename, line, lvalue);
2f4d31c1 4699 if (r < 0)
e8865688 4700 continue;
e8865688 4701
211a3d87 4702 if (path_startswith(sresolved, "private")) {
330f8990 4703 log_syntax(unit, LOG_WARNING, filename, line, 0,
211a3d87 4704 "%s= path can't be 'private', ignoring assignment: %s", lvalue, tuple);
e66cf1a3
LP
4705 continue;
4706 }
4707
211a3d87
LB
4708 /* For State and Runtime directories we support an optional destination parameter, which
4709 * will be used to create a symlink to the source. */
564e5c98 4710 _cleanup_free_ char *dresolved = NULL;
211a3d87 4711 if (!isempty(dest)) {
211a3d87
LB
4712 if (streq(lvalue, "ConfigurationDirectory")) {
4713 log_syntax(unit, LOG_WARNING, filename, line, 0,
4714 "Destination parameter is not supported for ConfigurationDirectory, ignoring: %s", tuple);
4715 continue;
4716 }
4717
4718 r = unit_path_printf(u, dest, &dresolved);
4719 if (r < 0) {
4720 log_syntax(unit, LOG_WARNING, filename, line, r,
4721 "Failed to resolve unit specifiers in \"%s\", ignoring: %m", dest);
4722 continue;
4723 }
4724
4725 r = path_simplify_and_warn(dresolved, PATH_CHECK_RELATIVE, unit, filename, line, lvalue);
4726 if (r < 0)
4727 continue;
211a3d87
LB
4728 }
4729
564e5c98 4730 r = exec_directory_add(ed, sresolved, dresolved);
e66cf1a3
LP
4731 if (r < 0)
4732 return log_oom();
e66cf1a3 4733 }
e66cf1a3
LP
4734}
4735
bb0c0d6f
LP
4736int config_parse_set_credential(
4737 const char *unit,
4738 const char *filename,
4739 unsigned line,
4740 const char *section,
4741 unsigned section_line,
4742 const char *lvalue,
4743 int ltype,
4744 const char *rvalue,
4745 void *data,
4746 void *userdata) {
4747
43144be4
LP
4748 _cleanup_free_ char *word = NULL, *k = NULL;
4749 _cleanup_free_ void *d = NULL;
99534007 4750 ExecContext *context = ASSERT_PTR(data);
bb0c0d6f
LP
4751 ExecSetCredential *old;
4752 Unit *u = userdata;
43144be4 4753 bool encrypted = ltype;
99534007 4754 const char *p = ASSERT_PTR(rvalue);
43144be4
LP
4755 size_t size;
4756 int r;
bb0c0d6f
LP
4757
4758 assert(filename);
4759 assert(lvalue);
bb0c0d6f
LP
4760
4761 if (isempty(rvalue)) {
4762 /* Empty assignment resets the list */
4763 context->set_credentials = hashmap_free(context->set_credentials);
4764 return 0;
4765 }
4766
bb0c0d6f
LP
4767 r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
4768 if (r == -ENOMEM)
4769 return log_oom();
6a35d52d
YW
4770 if (r < 0) {
4771 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to extract credential name, ignoring: %s", rvalue);
4772 return 0;
4773 }
4774 if (r == 0 || isempty(p)) {
4775 log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid syntax, ignoring: %s", rvalue);
bb0c0d6f
LP
4776 return 0;
4777 }
4778
06536492 4779 r = unit_cred_printf(u, word, &k);
bb0c0d6f
LP
4780 if (r < 0) {
4781 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in \"%s\", ignoring: %m", word);
4782 return 0;
4783 }
4784 if (!credential_name_valid(k)) {
4785 log_syntax(unit, LOG_WARNING, filename, line, 0, "Credential name \"%s\" not valid, ignoring.", k);
4786 return 0;
4787 }
4788
43144be4
LP
4789 if (encrypted) {
4790 r = unbase64mem_full(p, SIZE_MAX, true, &d, &size);
4791 if (r < 0) {
4792 log_syntax(unit, LOG_WARNING, filename, line, r, "Encrypted credential data not valid Base64 data, ignoring.");
4793 return 0;
4794 }
4795 } else {
1421705d 4796 char *unescaped;
e437538f 4797 ssize_t l;
43144be4
LP
4798
4799 /* We support escape codes here, so that users can insert trailing \n if they like */
4800 l = cunescape(p, UNESCAPE_ACCEPT_NUL, &unescaped);
4801 if (l < 0) {
4802 log_syntax(unit, LOG_WARNING, filename, line, l, "Can't unescape \"%s\", ignoring: %m", p);
4803 return 0;
4804 }
4805
4806 d = unescaped;
4807 size = l;
bb0c0d6f
LP
4808 }
4809
4810 old = hashmap_get(context->set_credentials, k);
4811 if (old) {
43144be4
LP
4812 free_and_replace(old->data, d);
4813 old->size = size;
4814 old->encrypted = encrypted;
bb0c0d6f
LP
4815 } else {
4816 _cleanup_(exec_set_credential_freep) ExecSetCredential *sc = NULL;
4817
43144be4 4818 sc = new(ExecSetCredential, 1);
bb0c0d6f
LP
4819 if (!sc)
4820 return log_oom();
4821
43144be4
LP
4822 *sc = (ExecSetCredential) {
4823 .id = TAKE_PTR(k),
4824 .data = TAKE_PTR(d),
4825 .size = size,
4826 .encrypted = encrypted,
4827 };
bb0c0d6f 4828
f85f5f0d
SS
4829 r = hashmap_ensure_put(&context->set_credentials, &exec_set_credential_hash_ops, sc->id, sc);
4830 if (r == -ENOMEM)
4831 return log_oom();
2400743e 4832 if (r < 0) {
43144be4 4833 log_syntax(unit, LOG_WARNING, filename, line, r,
2400743e
YW
4834 "Duplicated credential value '%s', ignoring assignment: %s", sc->id, rvalue);
4835 return 0;
4836 }
bb0c0d6f 4837
bb0c0d6f
LP
4838 TAKE_PTR(sc);
4839 }
4840
4841 return 0;
4842}
4843
bbfb25f4
DDM
4844int hashmap_put_credential(Hashmap **h, const char *id, const char *path, bool encrypted) {
4845 ExecLoadCredential *old;
4846 int r;
4847
4848 assert(h);
4849 assert(id);
4850 assert(path);
4851
4852 old = hashmap_get(*h, id);
4853 if (old) {
4854 r = free_and_strdup(&old->path, path);
4855 if (r < 0)
4856 return r;
4857
4858 old->encrypted = encrypted;
4859 } else {
4860 _cleanup_(exec_load_credential_freep) ExecLoadCredential *lc = NULL;
4861
4862 lc = new(ExecLoadCredential, 1);
4863 if (!lc)
4864 return log_oom();
4865
4866 *lc = (ExecLoadCredential) {
4867 .id = strdup(id),
4868 .path = strdup(path),
4869 .encrypted = encrypted,
4870 };
4871 if (!lc->id || !lc->path)
4872 return -ENOMEM;
4873
4874 r = hashmap_ensure_put(h, &exec_load_credential_hash_ops, lc->id, lc);
4875 if (r < 0)
4876 return r;
4877
4878 TAKE_PTR(lc);
4879 }
4880
4881 return 0;
4882}
4883
bb0c0d6f
LP
4884int config_parse_load_credential(
4885 const char *unit,
4886 const char *filename,
4887 unsigned line,
4888 const char *section,
4889 unsigned section_line,
4890 const char *lvalue,
4891 int ltype,
4892 const char *rvalue,
4893 void *data,
4894 void *userdata) {
4895
4896 _cleanup_free_ char *word = NULL, *k = NULL, *q = NULL;
99534007 4897 ExecContext *context = ASSERT_PTR(data);
43144be4 4898 bool encrypted = ltype;
bb0c0d6f
LP
4899 Unit *u = userdata;
4900 const char *p;
4901 int r;
4902
4903 assert(filename);
4904 assert(lvalue);
4905 assert(rvalue);
bb0c0d6f
LP
4906
4907 if (isempty(rvalue)) {
4908 /* Empty assignment resets the list */
43144be4 4909 context->load_credentials = hashmap_free(context->load_credentials);
bb0c0d6f
LP
4910 return 0;
4911 }
4912
4913 p = rvalue;
4914 r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
4915 if (r == -ENOMEM)
4916 return log_oom();
4917 if (r <= 0) {
4918 log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
4919 return 0;
4920 }
4921
06536492 4922 r = unit_cred_printf(u, word, &k);
bb0c0d6f
LP
4923 if (r < 0) {
4924 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in \"%s\", ignoring: %m", word);
4925 return 0;
4926 }
4927 if (!credential_name_valid(k)) {
4928 log_syntax(unit, LOG_WARNING, filename, line, 0, "Credential name \"%s\" not valid, ignoring.", k);
4929 return 0;
4930 }
8a29862e
LP
4931
4932 if (isempty(p)) {
08a7e545 4933 /* If only one field is specified take it as shortcut for inheriting a credential named
8a29862e
LP
4934 * the same way from our parent */
4935 q = strdup(k);
4936 if (!q)
4937 return log_oom();
4938 } else {
06536492 4939 r = unit_path_printf(u, p, &q);
8a29862e
LP
4940 if (r < 0) {
4941 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in \"%s\", ignoring: %m", p);
4942 return 0;
4943 }
4944 if (path_is_absolute(q) ? !path_is_normalized(q) : !credential_name_valid(q)) {
43144be4 4945 log_syntax(unit, LOG_WARNING, filename, line, 0, "Credential source \"%s\" not valid, ignoring.", q);
8a29862e
LP
4946 return 0;
4947 }
bb0c0d6f
LP
4948 }
4949
bbfb25f4
DDM
4950 r = hashmap_put_credential(&context->load_credentials, k, q, encrypted);
4951 if (r < 0)
4952 return log_error_errno(r, "Failed to store load credential '%s': %m", rvalue);
43144be4 4953
bbfb25f4
DDM
4954 return 0;
4955}
43144be4 4956
bbfb25f4
DDM
4957int config_parse_import_credential(
4958 const char *unit,
4959 const char *filename,
4960 unsigned line,
4961 const char *section,
4962 unsigned section_line,
4963 const char *lvalue,
4964 int ltype,
4965 const char *rvalue,
4966 void *data,
4967 void *userdata) {
43144be4 4968
bbfb25f4
DDM
4969 _cleanup_free_ char *s = NULL;
4970 Set** import_credentials = ASSERT_PTR(data);
4971 Unit *u = userdata;
4972 int r;
43144be4 4973
bbfb25f4
DDM
4974 assert(filename);
4975 assert(lvalue);
4976 assert(rvalue);
4977
4978 if (isempty(rvalue)) {
4979 /* Empty assignment resets the list */
4980 *import_credentials = set_free(*import_credentials);
4981 return 0;
4982 }
4983
4984 r = unit_cred_printf(u, rvalue, &s);
4985 if (r < 0) {
4986 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in \"%s\", ignoring: %m", s);
4987 return 0;
4988 }
947c4d39
LP
4989 if (!credential_glob_valid(s)) {
4990 log_syntax(unit, LOG_WARNING, filename, line, 0, "Credential name or glob \"%s\" not valid, ignoring.", s);
bbfb25f4 4991 return 0;
43144be4 4992 }
bb0c0d6f 4993
bbfb25f4
DDM
4994 r = set_put_strdup(import_credentials, s);
4995 if (r < 0)
4996 return log_error_errno(r, "Failed to store credential name '%s': %m", rvalue);
4997
bb0c0d6f
LP
4998 return 0;
4999}
5000
3af00fb8
LP
5001int config_parse_set_status(
5002 const char *unit,
5003 const char *filename,
5004 unsigned line,
5005 const char *section,
5006 unsigned section_line,
5007 const char *lvalue,
5008 int ltype,
5009 const char *rvalue,
5010 void *data,
5011 void *userdata) {
5012
99534007 5013 ExitStatusSet *status_set = ASSERT_PTR(data);
7896ad8f 5014 int r;
3af00fb8
LP
5015
5016 assert(filename);
5017 assert(lvalue);
5018 assert(rvalue);
3af00fb8 5019
3e2d435b 5020 /* Empty assignment resets the list */
3af00fb8 5021 if (isempty(rvalue)) {
3e2d435b 5022 exit_status_set_free(status_set);
3af00fb8
LP
5023 return 0;
5024 }
5025
7896ad8f
ZJS
5026 for (const char *p = rvalue;;) {
5027 _cleanup_free_ char *word = NULL;
23d5dd16 5028 Bitmap *bitmap;
3af00fb8 5029
7896ad8f 5030 r = extract_first_word(&p, &word, NULL, 0);
323dda78
YW
5031 if (r == -ENOMEM)
5032 return log_oom();
5033 if (r < 0) {
5034 log_syntax(unit, LOG_WARNING, filename, line, r,
5035 "Failed to parse %s=%s, ignoring: %m", lvalue, rvalue);
5036 return 0;
5037 }
7896ad8f
ZJS
5038 if (r == 0)
5039 return 0;
3af00fb8 5040
2e2ed880
ZJS
5041 /* We need to call exit_status_from_string() first, because we want
5042 * to parse numbers as exit statuses, not signals. */
3af00fb8 5043
7896ad8f 5044 r = exit_status_from_string(word);
2e2ed880
ZJS
5045 if (r >= 0) {
5046 assert(r >= 0 && r < 256);
5047 bitmap = &status_set->status;
3af00fb8 5048 } else {
7896ad8f
ZJS
5049 r = signal_from_string(word);
5050 if (r < 0) {
b98680b2 5051 log_syntax(unit, LOG_WARNING, filename, line, r,
2e2ed880 5052 "Failed to parse value, ignoring: %s", word);
1e2fd62d 5053 continue;
3af00fb8 5054 }
2e2ed880 5055 bitmap = &status_set->signal;
3af00fb8 5056 }
1e2fd62d 5057
2e2ed880 5058 r = bitmap_set(bitmap, r);
063c4b1a 5059 if (r < 0)
323dda78
YW
5060 log_syntax(unit, LOG_WARNING, filename, line, r,
5061 "Failed to set signal or status %s, ignoring: %m", word);
3af00fb8 5062 }
3af00fb8
LP
5063}
5064
94828d2d
LP
5065int config_parse_namespace_path_strv(
5066 const char *unit,
5067 const char *filename,
5068 unsigned line,
5069 const char *section,
5070 unsigned section_line,
5071 const char *lvalue,
5072 int ltype,
5073 const char *rvalue,
5074 void *data,
5075 void *userdata) {
5076
47538b76 5077 const Unit *u = userdata;
99534007 5078 char*** sv = ASSERT_PTR(data);
94828d2d
LP
5079 int r;
5080
5081 assert(filename);
5082 assert(lvalue);
5083 assert(rvalue);
94828d2d
LP
5084
5085 if (isempty(rvalue)) {
5086 /* Empty assignment resets the list */
6796073e 5087 *sv = strv_free(*sv);
94828d2d
LP
5088 return 0;
5089 }
5090
323dda78 5091 for (const char *p = rvalue;;) {
7b07e993 5092 _cleanup_free_ char *word = NULL, *resolved = NULL, *joined = NULL;
20b7a007
LP
5093 const char *w;
5094 bool ignore_enoent = false, shall_prefix = false;
94828d2d 5095
4ec85141 5096 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
0293a7a8
EV
5097 if (r == -ENOMEM)
5098 return log_oom();
727f76d7 5099 if (r < 0) {
323dda78 5100 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to extract first word, ignoring: %s", rvalue);
727f76d7
EV
5101 return 0;
5102 }
a687f500
ZJS
5103 if (r == 0)
5104 break;
94828d2d 5105
20b7a007
LP
5106 w = word;
5107 if (startswith(w, "-")) {
5108 ignore_enoent = true;
5109 w++;
5110 }
5111 if (startswith(w, "+")) {
5112 shall_prefix = true;
5113 w++;
5114 }
7b07e993 5115
06536492 5116 r = unit_path_printf(u, w, &resolved);
7b07e993 5117 if (r < 0) {
323dda78 5118 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in %s: %m", w);
94828d2d
LP
5119 continue;
5120 }
5121
2f4d31c1
YW
5122 r = path_simplify_and_warn(resolved, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
5123 if (r < 0)
7b07e993 5124 continue;
94828d2d 5125
20b7a007
LP
5126 joined = strjoin(ignore_enoent ? "-" : "",
5127 shall_prefix ? "+" : "",
5128 resolved);
7b07e993
LP
5129
5130 r = strv_push(sv, joined);
94828d2d
LP
5131 if (r < 0)
5132 return log_oom();
5133
7b07e993 5134 joined = NULL;
94828d2d
LP
5135 }
5136
5137 return 0;
5138}
5139
2abd4e38
YW
5140int config_parse_temporary_filesystems(
5141 const char *unit,
5142 const char *filename,
5143 unsigned line,
5144 const char *section,
5145 unsigned section_line,
5146 const char *lvalue,
5147 int ltype,
5148 const char *rvalue,
5149 void *data,
5150 void *userdata) {
5151
47538b76 5152 const Unit *u = userdata;
99534007 5153 ExecContext *c = ASSERT_PTR(data);
2abd4e38
YW
5154 int r;
5155
5156 assert(filename);
5157 assert(lvalue);
5158 assert(rvalue);
2abd4e38
YW
5159
5160 if (isempty(rvalue)) {
5161 /* Empty assignment resets the list */
5162 temporary_filesystem_free_many(c->temporary_filesystems, c->n_temporary_filesystems);
5163 c->temporary_filesystems = NULL;
5164 c->n_temporary_filesystems = 0;
5165 return 0;
5166 }
5167
323dda78 5168 for (const char *p = rvalue;;) {
2abd4e38
YW
5169 _cleanup_free_ char *word = NULL, *path = NULL, *resolved = NULL;
5170 const char *w;
5171
4ec85141 5172 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
2abd4e38
YW
5173 if (r == -ENOMEM)
5174 return log_oom();
5175 if (r < 0) {
323dda78 5176 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to extract first word, ignoring: %s", rvalue);
2abd4e38
YW
5177 return 0;
5178 }
a687f500
ZJS
5179 if (r == 0)
5180 return 0;
2abd4e38
YW
5181
5182 w = word;
5183 r = extract_first_word(&w, &path, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
063c4b1a
YW
5184 if (r == -ENOMEM)
5185 return log_oom();
5186 if (r < 0) {
323dda78 5187 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to extract first word, ignoring: %s", word);
063c4b1a
YW
5188 continue;
5189 }
5190 if (r == 0) {
323dda78 5191 log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid syntax, ignoring: %s", word);
063c4b1a
YW
5192 continue;
5193 }
2abd4e38 5194
06536492 5195 r = unit_path_printf(u, path, &resolved);
2abd4e38 5196 if (r < 0) {
323dda78 5197 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", path);
2abd4e38
YW
5198 continue;
5199 }
5200
2f4d31c1
YW
5201 r = path_simplify_and_warn(resolved, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
5202 if (r < 0)
2abd4e38 5203 continue;
2abd4e38 5204
a26fec24 5205 r = temporary_filesystem_add(&c->temporary_filesystems, &c->n_temporary_filesystems, resolved, w);
6302d1ea 5206 if (r < 0)
2abd4e38 5207 return log_oom();
2abd4e38 5208 }
2abd4e38
YW
5209}
5210
d2d6c096
LP
5211int config_parse_bind_paths(
5212 const char *unit,
5213 const char *filename,
5214 unsigned line,
5215 const char *section,
5216 unsigned section_line,
5217 const char *lvalue,
5218 int ltype,
5219 const char *rvalue,
5220 void *data,
5221 void *userdata) {
5222
99534007 5223 ExecContext *c = ASSERT_PTR(data);
47538b76 5224 const Unit *u = userdata;
d2d6c096
LP
5225 int r;
5226
5227 assert(filename);
5228 assert(lvalue);
5229 assert(rvalue);
d2d6c096
LP
5230
5231 if (isempty(rvalue)) {
5232 /* Empty assignment resets the list */
5233 bind_mount_free_many(c->bind_mounts, c->n_bind_mounts);
5234 c->bind_mounts = NULL;
5235 c->n_bind_mounts = 0;
5236 return 0;
5237 }
5238
323dda78 5239 for (const char *p = rvalue;;) {
d2d6c096 5240 _cleanup_free_ char *source = NULL, *destination = NULL;
42d43f21 5241 _cleanup_free_ char *sresolved = NULL, *dresolved = NULL;
d2d6c096
LP
5242 char *s = NULL, *d = NULL;
5243 bool rbind = true, ignore_enoent = false;
5244
4ec85141 5245 r = extract_first_word(&p, &source, ":" WHITESPACE, EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS);
d2d6c096
LP
5246 if (r == -ENOMEM)
5247 return log_oom();
5248 if (r < 0) {
323dda78 5249 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse %s, ignoring: %s", lvalue, rvalue);
d2d6c096
LP
5250 return 0;
5251 }
a687f500
ZJS
5252 if (r == 0)
5253 break;
d2d6c096 5254
06536492 5255 r = unit_full_printf_full(u, source, PATH_MAX, &sresolved);
42d43f21 5256 if (r < 0) {
323dda78 5257 log_syntax(unit, LOG_WARNING, filename, line, r,
556a7bbe 5258 "Failed to resolve unit specifiers in \"%s\", ignoring: %m", source);
2f4d31c1 5259 continue;
42d43f21
DC
5260 }
5261
5262 s = sresolved;
d2d6c096
LP
5263 if (s[0] == '-') {
5264 ignore_enoent = true;
5265 s++;
5266 }
5267
2f4d31c1
YW
5268 r = path_simplify_and_warn(s, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
5269 if (r < 0)
5270 continue;
d2d6c096
LP
5271
5272 /* Optionally, the destination is specified. */
5273 if (p && p[-1] == ':') {
4ec85141 5274 r = extract_first_word(&p, &destination, ":" WHITESPACE, EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS);
d2d6c096
LP
5275 if (r == -ENOMEM)
5276 return log_oom();
5277 if (r < 0) {
323dda78 5278 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse %s, ignoring: %s", lvalue, rvalue);
d2d6c096
LP
5279 return 0;
5280 }
5281 if (r == 0) {
323dda78 5282 log_syntax(unit, LOG_WARNING, filename, line, 0, "Missing argument after ':', ignoring: %s", s);
2f4d31c1 5283 continue;
d2d6c096
LP
5284 }
5285
06536492 5286 r = unit_path_printf(u, destination, &dresolved);
42d43f21 5287 if (r < 0) {
323dda78 5288 log_syntax(unit, LOG_WARNING, filename, line, r,
556a7bbe 5289 "Failed to resolve specifiers in \"%s\", ignoring: %m", destination);
2f4d31c1 5290 continue;
42d43f21
DC
5291 }
5292
2f4d31c1
YW
5293 r = path_simplify_and_warn(dresolved, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
5294 if (r < 0)
5295 continue;
d2d6c096 5296
2f4d31c1 5297 d = dresolved;
d2d6c096
LP
5298
5299 /* Optionally, there's also a short option string specified */
5300 if (p && p[-1] == ':') {
5301 _cleanup_free_ char *options = NULL;
5302
4ec85141 5303 r = extract_first_word(&p, &options, NULL, EXTRACT_UNQUOTE);
d2d6c096
LP
5304 if (r == -ENOMEM)
5305 return log_oom();
5306 if (r < 0) {
6a35d52d 5307 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse %s=, ignoring: %s", lvalue, rvalue);
d2d6c096
LP
5308 return 0;
5309 }
5310
5311 if (isempty(options) || streq(options, "rbind"))
5312 rbind = true;
5313 else if (streq(options, "norbind"))
5314 rbind = false;
5315 else {
323dda78 5316 log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid option string, ignoring setting: %s", options);
2f4d31c1 5317 continue;
d2d6c096
LP
5318 }
5319 }
5320 } else
5321 d = s;
5322
5323 r = bind_mount_add(&c->bind_mounts, &c->n_bind_mounts,
5324 &(BindMount) {
5325 .source = s,
5326 .destination = d,
5327 .read_only = !!strstr(lvalue, "ReadOnly"),
5328 .recursive = rbind,
5329 .ignore_enoent = ignore_enoent,
5330 });
5331 if (r < 0)
5332 return log_oom();
5333 }
5334
5335 return 0;
5336}
5337
b3d13314
LB
5338int config_parse_mount_images(
5339 const char *unit,
5340 const char *filename,
5341 unsigned line,
5342 const char *section,
5343 unsigned section_line,
5344 const char *lvalue,
5345 int ltype,
5346 const char *rvalue,
5347 void *data,
5348 void *userdata) {
5349
99534007 5350 ExecContext *c = ASSERT_PTR(data);
b3d13314 5351 const Unit *u = userdata;
b3d13314
LB
5352 int r;
5353
5354 assert(filename);
5355 assert(lvalue);
5356 assert(rvalue);
b3d13314
LB
5357
5358 if (isempty(rvalue)) {
5359 /* Empty assignment resets the list */
5360 c->mount_images = mount_image_free_many(c->mount_images, &c->n_mount_images);
5361 return 0;
5362 }
5363
323dda78 5364 for (const char *p = rvalue;;) {
427353f6
LB
5365 _cleanup_(mount_options_free_allp) MountOptions *options = NULL;
5366 _cleanup_free_ char *first = NULL, *second = NULL, *tuple = NULL;
b3d13314 5367 _cleanup_free_ char *sresolved = NULL, *dresolved = NULL;
427353f6 5368 const char *q = NULL;
b3d13314
LB
5369 char *s = NULL;
5370 bool permissive = false;
5371
427353f6 5372 r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
323dda78
YW
5373 if (r == -ENOMEM)
5374 return log_oom();
5375 if (r < 0) {
5376 log_syntax(unit, LOG_WARNING, filename, line, r,
5377 "Invalid syntax %s=%s, ignoring: %m", lvalue, rvalue);
5378 return 0;
5379 }
427353f6 5380 if (r == 0)
323dda78 5381 return 0;
427353f6
LB
5382
5383 q = tuple;
5384 r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &first, &second, NULL);
323dda78
YW
5385 if (r == -ENOMEM)
5386 return log_oom();
5387 if (r < 0) {
5388 log_syntax(unit, LOG_WARNING, filename, line, r,
5389 "Invalid syntax in %s=, ignoring: %s", lvalue, tuple);
5390 return 0;
5391 }
427353f6
LB
5392 if (r == 0)
5393 continue;
5394
6c3f7ca0 5395 s = first;
b3d13314
LB
5396 if (s[0] == '-') {
5397 permissive = true;
5398 s++;
5399 }
5400
06536492 5401 r = unit_path_printf(u, s, &sresolved);
6c3f7ca0
LB
5402 if (r < 0) {
5403 log_syntax(unit, LOG_WARNING, filename, line, r,
5404 "Failed to resolve unit specifiers in \"%s\", ignoring: %m", s);
5405 continue;
5406 }
5407
5408 r = path_simplify_and_warn(sresolved, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
b3d13314
LB
5409 if (r < 0)
5410 continue;
5411
427353f6 5412 if (isempty(second)) {
323dda78 5413 log_syntax(unit, LOG_WARNING, filename, line, 0, "Missing destination in %s, ignoring: %s", lvalue, rvalue);
b3d13314
LB
5414 continue;
5415 }
5416
06536492 5417 r = unit_path_printf(u, second, &dresolved);
b3d13314 5418 if (r < 0) {
323dda78 5419 log_syntax(unit, LOG_WARNING, filename, line, r,
427353f6 5420 "Failed to resolve specifiers in \"%s\", ignoring: %m", second);
b3d13314
LB
5421 continue;
5422 }
5423
5424 r = path_simplify_and_warn(dresolved, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
5425 if (r < 0)
5426 continue;
5427
427353f6
LB
5428 for (;;) {
5429 _cleanup_free_ char *partition = NULL, *mount_options = NULL, *mount_options_resolved = NULL;
5430 MountOptions *o = NULL;
569a0e42 5431 PartitionDesignator partition_designator;
427353f6
LB
5432
5433 r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options, NULL);
323dda78
YW
5434 if (r == -ENOMEM)
5435 return log_oom();
5436 if (r < 0) {
5437 log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", q);
5438 return 0;
5439 }
427353f6
LB
5440 if (r == 0)
5441 break;
5442 /* Single set of options, applying to the root partition/single filesystem */
5443 if (r == 1) {
5444 r = unit_full_printf(u, partition, &mount_options_resolved);
5445 if (r < 0) {
323dda78 5446 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", first);
427353f6
LB
5447 continue;
5448 }
5449
5450 o = new(MountOptions, 1);
5451 if (!o)
5452 return log_oom();
5453 *o = (MountOptions) {
5454 .partition_designator = PARTITION_ROOT,
5455 .options = TAKE_PTR(mount_options_resolved),
5456 };
5457 LIST_APPEND(mount_options, options, o);
5458
5459 break;
5460 }
5461
5462 partition_designator = partition_designator_from_string(partition);
5463 if (partition_designator < 0) {
b98680b2
YW
5464 log_syntax(unit, LOG_WARNING, filename, line, partition_designator,
5465 "Invalid partition name %s, ignoring", partition);
427353f6
LB
5466 continue;
5467 }
5468 r = unit_full_printf(u, mount_options, &mount_options_resolved);
5469 if (r < 0) {
323dda78 5470 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", mount_options);
427353f6
LB
5471 continue;
5472 }
5473
5474 o = new(MountOptions, 1);
5475 if (!o)
5476 return log_oom();
5477 *o = (MountOptions) {
5478 .partition_designator = partition_designator,
5479 .options = TAKE_PTR(mount_options_resolved),
5480 };
5481 LIST_APPEND(mount_options, options, o);
5482 }
5483
b3d13314
LB
5484 r = mount_image_add(&c->mount_images, &c->n_mount_images,
5485 &(MountImage) {
6c3f7ca0 5486 .source = sresolved,
b3d13314 5487 .destination = dresolved,
427353f6 5488 .mount_options = options,
b3d13314 5489 .ignore_enoent = permissive,
93f59701
LB
5490 .type = MOUNT_IMAGE_DISCRETE,
5491 });
5492 if (r < 0)
5493 return log_oom();
5494 }
5495}
5496
5497int config_parse_extension_images(
5498 const char *unit,
5499 const char *filename,
5500 unsigned line,
5501 const char *section,
5502 unsigned section_line,
5503 const char *lvalue,
5504 int ltype,
5505 const char *rvalue,
5506 void *data,
5507 void *userdata) {
5508
99534007 5509 ExecContext *c = ASSERT_PTR(data);
93f59701
LB
5510 const Unit *u = userdata;
5511 int r;
5512
5513 assert(filename);
5514 assert(lvalue);
5515 assert(rvalue);
93f59701
LB
5516
5517 if (isempty(rvalue)) {
5518 /* Empty assignment resets the list */
5519 c->extension_images = mount_image_free_many(c->extension_images, &c->n_extension_images);
5520 return 0;
5521 }
5522
5523 for (const char *p = rvalue;;) {
5524 _cleanup_free_ char *source = NULL, *tuple = NULL, *sresolved = NULL;
5525 _cleanup_(mount_options_free_allp) MountOptions *options = NULL;
5526 bool permissive = false;
5527 const char *q = NULL;
5528 char *s = NULL;
5529
5530 r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
5531 if (r == -ENOMEM)
5532 return log_oom();
5533 if (r < 0) {
5534 log_syntax(unit, LOG_WARNING, filename, line, r,
5535 "Invalid syntax %s=%s, ignoring: %m", lvalue, rvalue);
5536 return 0;
5537 }
5538 if (r == 0)
5539 return 0;
5540
5541 q = tuple;
5542 r = extract_first_word(&q, &source, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS);
5543 if (r == -ENOMEM)
5544 return log_oom();
5545 if (r < 0) {
5546 log_syntax(unit, LOG_WARNING, filename, line, r,
5547 "Invalid syntax in %s=, ignoring: %s", lvalue, tuple);
5548 return 0;
5549 }
5550 if (r == 0)
5551 continue;
5552
5553 s = source;
5554 if (s[0] == '-') {
5555 permissive = true;
5556 s++;
5557 }
5558
06536492 5559 r = unit_path_printf(u, s, &sresolved);
93f59701
LB
5560 if (r < 0) {
5561 log_syntax(unit, LOG_WARNING, filename, line, r,
5562 "Failed to resolve unit specifiers in \"%s\", ignoring: %m", s);
5563 continue;
5564 }
5565
5566 r = path_simplify_and_warn(sresolved, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
5567 if (r < 0)
5568 continue;
5569
5570 for (;;) {
5571 _cleanup_free_ char *partition = NULL, *mount_options = NULL, *mount_options_resolved = NULL;
5572 MountOptions *o = NULL;
5573 PartitionDesignator partition_designator;
5574
5575 r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options, NULL);
5576 if (r == -ENOMEM)
5577 return log_oom();
5578 if (r < 0) {
5579 log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", q);
5580 return 0;
5581 }
5582 if (r == 0)
5583 break;
5584 /* Single set of options, applying to the root partition/single filesystem */
5585 if (r == 1) {
5586 r = unit_full_printf(u, partition, &mount_options_resolved);
5587 if (r < 0) {
5588 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", partition);
5589 continue;
5590 }
5591
5592 o = new(MountOptions, 1);
5593 if (!o)
5594 return log_oom();
5595 *o = (MountOptions) {
5596 .partition_designator = PARTITION_ROOT,
5597 .options = TAKE_PTR(mount_options_resolved),
5598 };
5599 LIST_APPEND(mount_options, options, o);
5600
5601 break;
5602 }
5603
5604 partition_designator = partition_designator_from_string(partition);
5605 if (partition_designator < 0) {
5606 log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid partition name %s, ignoring", partition);
5607 continue;
5608 }
5609 r = unit_full_printf(u, mount_options, &mount_options_resolved);
5610 if (r < 0) {
5611 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", mount_options);
5612 continue;
5613 }
5614
5615 o = new(MountOptions, 1);
5616 if (!o)
5617 return log_oom();
5618 *o = (MountOptions) {
5619 .partition_designator = partition_designator,
5620 .options = TAKE_PTR(mount_options_resolved),
5621 };
5622 LIST_APPEND(mount_options, options, o);
5623 }
5624
5625 r = mount_image_add(&c->extension_images, &c->n_extension_images,
5626 &(MountImage) {
5627 .source = sresolved,
5628 .mount_options = options,
5629 .ignore_enoent = permissive,
5630 .type = MOUNT_IMAGE_EXTENSION,
b3d13314
LB
5631 });
5632 if (r < 0)
5633 return log_oom();
5634 }
b3d13314
LB
5635}
5636
eae51da3
LP
5637int config_parse_job_timeout_sec(
5638 const char* unit,
5639 const char *filename,
5640 unsigned line,
5641 const char *section,
5642 unsigned section_line,
5643 const char *lvalue,
5644 int ltype,
5645 const char *rvalue,
5646 void *data,
5647 void *userdata) {
5648
99534007 5649 Unit *u = ASSERT_PTR(data);
eae51da3
LP
5650 usec_t usec;
5651 int r;
5652
5653 assert(filename);
5654 assert(lvalue);
5655 assert(rvalue);
eae51da3
LP
5656
5657 r = parse_sec_fix_0(rvalue, &usec);
5658 if (r < 0) {
323dda78 5659 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse JobTimeoutSec= parameter, ignoring: %s", rvalue);
eae51da3
LP
5660 return 0;
5661 }
5662
5663 /* If the user explicitly changed JobTimeoutSec= also change JobRunningTimeoutSec=, for compatibility with old
c05f3c8f 5664 * versions. If JobRunningTimeoutSec= was explicitly set, avoid this however as whatever the user picked should
eae51da3
LP
5665 * count. */
5666
5667 if (!u->job_running_timeout_set)
5668 u->job_running_timeout = usec;
5669
5670 u->job_timeout = usec;
5671
5672 return 0;
5673}
5674
5675int config_parse_job_running_timeout_sec(
5676 const char* unit,
5677 const char *filename,
5678 unsigned line,
5679 const char *section,
5680 unsigned section_line,
5681 const char *lvalue,
5682 int ltype,
5683 const char *rvalue,
5684 void *data,
5685 void *userdata) {
5686
99534007 5687 Unit *u = ASSERT_PTR(data);
eae51da3
LP
5688 usec_t usec;
5689 int r;
5690
5691 assert(filename);
5692 assert(lvalue);
5693 assert(rvalue);
eae51da3
LP
5694
5695 r = parse_sec_fix_0(rvalue, &usec);
5696 if (r < 0) {
323dda78 5697 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse JobRunningTimeoutSec= parameter, ignoring: %s", rvalue);
eae51da3
LP
5698 return 0;
5699 }
5700
5701 u->job_running_timeout = usec;
5702 u->job_running_timeout_set = true;
5703
5704 return 0;
5705}
5706
54fcb619
ZJS
5707int config_parse_emergency_action(
5708 const char* unit,
5709 const char *filename,
5710 unsigned line,
5711 const char *section,
5712 unsigned section_line,
5713 const char *lvalue,
5714 int ltype,
5715 const char *rvalue,
5716 void *data,
5717 void *userdata) {
5718
99534007 5719 EmergencyAction *x = ASSERT_PTR(data);
4870133b 5720 RuntimeScope runtime_scope;
54fcb619
ZJS
5721 int r;
5722
5723 assert(filename);
5724 assert(lvalue);
5725 assert(rvalue);
54fcb619 5726
724f061d 5727 /* If we have a unit determine the scope based on it */
54fcb619 5728 if (unit)
4870133b 5729 runtime_scope = ((Unit*) ASSERT_PTR(userdata))->manager->runtime_scope;
54fcb619 5730 else
4870133b 5731 runtime_scope = ltype; /* otherwise, assume the scope is passed in via ltype */
54fcb619 5732
4870133b 5733 r = parse_emergency_action(rvalue, runtime_scope, x);
54fcb619
ZJS
5734 if (r < 0) {
5735 if (r == -EOPNOTSUPP)
323dda78 5736 log_syntax(unit, LOG_WARNING, filename, line, r,
54fcb619 5737 "%s= specified as %s mode action, ignoring: %s",
4870133b 5738 lvalue, runtime_scope_to_string(runtime_scope), rvalue);
54fcb619 5739 else
323dda78 5740 log_syntax(unit, LOG_WARNING, filename, line, r,
54fcb619
ZJS
5741 "Failed to parse %s=, ignoring: %s", lvalue, rvalue);
5742 return 0;
5743 }
5744
5745 return 0;
5746}
5747
a9353a5c
LP
5748int config_parse_pid_file(
5749 const char *unit,
5750 const char *filename,
5751 unsigned line,
5752 const char *section,
5753 unsigned section_line,
5754 const char *lvalue,
5755 int ltype,
5756 const char *rvalue,
5757 void *data,
5758 void *userdata) {
5759
5760 _cleanup_free_ char *k = NULL, *n = NULL;
99534007 5761 const Unit *u = ASSERT_PTR(userdata);
a9353a5c 5762 char **s = data;
a9353a5c
LP
5763 int r;
5764
5765 assert(filename);
5766 assert(lvalue);
5767 assert(rvalue);
a9353a5c 5768
b8055c05
YW
5769 if (isempty(rvalue)) {
5770 /* An empty assignment removes already set value. */
5771 *s = mfree(*s);
5772 return 0;
5773 }
5774
06536492 5775 r = unit_path_printf(u, rvalue, &k);
a9353a5c 5776 if (r < 0) {
323dda78 5777 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
a9353a5c
LP
5778 return 0;
5779 }
5780
5781 /* If this is a relative path make it absolute by prefixing the /run */
5782 n = path_make_absolute(k, u->manager->prefix[EXEC_DIRECTORY_RUNTIME]);
5783 if (!n)
5784 return log_oom();
5785
5786 /* Check that the result is a sensible path */
5787 r = path_simplify_and_warn(n, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
5788 if (r < 0)
5789 return r;
5790
4a66b5c9
LP
5791 r = patch_var_run(unit, filename, line, lvalue, &n);
5792 if (r < 0)
5793 return r;
a9353a5c 5794
4a66b5c9 5795 free_and_replace(*s, n);
a9353a5c
LP
5796 return 0;
5797}
5798
7af67e9a
LP
5799int config_parse_exit_status(
5800 const char *unit,
5801 const char *filename,
5802 unsigned line,
5803 const char *section,
5804 unsigned section_line,
5805 const char *lvalue,
5806 int ltype,
5807 const char *rvalue,
5808 void *data,
5809 void *userdata) {
5810
5811 int *exit_status = data, r;
5812 uint8_t u;
5813
5814 assert(filename);
5815 assert(lvalue);
5816 assert(rvalue);
5817 assert(exit_status);
5818
5819 if (isempty(rvalue)) {
5820 *exit_status = -1;
5821 return 0;
5822 }
5823
5824 r = safe_atou8(rvalue, &u);
5825 if (r < 0) {
323dda78 5826 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse exit status '%s', ignoring: %m", rvalue);
7af67e9a
LP
5827 return 0;
5828 }
5829
5830 *exit_status = u;
5831 return 0;
5832}
5833
c72703e2
CD
5834int config_parse_disable_controllers(
5835 const char *unit,
5836 const char *filename,
5837 unsigned line,
5838 const char *section,
5839 unsigned section_line,
5840 const char *lvalue,
5841 int ltype,
5842 const char *rvalue,
5843 void *data,
5844 void *userdata) {
5845
5846 int r;
5847 CGroupContext *c = data;
5848 CGroupMask disabled_mask;
5849
5850 /* 1. If empty, make all controllers eligible for use again.
5851 * 2. If non-empty, merge all listed controllers, space separated. */
5852
5853 if (isempty(rvalue)) {
5854 c->disable_controllers = 0;
5855 return 0;
5856 }
5857
5858 r = cg_mask_from_string(rvalue, &disabled_mask);
5859 if (r < 0 || disabled_mask <= 0) {
323dda78 5860 log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid cgroup string: %s, ignoring", rvalue);
c72703e2
CD
5861 return 0;
5862 }
5863
5864 c->disable_controllers |= disabled_mask;
5865
5866 return 0;
5867}
5868
fab34748
KL
5869int config_parse_ip_filter_bpf_progs(
5870 const char *unit,
5871 const char *filename,
5872 unsigned line,
5873 const char *section,
5874 unsigned section_line,
5875 const char *lvalue,
5876 int ltype,
5877 const char *rvalue,
5878 void *data,
5879 void *userdata) {
5880
5881 _cleanup_free_ char *resolved = NULL;
47538b76 5882 const Unit *u = userdata;
99534007 5883 char ***paths = ASSERT_PTR(data);
fab34748
KL
5884 int r;
5885
5886 assert(filename);
5887 assert(lvalue);
5888 assert(rvalue);
fab34748
KL
5889
5890 if (isempty(rvalue)) {
5891 *paths = strv_free(*paths);
5892 return 0;
5893 }
5894
06536492 5895 r = unit_path_printf(u, rvalue, &resolved);
fab34748 5896 if (r < 0) {
323dda78 5897 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
fab34748
KL
5898 return 0;
5899 }
5900
5901 r = path_simplify_and_warn(resolved, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
5902 if (r < 0)
5903 return 0;
5904
5905 if (strv_contains(*paths, resolved))
5906 return 0;
5907
5908 r = strv_extend(paths, resolved);
5909 if (r < 0)
5910 return log_oom();
5911
5912 r = bpf_firewall_supported();
5913 if (r < 0)
5914 return r;
5915 if (r != BPF_FIREWALL_SUPPORTED_WITH_MULTI) {
5916 static bool warned = false;
5917
5918 log_full(warned ? LOG_DEBUG : LOG_WARNING,
5919 "File %s:%u configures an IP firewall with BPF programs (%s=%s), but the local system does not support BPF/cgroup based firewalling with multiple filters.\n"
5920 "Starting this unit will fail! (This warning is only shown for the first loaded unit using IP firewalling.)", filename, line, lvalue, rvalue);
5921
5922 warned = true;
5923 }
5924
5925 return 0;
5926}
5927
0879da98
JK
5928int config_parse_bpf_foreign_program(
5929 const char *unit,
5930 const char *filename,
5931 unsigned line,
5932 const char *section,
5933 unsigned section_line,
5934 const char *lvalue,
5935 int ltype,
5936 const char *rvalue,
5937 void *data,
5938 void *userdata) {
5939 _cleanup_free_ char *resolved = NULL, *word = NULL;
5940 CGroupContext *c = data;
99534007 5941 const char *p = ASSERT_PTR(rvalue);
0879da98
JK
5942 Unit *u = userdata;
5943 int attach_type, r;
5944
5945 assert(filename);
5946 assert(lvalue);
0879da98
JK
5947
5948 if (isempty(rvalue)) {
5949 while (c->bpf_foreign_programs)
5950 cgroup_context_remove_bpf_foreign_program(c, c->bpf_foreign_programs);
5951
5952 return 0;
5953 }
5954
6a35d52d 5955 r = extract_first_word(&p, &word, ":", 0);
0879da98
JK
5956 if (r == -ENOMEM)
5957 return log_oom();
6a35d52d 5958 if (r < 0) {
0879da98
JK
5959 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse foreign BPF program, ignoring: %s", rvalue);
5960 return 0;
5961 }
6a35d52d
YW
5962 if (r == 0 || isempty(p)) {
5963 log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid syntax in %s=, ignoring: %s", lvalue, rvalue);
5964 return 0;
5965 }
0879da98
JK
5966
5967 attach_type = bpf_cgroup_attach_type_from_string(word);
5968 if (attach_type < 0) {
5969 log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown BPF attach type=%s, ignoring: %s", word, rvalue);
5970 return 0;
5971 }
5972
6a35d52d 5973 r = unit_path_printf(u, p, &resolved);
0879da98 5974 if (r < 0) {
6a35d52d 5975 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %s", p, rvalue);
0879da98
JK
5976 return 0;
5977 }
5978
5979 r = path_simplify_and_warn(resolved, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
5980 if (r < 0)
5981 return 0;
5982
5983 r = cgroup_add_bpf_foreign_program(c, attach_type, resolved);
5984 if (r < 0)
5985 return log_error_errno(r, "Failed to add foreign BPF program to cgroup context: %m");
5986
5987 return 0;
5988}
5989
8dd210ab
JK
5990int config_parse_cgroup_socket_bind(
5991 const char *unit,
5992 const char *filename,
5993 unsigned line,
5994 const char *section,
5995 unsigned section_line,
5996 const char *lvalue,
5997 int ltype,
5998 const char *rvalue,
5999 void *data,
6000 void *userdata) {
6001 _cleanup_free_ CGroupSocketBindItem *item = NULL;
8dd210ab 6002 CGroupSocketBindItem **head = data;
5587ce7f
JK
6003 uint16_t nr_ports, port_min;
6004 int af, ip_protocol, r;
8dd210ab
JK
6005
6006 if (isempty(rvalue)) {
6007 cgroup_context_remove_socket_bind(head);
6008 return 0;
6009 }
6010
5587ce7f 6011 r = parse_socket_bind_item(rvalue, &af, &ip_protocol, &nr_ports, &port_min);
8dd210ab
JK
6012 if (r == -ENOMEM)
6013 return log_oom();
5587ce7f 6014 if (r < 0) {
cc87b3f6
ZJS
6015 log_syntax(unit, LOG_WARNING, filename, line, r,
6016 "Unable to parse %s= assignment, ignoring: %s", lvalue, rvalue);
6017 return 0;
6018 }
8dd210ab 6019
8dd210ab
JK
6020 item = new(CGroupSocketBindItem, 1);
6021 if (!item)
6022 return log_oom();
6023 *item = (CGroupSocketBindItem) {
6024 .address_family = af,
5587ce7f 6025 .ip_protocol = ip_protocol,
8dd210ab
JK
6026 .nr_ports = nr_ports,
6027 .port_min = port_min,
6028 };
6029
6030 LIST_PREPEND(socket_bind_items, *head, TAKE_PTR(item));
6031
6032 return 0;
6033}
6034
4f0c25c7
MV
6035int config_parse_restrict_network_interfaces(
6036 const char *unit,
6037 const char *filename,
6038 unsigned line,
6039 const char *section,
6040 unsigned section_line,
6041 const char *lvalue,
6042 int ltype,
6043 const char *rvalue,
6044 void *data,
6045 void *userdata) {
99534007 6046 CGroupContext *c = ASSERT_PTR(data);
4f0c25c7
MV
6047 bool is_allow_rule = true;
6048 int r;
6049
6050 assert(filename);
6051 assert(lvalue);
6052 assert(rvalue);
4f0c25c7
MV
6053
6054 if (isempty(rvalue)) {
6055 /* Empty assignment resets the list */
6056 c->restrict_network_interfaces = set_free(c->restrict_network_interfaces);
6057 return 0;
6058 }
6059
6060 if (rvalue[0] == '~') {
6061 is_allow_rule = false;
6062 rvalue++;
6063 }
6064
6065 if (set_isempty(c->restrict_network_interfaces))
6066 /* Only initialize this when creating the set */
6067 c->restrict_network_interfaces_is_allow_list = is_allow_rule;
6068
6069 for (const char *p = rvalue;;) {
6070 _cleanup_free_ char *word = NULL;
6071
6072 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
6073 if (r == 0)
6074 break;
6075 if (r == -ENOMEM)
6076 return log_oom();
6077 if (r < 0) {
6078 log_syntax(unit, LOG_WARNING, filename, line, r,
6079 "Trailing garbage in %s, ignoring: %s", lvalue, rvalue);
6080 break;
6081 }
6082
6083 if (!ifname_valid(word)) {
6084 log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid interface name, ignoring: %s", word);
6085 continue;
6086 }
6087
6088 if (c->restrict_network_interfaces_is_allow_list != is_allow_rule)
6089 free(set_remove(c->restrict_network_interfaces, word));
6090 else {
6091 r = set_put_strdup(&c->restrict_network_interfaces, word);
6092 if (r < 0)
6093 return log_oom();
6094 }
6095 }
6096
6097 return 0;
6098}
6099
23a177ef
LP
6100static int merge_by_names(Unit **u, Set *names, const char *id) {
6101 char *k;
6102 int r;
6103
6104 assert(u);
6105 assert(*u);
23a177ef 6106
e8630e69 6107 /* Let's try to add in all names that are aliases of this unit */
23a177ef 6108 while ((k = set_steal_first(names))) {
e8630e69 6109 _cleanup_free_ _unused_ char *free_k = k;
23a177ef 6110
e8630e69 6111 /* First try to merge in the other name into our unit */
9946996c
LP
6112 r = unit_merge_by_name(*u, k);
6113 if (r < 0) {
23a177ef
LP
6114 Unit *other;
6115
e8630e69
ZJS
6116 /* Hmm, we couldn't merge the other unit into ours? Then let's try it the other way
6117 * round. */
036643a2 6118
e8630e69
ZJS
6119 other = manager_get_unit((*u)->manager, k);
6120 if (!other)
6121 return r; /* return previous failure */
036643a2 6122
e8630e69
ZJS
6123 r = unit_merge(other, *u);
6124 if (r < 0)
a837f088 6125 return r;
fe51822e 6126
e8630e69
ZJS
6127 *u = other;
6128 return merge_by_names(u, names, NULL);
036643a2 6129 }
034c6ed7 6130
e8630e69
ZJS
6131 if (streq_ptr(id, k))
6132 unit_choose_id(*u, id);
1b64d026
LP
6133 }
6134
e48614c4 6135 return 0;
0301abf4
LP
6136}
6137
e537352b 6138int unit_load_fragment(Unit *u) {
e8630e69
ZJS
6139 const char *fragment;
6140 _cleanup_set_free_free_ Set *names = NULL;
23a177ef 6141 int r;
0301abf4
LP
6142
6143 assert(u);
ac155bb8
MS
6144 assert(u->load_state == UNIT_STUB);
6145 assert(u->id);
23a177ef 6146
3f5e8115 6147 if (u->transient) {
23e9a7dd 6148 u->access_selinux_context = mfree(u->access_selinux_context);
3f5e8115
LP
6149 u->load_state = UNIT_LOADED;
6150 return 0;
6151 }
6152
91e0ee5f
ZJS
6153 /* Possibly rebuild the fragment map to catch new units */
6154 r = unit_file_build_name_map(&u->manager->lookup_paths,
c2911d48 6155 &u->manager->unit_cache_timestamp_hash,
91e0ee5f
ZJS
6156 &u->manager->unit_id_map,
6157 &u->manager->unit_name_map,
6158 &u->manager->unit_path_cache);
9946996c 6159 if (r < 0)
14140908 6160 return log_error_errno(r, "Failed to rebuild name map: %m");
91e0ee5f 6161
e8630e69
ZJS
6162 r = unit_file_find_fragment(u->manager->unit_id_map,
6163 u->manager->unit_name_map,
6164 u->id,
6165 &fragment,
6166 &names);
6167 if (r < 0 && r != -ENOENT)
294d81f1
LP
6168 return r;
6169
e8630e69
ZJS
6170 if (fragment) {
6171 /* Open the file, check if this is a mask, otherwise read. */
6172 _cleanup_fclose_ FILE *f = NULL;
c9e06956 6173 struct stat st;
0301abf4 6174
e8630e69
ZJS
6175 /* Try to open the file name. A symlink is OK, for example for linked files or masks. We
6176 * expect that all symlinks within the lookup paths have been already resolved, but we don't
6177 * verify this here. */
6178 f = fopen(fragment, "re");
6179 if (!f)
6180 return log_unit_notice_errno(u, errno, "Failed to open %s: %m", fragment);
6ccb1b44 6181
e8630e69
ZJS
6182 if (fstat(fileno(f), &st) < 0)
6183 return -errno;
294d81f1 6184
e8630e69 6185 r = free_and_strdup(&u->fragment_path, fragment);
7410616c
LP
6186 if (r < 0)
6187 return r;
294d81f1 6188
e8630e69 6189 if (null_or_empty(&st)) {
88414eed
LP
6190 /* Unit file is masked */
6191
6192 u->load_state = u->perpetual ? UNIT_LOADED : UNIT_MASKED; /* don't allow perpetual units to ever be masked */
e8630e69 6193 u->fragment_mtime = 0;
23e9a7dd 6194 u->access_selinux_context = mfree(u->access_selinux_context);
e8630e69 6195 } else {
23e9a7dd
LP
6196#if HAVE_SELINUX
6197 if (mac_selinux_use()) {
6198 _cleanup_freecon_ char *selcon = NULL;
6199
6200 /* Cache the SELinux context of the unit file here. We'll make use of when checking access permissions to loaded units */
6201 r = fgetfilecon_raw(fileno(f), &selcon);
6202 if (r < 0)
6203 log_unit_warning_errno(u, r, "Failed to read SELinux context of '%s', ignoring: %m", fragment);
6204
6205 r = free_and_strdup(&u->access_selinux_context, selcon);
6206 if (r < 0)
6207 return r;
6208 } else
6209#endif
6210 u->access_selinux_context = mfree(u->access_selinux_context);
6211
e8630e69
ZJS
6212 u->load_state = UNIT_LOADED;
6213 u->fragment_mtime = timespec_load(&st.st_mtim);
6214
6215 /* Now, parse the file contents */
6216 r = config_parse(u->id, fragment, f,
6217 UNIT_VTABLE(u)->sections,
6218 config_item_perf_lookup, load_fragment_gperf_lookup,
7ade8982 6219 0,
4f9ff96a
LP
6220 u,
6221 NULL);
bb28e684 6222 if (r == -ENOEXEC)
e8630e69
ZJS
6223 log_unit_notice_errno(u, r, "Unit configuration has fatal error, unit will not be started.");
6224 if (r < 0)
6225 return r;
bb28e684 6226 }
e8630e69 6227 }
890f434c 6228
3aa57658
ZJS
6229 /* Call merge_by_names with the name derived from the fragment path as the preferred name.
6230 *
6231 * We do the merge dance here because for some unit types, the unit might have aliases which are not
e8630e69
ZJS
6232 * declared in the file system. In particular, this is true (and frequent) for device and swap units.
6233 */
e8630e69 6234 const char *id = u->id;
b58feca6 6235 _cleanup_free_ char *filename = NULL, *free_id = NULL;
294d81f1 6236
e8630e69 6237 if (fragment) {
b58feca6
JR
6238 r = path_extract_filename(fragment, &filename);
6239 if (r < 0)
6240 return log_debug_errno(r, "Failed to extract filename from fragment '%s': %m", fragment);
6241 id = filename;
6242
e8630e69
ZJS
6243 if (unit_name_is_valid(id, UNIT_NAME_TEMPLATE)) {
6244 assert(u->instance); /* If we're not trying to use a template for non-instanced unit,
6245 * this must be set. */
890f434c 6246
e8630e69
ZJS
6247 r = unit_name_replace_instance(id, u->instance, &free_id);
6248 if (r < 0)
6249 return log_debug_errno(r, "Failed to build id (%s + %s): %m", id, u->instance);
6250 id = free_id;
abc08d4d 6251 }
071830ff
LP
6252 }
6253
3aa57658 6254 Unit *merged = u;
e8630e69
ZJS
6255 r = merge_by_names(&merged, names, id);
6256 if (r < 0)
6257 return r;
6258
6259 if (merged != u)
6260 u->load_state = UNIT_MERGED;
6261
23a177ef 6262 return 0;
3efd4195 6263}
e537352b
LP
6264
6265void unit_dump_config_items(FILE *f) {
f975e971
LP
6266 static const struct {
6267 const ConfigParserCallback callback;
6268 const char *rvalue;
6269 } table[] = {
17df7223 6270 { config_parse_warn_compat, "NOTSUPPORTED" },
f975e971
LP
6271 { config_parse_int, "INTEGER" },
6272 { config_parse_unsigned, "UNSIGNED" },
5556b5fe 6273 { config_parse_iec_size, "SIZE" },
59f448cf 6274 { config_parse_iec_uint64, "SIZE" },
50299121 6275 { config_parse_si_uint64, "SIZE" },
f975e971
LP
6276 { config_parse_bool, "BOOLEAN" },
6277 { config_parse_string, "STRING" },
6278 { config_parse_path, "PATH" },
6279 { config_parse_unit_path_printf, "PATH" },
8c35c10d 6280 { config_parse_colon_separated_paths, "PATH" },
f975e971
LP
6281 { config_parse_strv, "STRING [...]" },
6282 { config_parse_exec_nice, "NICE" },
6283 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
6284 { config_parse_exec_io_class, "IOCLASS" },
6285 { config_parse_exec_io_priority, "IOPRIORITY" },
6286 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
6287 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
6288 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
6289 { config_parse_mode, "MODE" },
6290 { config_parse_unit_env_file, "FILE" },
52c239d7
LB
6291 { config_parse_exec_output, "OUTPUT" },
6292 { config_parse_exec_input, "INPUT" },
ca37242e
LP
6293 { config_parse_log_facility, "FACILITY" },
6294 { config_parse_log_level, "LEVEL" },
f975e971 6295 { config_parse_exec_secure_bits, "SECUREBITS" },
a103496c 6296 { config_parse_capability_set, "BOUNDINGSET" },
4f424df7 6297 { config_parse_rlimit, "LIMIT" },
f975e971 6298 { config_parse_unit_deps, "UNIT [...]" },
f975e971
LP
6299 { config_parse_exec, "PATH [ARGUMENT [...]]" },
6300 { config_parse_service_type, "SERVICETYPE" },
596e4470 6301 { config_parse_service_exit_type, "SERVICEEXITTYPE" },
f975e971 6302 { config_parse_service_restart, "SERVICERESTART" },
e568fea9 6303 { config_parse_service_restart_mode, "SERVICERESTARTMODE" },
bf760801 6304 { config_parse_service_timeout_failure_mode, "TIMEOUTMODE" },
f975e971 6305 { config_parse_kill_mode, "KILLMODE" },
f757855e 6306 { config_parse_signal, "SIGNAL" },
f975e971
LP
6307 { config_parse_socket_listen, "SOCKET [...]" },
6308 { config_parse_socket_bind, "SOCKETBIND" },
6309 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
7f602784 6310 { config_parse_sec, "SECONDS" },
d88a251b 6311 { config_parse_nsec, "NANOSECONDS" },
94828d2d 6312 { config_parse_namespace_path_strv, "PATH [...]" },
d2d6c096 6313 { config_parse_bind_paths, "PATH[:PATH[:OPTIONS]] [...]" },
874cdcbc
LP
6314 { config_parse_unit_requires_mounts_for,
6315 "PATH [...]" },
6316 { config_parse_exec_mount_propagation_flag,
f0a96d19 6317 "MOUNTFLAG" },
f975e971 6318 { config_parse_unit_string_printf, "STRING" },
3ecaa09b 6319 { config_parse_trigger_unit, "UNIT" },
f975e971 6320 { config_parse_timer, "TIMER" },
f975e971 6321 { config_parse_path_spec, "PATH" },
f975e971
LP
6322 { config_parse_notify_access, "ACCESS" },
6323 { config_parse_ip_tos, "TOS" },
6324 { config_parse_unit_condition_path, "CONDITION" },
6325 { config_parse_unit_condition_string, "CONDITION" },
a016b922 6326 { config_parse_unit_slice, "SLICE" },
7f0386f6
LP
6327 { config_parse_documentation, "URL" },
6328 { config_parse_service_timeout, "SECONDS" },
87a47f99 6329 { config_parse_emergency_action, "ACTION" },
7f0386f6
LP
6330 { config_parse_set_status, "STATUS" },
6331 { config_parse_service_sockets, "SOCKETS" },
7f0386f6 6332 { config_parse_environ, "ENVIRON" },
349cc4a5 6333#if HAVE_SECCOMP
17df7223 6334 { config_parse_syscall_filter, "SYSCALLS" },
6a6751fe 6335 { config_parse_syscall_archs, "ARCHS" },
17df7223 6336 { config_parse_syscall_errno, "ERRNO" },
9df2cdd8 6337 { config_parse_syscall_log, "SYSCALLS" },
4298d0b5 6338 { config_parse_address_families, "FAMILIES" },
add00535 6339 { config_parse_restrict_namespaces, "NAMESPACES" },
c0467cf3 6340#endif
e59ccd03 6341 { config_parse_restrict_filesystems, "FILESYSTEMS" },
7f0386f6 6342 { config_parse_cpu_shares, "SHARES" },
984faf29 6343 { config_parse_cg_weight, "WEIGHT" },
c8340822 6344 { config_parse_cg_cpu_weight, "CPUWEIGHT" },
7f0386f6
LP
6345 { config_parse_memory_limit, "LIMIT" },
6346 { config_parse_device_allow, "DEVICE" },
6347 { config_parse_device_policy, "POLICY" },
13c31542 6348 { config_parse_io_limit, "LIMIT" },
13c31542 6349 { config_parse_io_device_weight, "DEVICEWEIGHT" },
6ae4283c 6350 { config_parse_io_device_latency, "DEVICELATENCY" },
7f0386f6
LP
6351 { config_parse_blockio_bandwidth, "BANDWIDTH" },
6352 { config_parse_blockio_weight, "WEIGHT" },
6353 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
6354 { config_parse_long, "LONG" },
6355 { config_parse_socket_service, "SERVICE" },
349cc4a5 6356#if HAVE_SELINUX
6a6751fe
LP
6357 { config_parse_exec_selinux_context, "LABEL" },
6358#endif
6359 { config_parse_job_mode, "MODE" },
6360 { config_parse_job_mode_isolate, "BOOLEAN" },
4298d0b5 6361 { config_parse_personality, "PERSONALITY" },
523ea123 6362 { config_parse_log_filter_patterns, "REGEX" },
f975e971
LP
6363 };
6364
6365 const char *prev = NULL;
f975e971
LP
6366
6367 assert(f);
e537352b 6368
f975e971
LP
6369 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
6370 const char *rvalue = "OTHER", *lvalue;
313b7856 6371 const ConfigPerfItem *p;
f975e971 6372 const char *dot;
f975e971
LP
6373
6374 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
6375
313b7856
LP
6376 /* Hide legacy settings */
6377 if (p->parse == config_parse_warn_compat &&
6378 p->ltype == DISABLED_LEGACY)
6379 continue;
6380
601844b7 6381 for (size_t j = 0; j < ELEMENTSOF(table); j++)
313b7856
LP
6382 if (p->parse == table[j].callback) {
6383 rvalue = table[j].rvalue;
6384 break;
6385 }
6386
f975e971
LP
6387 dot = strchr(i, '.');
6388 lvalue = dot ? dot + 1 : i;
f975e971 6389
601844b7
YW
6390 if (dot) {
6391 size_t prefix_len = dot - i;
6392
641906e9 6393 if (!prev || !strneq(prev, i, prefix_len+1)) {
f975e971
LP
6394 if (prev)
6395 fputc('\n', f);
6396
6397 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
6398 }
601844b7 6399 }
f975e971 6400
f975e971
LP
6401 fprintf(f, "%s=%s\n", lvalue, rvalue);
6402 prev = i;
6403 }
e537352b 6404}
a07a7324
FS
6405
6406int config_parse_cpu_affinity2(
6407 const char *unit,
6408 const char *filename,
6409 unsigned line,
6410 const char *section,
6411 unsigned section_line,
6412 const char *lvalue,
6413 int ltype,
6414 const char *rvalue,
6415 void *data,
6416 void *userdata) {
6417
99534007 6418 CPUSet *affinity = ASSERT_PTR(data);
a07a7324
FS
6419
6420 (void) parse_cpu_set_extend(rvalue, affinity, true, unit, filename, line, lvalue);
6421
6422 return 0;
6423}
6424
6425int config_parse_show_status(
6426 const char* unit,
6427 const char *filename,
6428 unsigned line,
6429 const char *section,
6430 unsigned section_line,
6431 const char *lvalue,
6432 int ltype,
6433 const char *rvalue,
6434 void *data,
6435 void *userdata) {
6436
6437 int k;
99534007 6438 ShowStatus *b = ASSERT_PTR(data);
a07a7324
FS
6439
6440 assert(filename);
6441 assert(lvalue);
6442 assert(rvalue);
a07a7324
FS
6443
6444 k = parse_show_status(rvalue, b);
323dda78
YW
6445 if (k < 0)
6446 log_syntax(unit, LOG_WARNING, filename, line, k, "Failed to parse show status setting, ignoring: %s", rvalue);
a07a7324
FS
6447
6448 return 0;
6449}
6450
6451int config_parse_output_restricted(
6452 const char* unit,
6453 const char *filename,
6454 unsigned line,
6455 const char *section,
6456 unsigned section_line,
6457 const char *lvalue,
6458 int ltype,
6459 const char *rvalue,
6460 void *data,
6461 void *userdata) {
6462
99534007 6463 ExecOutput t, *eo = ASSERT_PTR(data);
f3dc6af2 6464 bool obsolete = false;
a07a7324
FS
6465
6466 assert(filename);
6467 assert(lvalue);
6468 assert(rvalue);
a07a7324 6469
f3dc6af2
LP
6470 if (streq(rvalue, "syslog")) {
6471 t = EXEC_OUTPUT_JOURNAL;
6472 obsolete = true;
6473 } else if (streq(rvalue, "syslog+console")) {
6474 t = EXEC_OUTPUT_JOURNAL_AND_CONSOLE;
6475 obsolete = true;
6476 } else {
6477 t = exec_output_from_string(rvalue);
6478 if (t < 0) {
b98680b2 6479 log_syntax(unit, LOG_WARNING, filename, line, t, "Failed to parse output type, ignoring: %s", rvalue);
f3dc6af2
LP
6480 return 0;
6481 }
a07a7324 6482
8d7dab1f
LW
6483 if (IN_SET(t, EXEC_OUTPUT_SOCKET, EXEC_OUTPUT_NAMED_FD, EXEC_OUTPUT_FILE, EXEC_OUTPUT_FILE_APPEND, EXEC_OUTPUT_FILE_TRUNCATE)) {
6484 log_syntax(unit, LOG_WARNING, filename, line, 0, "Standard output types socket, fd:, file:, append:, truncate: are not supported as defaults, ignoring: %s", rvalue);
f3dc6af2
LP
6485 return 0;
6486 }
a07a7324
FS
6487 }
6488
f3dc6af2
LP
6489 if (obsolete)
6490 log_syntax(unit, LOG_NOTICE, filename, line, 0,
6491 "Standard output type %s is obsolete, automatically updating to %s. Please update your configuration.",
6492 rvalue, exec_output_to_string(t));
6493
a07a7324
FS
6494 *eo = t;
6495 return 0;
6496}
6497
6498int config_parse_crash_chvt(
6499 const char* unit,
6500 const char *filename,
6501 unsigned line,
6502 const char *section,
6503 unsigned section_line,
6504 const char *lvalue,
6505 int ltype,
6506 const char *rvalue,
6507 void *data,
6508 void *userdata) {
6509
6510 int r;
6511
6512 assert(filename);
6513 assert(lvalue);
6514 assert(rvalue);
6515 assert(data);
6516
6517 r = parse_crash_chvt(rvalue, data);
323dda78
YW
6518 if (r < 0)
6519 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse CrashChangeVT= setting, ignoring: %s", rvalue);
a07a7324
FS
6520
6521 return 0;
6522}
eb34a981
LP
6523
6524int config_parse_swap_priority(
6525 const char *unit,
6526 const char *filename,
6527 unsigned line,
6528 const char *section,
6529 unsigned section_line,
6530 const char *lvalue,
6531 int ltype,
6532 const char *rvalue,
6533 void *data,
6534 void *userdata) {
6535
99534007 6536 Swap *s = ASSERT_PTR(userdata);
eb34a981
LP
6537 int r, priority;
6538
eb34a981
LP
6539 assert(filename);
6540 assert(lvalue);
6541 assert(rvalue);
6542 assert(data);
6543
6544 if (isempty(rvalue)) {
6545 s->parameters_fragment.priority = -1;
6546 s->parameters_fragment.priority_set = false;
6547 return 0;
6548 }
6549
6550 r = safe_atoi(rvalue, &priority);
6551 if (r < 0) {
323dda78 6552 log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid swap priority '%s', ignoring.", rvalue);
eb34a981
LP
6553 return 0;
6554 }
6555
6556 if (priority < -1) {
323dda78 6557 log_syntax(unit, LOG_WARNING, filename, line, 0, "Sorry, swap priorities smaller than -1 may only be assigned by the kernel itself, ignoring: %s", rvalue);
eb34a981
LP
6558 return 0;
6559 }
6560
6561 if (priority > 32767) {
323dda78 6562 log_syntax(unit, LOG_WARNING, filename, line, 0, "Swap priority out of range, ignoring: %s", rvalue);
eb34a981
LP
6563 return 0;
6564 }
6565
6566 s->parameters_fragment.priority = priority;
6567 s->parameters_fragment.priority_set = true;
6568 return 0;
6569}
8a85c5b6
FB
6570
6571int config_parse_watchdog_sec(
6572 const char *unit,
6573 const char *filename,
6574 unsigned line,
6575 const char *section,
6576 unsigned section_line,
6577 const char *lvalue,
6578 int ltype,
6579 const char *rvalue,
6580 void *data,
6581 void *userdata) {
6582
c91c95e6
LP
6583 usec_t *usec = data;
6584
8a85c5b6
FB
6585 assert(filename);
6586 assert(lvalue);
6587 assert(rvalue);
6588
6589 /* This is called for {Runtime,Reboot,KExec}WatchdogSec= where "default" maps to
6590 * USEC_INFINITY internally. */
6591
c91c95e6 6592 if (streq(rvalue, "default"))
8a85c5b6 6593 *usec = USEC_INFINITY;
c91c95e6
LP
6594 else if (streq(rvalue, "off"))
6595 *usec = 0;
6596 else
6597 return config_parse_sec(unit, filename, line, section, section_line, lvalue, ltype, rvalue, data, userdata);
8a85c5b6 6598
c91c95e6 6599 return 0;
8a85c5b6 6600}
51462135
DDM
6601
6602int config_parse_tty_size(
6603 const char *unit,
6604 const char *filename,
6605 unsigned line,
6606 const char *section,
6607 unsigned section_line,
6608 const char *lvalue,
6609 int ltype,
6610 const char *rvalue,
6611 void *data,
6612 void *userdata) {
6613
6614 unsigned *sz = data;
6615
6616 assert(filename);
6617 assert(lvalue);
6618 assert(rvalue);
6619
6620 if (isempty(rvalue)) {
6621 *sz = UINT_MAX;
6622 return 0;
6623 }
6624
6625 return config_parse_unsigned(unit, filename, line, section, section_line, lvalue, ltype, rvalue, data, userdata);
6626}
523ea123
QD
6627
6628int config_parse_log_filter_patterns(
6629 const char *unit,
6630 const char *filename,
6631 unsigned line,
6632 const char *section,
6633 unsigned section_line,
6634 const char *lvalue,
6635 int ltype,
6636 const char *rvalue,
6637 void *data,
6638 void *userdata) {
6639
6640 ExecContext *c = ASSERT_PTR(data);
523ea123
QD
6641 const char *pattern = ASSERT_PTR(rvalue);
6642 bool is_allowlist = true;
6643 int r;
6644
6645 assert(filename);
6646 assert(lvalue);
6647
6648 if (isempty(pattern)) {
6649 /* Empty assignment resets the lists. */
6650 c->log_filter_allowed_patterns = set_free(c->log_filter_allowed_patterns);
6651 c->log_filter_denied_patterns = set_free(c->log_filter_denied_patterns);
6652 return 0;
6653 }
6654
6655 if (pattern[0] == '~') {
6656 is_allowlist = false;
6657 pattern++;
6658 if (isempty(pattern))
6659 /* LogFilterPatterns=~ is not considered a valid pattern. */
6660 return log_syntax(unit, LOG_WARNING, filename, line, 0,
6661 "Regex pattern invalid, ignoring: %s=%s", lvalue, rvalue);
6662 }
6663
48d85160 6664 if (pattern_compile_and_log(pattern, 0, NULL) < 0)
523ea123
QD
6665 return 0;
6666
6667 r = set_put_strdup(is_allowlist ? &c->log_filter_allowed_patterns : &c->log_filter_denied_patterns,
6668 pattern);
6669 if (r < 0) {
6670 log_syntax(unit, LOG_WARNING, filename, line, r,
6671 "Failed to store log filtering pattern, ignoring: %s=%s", lvalue, rvalue);
6672 return 0;
6673 }
6674
6675 return 0;
6676}
cd48e23f
RP
6677
6678int config_parse_open_file(
6679 const char *unit,
6680 const char *filename,
6681 unsigned line,
6682 const char *section,
6683 unsigned section_line,
6684 const char *lvalue,
6685 int ltype,
6686 const char *rvalue,
6687 void *data,
6688 void *userdata) {
6689
6690 _cleanup_(open_file_freep) OpenFile *of = NULL;
6691 OpenFile **head = ASSERT_PTR(data);
6692 int r;
6693
6694 assert(filename);
6695 assert(lvalue);
6696 assert(rvalue);
6697
6698 if (isempty(rvalue)) {
6699 open_file_free_many(head);
6700 return 0;
6701 }
6702
6703 r = open_file_parse(rvalue, &of);
6704 if (r < 0) {
6705 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse OpenFile= setting, ignoring: %s", rvalue);
6706 return 0;
6707 }
6708
6709 LIST_APPEND(open_files, *head, TAKE_PTR(of));
6710
6711 return 0;
6712}