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