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