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