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