blob: 4bb1ef0108d5371f76915e6c0c293befcfc029e9 [file] [log] [blame]
Lennart Poettering3efd4192009-11-19 23:13:20 +01001/*-*- Mode: C; c-basic-offset: 8 -*-*/
2
Lennart Poettering87f0e412010-01-26 21:39:06 +01003#include <linux/oom.h>
Lennart Poettering3efd4192009-11-19 23:13:20 +01004#include <assert.h>
5#include <errno.h>
6#include <string.h>
Lennart Poettering87f0e412010-01-26 21:39:06 +01007#include <unistd.h>
8#include <fcntl.h>
Lennart Poettering94f04342010-01-30 01:55:42 +01009#include <sched.h>
10#include <sys/prctl.h>
Lennart Poettering3efd4192009-11-19 23:13:20 +010011
Lennart Poettering87f0e412010-01-26 21:39:06 +010012#include "unit.h"
Lennart Poettering3efd4192009-11-19 23:13:20 +010013#include "strv.h"
14#include "conf-parser.h"
15#include "load-fragment.h"
Lennart Poettering16354ef2010-01-20 19:19:53 +010016#include "log.h"
Lennart Poettering9eba9da2010-01-29 20:46:22 +010017#include "ioprio.h"
Lennart Poettering94f04342010-01-30 01:55:42 +010018#include "securebits.h"
19#include "missing.h"
Lennart Poettering3efd4192009-11-19 23:13:20 +010020
Lennart Poettering42f4e3c2010-01-19 02:56:37 +010021static int config_parse_deps(
Lennart Poettering3efd4192009-11-19 23:13:20 +010022 const char *filename,
23 unsigned line,
24 const char *section,
25 const char *lvalue,
26 const char *rvalue,
27 void *data,
28 void *userdata) {
29
Lennart Poettering87f0e412010-01-26 21:39:06 +010030 UnitDependency d = PTR_TO_UINT(data);
31 Unit *u = userdata;
Lennart Poettering3efd4192009-11-19 23:13:20 +010032 char *w;
33 size_t l;
34 char *state;
35
36 assert(filename);
37 assert(lvalue);
38 assert(rvalue);
Lennart Poettering3efd4192009-11-19 23:13:20 +010039
40 FOREACH_WORD(w, &l, rvalue, state) {
41 char *t;
42 int r;
Lennart Poettering3efd4192009-11-19 23:13:20 +010043
44 if (!(t = strndup(w, l)))
45 return -ENOMEM;
46
Lennart Poetteringb19e7dc2010-01-28 06:43:49 +010047 r = unit_add_dependency_by_name(u, d, t);
Lennart Poettering3efd4192009-11-19 23:13:20 +010048 free(t);
49
50 if (r < 0)
51 return r;
Lennart Poettering3efd4192009-11-19 23:13:20 +010052 }
53
54 return 0;
55}
56
Lennart Poettering42f4e3c2010-01-19 02:56:37 +010057static int config_parse_names(
Lennart Poettering87d15152010-01-18 23:50:13 +010058 const char *filename,
59 unsigned line,
60 const char *section,
61 const char *lvalue,
62 const char *rvalue,
63 void *data,
64 void *userdata) {
65
Lennart Poettering87f0e412010-01-26 21:39:06 +010066 Unit *u = userdata;
Lennart Poettering87d15152010-01-18 23:50:13 +010067 char *w;
68 size_t l;
69 char *state;
70
71 assert(filename);
72 assert(lvalue);
73 assert(rvalue);
74 assert(data);
75
76 FOREACH_WORD(w, &l, rvalue, state) {
77 char *t;
78 int r;
Lennart Poettering87f0e412010-01-26 21:39:06 +010079 Unit *other;
Lennart Poettering87d15152010-01-18 23:50:13 +010080
81 if (!(t = strndup(w, l)))
82 return -ENOMEM;
83
Lennart Poettering87f0e412010-01-26 21:39:06 +010084 other = manager_get_unit(u->meta.manager, t);
Lennart Poettering87d15152010-01-18 23:50:13 +010085
86 if (other) {
87
Lennart Poettering87f0e412010-01-26 21:39:06 +010088 if (other != u) {
Lennart Poettering87d15152010-01-18 23:50:13 +010089
Lennart Poettering87f0e412010-01-26 21:39:06 +010090 if (other->meta.load_state != UNIT_STUB) {
Lennart Poettering87d15152010-01-18 23:50:13 +010091 free(t);
92 return -EEXIST;
93 }
94
Lennart Poettering87f0e412010-01-26 21:39:06 +010095 if ((r = unit_merge(u, other)) < 0) {
Lennart Poettering87d15152010-01-18 23:50:13 +010096 free(t);
97 return r;
98 }
99 }
100
101 } else {
Lennart Poettering87f0e412010-01-26 21:39:06 +0100102 if ((r = unit_add_name(u, t)) < 0) {
Lennart Poettering87d15152010-01-18 23:50:13 +0100103 free(t);
104 return r;
105 }
106 }
107
108 free(t);
109 }
110
111 return 0;
112}
113
Lennart Poettering42f4e3c2010-01-19 02:56:37 +0100114static int config_parse_listen(
115 const char *filename,
116 unsigned line,
117 const char *section,
118 const char *lvalue,
119 const char *rvalue,
120 void *data,
121 void *userdata) {
122
Lennart Poettering16354ef2010-01-20 19:19:53 +0100123 int r;
Lennart Poettering542563b2010-01-23 03:35:54 +0100124 SocketPort *p;
125 Socket *s;
Lennart Poettering16354ef2010-01-20 19:19:53 +0100126
Lennart Poettering42f4e3c2010-01-19 02:56:37 +0100127 assert(filename);
128 assert(lvalue);
129 assert(rvalue);
130 assert(data);
131
Lennart Poettering542563b2010-01-23 03:35:54 +0100132 s = (Socket*) data;
133
134 if (!(p = new0(SocketPort, 1)))
135 return -ENOMEM;
136
137 if (streq(lvalue, "ListenFIFO")) {
138 p->type = SOCKET_FIFO;
139
140 if (!(p->path = strdup(rvalue))) {
141 free(p);
142 return -ENOMEM;
143 }
144 } else {
145 p->type = SOCKET_SOCKET;
146
147 if ((r = socket_address_parse(&p->address, rvalue)) < 0) {
148 log_error("[%s:%u] Failed to parse address value: %s", filename, line, rvalue);
149 free(p);
150 return r;
151 }
152
153 if (streq(lvalue, "ListenStream"))
154 p->address.type = SOCK_STREAM;
155 else if (streq(lvalue, "ListenDatagram"))
156 p->address.type = SOCK_DGRAM;
157 else {
158 assert(streq(lvalue, "ListenSequentialPacket"));
159 p->address.type = SOCK_SEQPACKET;
160 }
161
162 if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
163 free(p);
164 return -EPROTONOSUPPORT;
165 }
Lennart Poettering16354ef2010-01-20 19:19:53 +0100166 }
167
Lennart Poettering542563b2010-01-23 03:35:54 +0100168 p->fd = -1;
Lennart Poettering034c6ed2010-01-26 04:18:44 +0100169 LIST_PREPEND(SocketPort, port, s->ports, p);
Lennart Poettering542563b2010-01-23 03:35:54 +0100170
Lennart Poettering16354ef2010-01-20 19:19:53 +0100171 return 0;
Lennart Poettering42f4e3c2010-01-19 02:56:37 +0100172}
173
Lennart Poettering034c6ed2010-01-26 04:18:44 +0100174static int config_parse_socket_bind(
Lennart Poettering42f4e3c2010-01-19 02:56:37 +0100175 const char *filename,
176 unsigned line,
177 const char *section,
178 const char *lvalue,
179 const char *rvalue,
180 void *data,
181 void *userdata) {
182
Lennart Poettering542563b2010-01-23 03:35:54 +0100183 int r;
184 Socket *s;
Lennart Poettering42f4e3c2010-01-19 02:56:37 +0100185
186 assert(filename);
187 assert(lvalue);
188 assert(rvalue);
189 assert(data);
190
Lennart Poettering542563b2010-01-23 03:35:54 +0100191 s = (Socket*) data;
192
193 if ((r = parse_boolean(rvalue)) < 0) {
194 log_error("[%s:%u] Failed to parse bind IPv6 only value: %s", filename, line, rvalue);
195 return r;
Lennart Poettering16354ef2010-01-20 19:19:53 +0100196 }
Lennart Poettering42f4e3c2010-01-19 02:56:37 +0100197
Lennart Poettering542563b2010-01-23 03:35:54 +0100198 s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
199
Lennart Poettering42f4e3c2010-01-19 02:56:37 +0100200 return 0;
201}
202
Lennart Poettering034c6ed2010-01-26 04:18:44 +0100203static int config_parse_nice(
204 const char *filename,
205 unsigned line,
206 const char *section,
207 const char *lvalue,
208 const char *rvalue,
209 void *data,
210 void *userdata) {
211
Lennart Poetteringfb33a392010-01-28 02:53:56 +0100212 ExecContext *c = data;
213 int priority, r;
Lennart Poettering034c6ed2010-01-26 04:18:44 +0100214
215 assert(filename);
216 assert(lvalue);
217 assert(rvalue);
218 assert(data);
219
220 if ((r = safe_atoi(rvalue, &priority)) < 0) {
221 log_error("[%s:%u] Failed to parse nice priority: %s", filename, line, rvalue);
222 return r;
223 }
224
225 if (priority < PRIO_MIN || priority >= PRIO_MAX) {
226 log_error("[%s:%u] Nice priority out of range: %s", filename, line, rvalue);
227 return -ERANGE;
228 }
229
Lennart Poetteringfb33a392010-01-28 02:53:56 +0100230 c->nice = priority;
231 c->nice_set = false;
232
Lennart Poettering034c6ed2010-01-26 04:18:44 +0100233 return 0;
234}
235
236static int config_parse_oom_adjust(
237 const char *filename,
238 unsigned line,
239 const char *section,
240 const char *lvalue,
241 const char *rvalue,
242 void *data,
243 void *userdata) {
244
Lennart Poetteringfb33a392010-01-28 02:53:56 +0100245 ExecContext *c = data;
246 int oa, r;
Lennart Poettering034c6ed2010-01-26 04:18:44 +0100247
248 assert(filename);
249 assert(lvalue);
250 assert(rvalue);
251 assert(data);
252
253 if ((r = safe_atoi(rvalue, &oa)) < 0) {
254 log_error("[%s:%u] Failed to parse OOM adjust value: %s", filename, line, rvalue);
255 return r;
256 }
257
258 if (oa < OOM_DISABLE || oa > OOM_ADJUST_MAX) {
259 log_error("[%s:%u] OOM adjust value out of range: %s", filename, line, rvalue);
260 return -ERANGE;
261 }
262
Lennart Poetteringfb33a392010-01-28 02:53:56 +0100263 c->oom_adjust = oa;
264 c->oom_adjust_set = true;
265
Lennart Poettering034c6ed2010-01-26 04:18:44 +0100266 return 0;
267}
268
269static int config_parse_umask(
270 const char *filename,
271 unsigned line,
272 const char *section,
273 const char *lvalue,
274 const char *rvalue,
275 void *data,
276 void *userdata) {
277
278 mode_t *m = data;
279 long l;
280 char *x = NULL;
281
282 assert(filename);
283 assert(lvalue);
284 assert(rvalue);
285 assert(data);
286
287 errno = 0;
288 l = strtol(rvalue, &x, 8);
289 if (!x || *x || errno) {
290 log_error("[%s:%u] Failed to parse umask value: %s", filename, line, rvalue);
291 return errno ? -errno : -EINVAL;
292 }
293
294 if (l < 0000 || l > 0777) {
295 log_error("[%s:%u] umask value out of range: %s", filename, line, rvalue);
296 return -ERANGE;
297 }
298
299 *m = (mode_t) l;
300 return 0;
301}
302
303static int config_parse_exec(
304 const char *filename,
305 unsigned line,
306 const char *section,
307 const char *lvalue,
308 const char *rvalue,
309 void *data,
310 void *userdata) {
311
312 ExecCommand **e = data, *ee, *nce = NULL;
313 char **n;
314 char *w;
315 unsigned k;
316 size_t l;
317 char *state;
318
319 assert(filename);
320 assert(lvalue);
321 assert(rvalue);
322 assert(data);
323
324 k = 0;
325 FOREACH_WORD_QUOTED(w, l, rvalue, state)
326 k++;
327
328 if (!(n = new(char*, k+1)))
329 return -ENOMEM;
330
Lennart Poettering44d8db92010-01-26 07:02:51 +0100331 k = 0;
Lennart Poettering034c6ed2010-01-26 04:18:44 +0100332 FOREACH_WORD_QUOTED(w, l, rvalue, state)
333 if (!(n[k++] = strndup(w, l)))
334 goto fail;
335
336 n[k] = NULL;
337
Lennart Poettering0301abf2010-01-27 00:15:56 +0100338 if (!n[0] || !path_is_absolute(n[0])) {
Lennart Poettering034c6ed2010-01-26 04:18:44 +0100339 log_error("[%s:%u] Invalid executable path in command line: %s", filename, line, rvalue);
340 strv_free(n);
341 return -EINVAL;
342 }
343
344 if (!(nce = new0(ExecCommand, 1)))
345 goto fail;
346
347 nce->argv = n;
348 if (!(nce->path = strdup(n[0])))
349 goto fail;
350
351 if (*e) {
352 /* It's kinda important that we keep the order here */
353 LIST_FIND_TAIL(ExecCommand, command, *e, ee);
354 LIST_INSERT_AFTER(ExecCommand, command, *e, ee, nce);
355 } else
356 *e = nce;
357
358 return 0;
359
360fail:
361 for (; k > 0; k--)
362 free(n[k-1]);
363 free(n);
364
365 free(nce);
366
367 return -ENOMEM;
368}
369
370static int config_parse_usec(
371 const char *filename,
372 unsigned line,
373 const char *section,
374 const char *lvalue,
375 const char *rvalue,
376 void *data,
377 void *userdata) {
378
379 usec_t *usec = data;
380 unsigned long long u;
381 int r;
382
383 assert(filename);
384 assert(lvalue);
385 assert(rvalue);
386 assert(data);
387
388 if ((r = safe_atollu(rvalue, &u)) < 0) {
389 log_error("[%s:%u] Failed to parse time value: %s", filename, line, rvalue);
390 return r;
391 }
392
393 /* We actually assume the user configures seconds. Later on we
394 * might choose to support suffixes for time values, to
395 * configure bigger or smaller units */
396
397 *usec = u * USEC_PER_SEC;
398
399 return 0;
400}
401
402static int config_parse_service_type(
403 const char *filename,
404 unsigned line,
405 const char *section,
406 const char *lvalue,
407 const char *rvalue,
408 void *data,
409 void *userdata) {
410
411 Service *s = data;
Lennart Poettering94f04342010-01-30 01:55:42 +0100412 ServiceType x;
Lennart Poettering034c6ed2010-01-26 04:18:44 +0100413
414 assert(filename);
415 assert(lvalue);
416 assert(rvalue);
417 assert(data);
418
Lennart Poettering94f04342010-01-30 01:55:42 +0100419 if ((x = service_type_from_string(rvalue)) < 0) {
Lennart Poettering034c6ed2010-01-26 04:18:44 +0100420 log_error("[%s:%u] Failed to parse service type: %s", filename, line, rvalue);
421 return -EBADMSG;
422 }
423
Lennart Poettering94f04342010-01-30 01:55:42 +0100424 s->type = x;
425
Lennart Poettering034c6ed2010-01-26 04:18:44 +0100426 return 0;
427}
428
429static int config_parse_service_restart(
430 const char *filename,
431 unsigned line,
432 const char *section,
433 const char *lvalue,
434 const char *rvalue,
435 void *data,
436 void *userdata) {
437
438 Service *s = data;
Lennart Poettering94f04342010-01-30 01:55:42 +0100439 ServiceRestart x;
Lennart Poettering034c6ed2010-01-26 04:18:44 +0100440
441 assert(filename);
442 assert(lvalue);
443 assert(rvalue);
444 assert(data);
445
Lennart Poettering94f04342010-01-30 01:55:42 +0100446 if ((x = service_restart_from_string(rvalue)) < 0) {
447 log_error("[%s:%u] Failed to parse service restart specifier: %s", filename, line, rvalue);
Lennart Poettering034c6ed2010-01-26 04:18:44 +0100448 return -EBADMSG;
449 }
450
Lennart Poettering94f04342010-01-30 01:55:42 +0100451 s->restart = x;
452
Lennart Poettering034c6ed2010-01-26 04:18:44 +0100453 return 0;
454}
455
Lennart Poetteringacbb0222010-01-27 04:31:52 +0100456int config_parse_bindtodevice(
457 const char *filename,
458 unsigned line,
459 const char *section,
460 const char *lvalue,
461 const char *rvalue,
462 void *data,
463 void *userdata) {
464
465 Socket *s = data;
466 char *n;
467
468 assert(filename);
469 assert(lvalue);
470 assert(rvalue);
471 assert(data);
472
473 if (rvalue[0] && !streq(rvalue, "*")) {
474 if (!(n = strdup(rvalue)))
475 return -ENOMEM;
476 } else
477 n = NULL;
478
479 free(s->bind_to_device);
480 s->bind_to_device = n;
481
482 return 0;
483}
484
Lennart Poettering071830f2010-01-28 02:06:20 +0100485int config_parse_output(
486 const char *filename,
487 unsigned line,
488 const char *section,
489 const char *lvalue,
490 const char *rvalue,
491 void *data,
492 void *userdata) {
Lennart Poettering3efd4192009-11-19 23:13:20 +0100493
Lennart Poettering94f04342010-01-30 01:55:42 +0100494 ExecOutput *o = data, x;
Lennart Poettering071830f2010-01-28 02:06:20 +0100495
496 assert(filename);
497 assert(lvalue);
498 assert(rvalue);
499 assert(data);
500
Lennart Poettering94f04342010-01-30 01:55:42 +0100501 if ((x = exec_output_from_string(rvalue)) < 0) {
502 log_error("[%s:%u] Failed to parse output specifier: %s", filename, line, rvalue);
Lennart Poettering071830f2010-01-28 02:06:20 +0100503 return -EBADMSG;
504 }
505
Lennart Poettering94f04342010-01-30 01:55:42 +0100506 *o = x;
507
508 return 0;
509}
510
511int config_parse_input(
512 const char *filename,
513 unsigned line,
514 const char *section,
515 const char *lvalue,
516 const char *rvalue,
517 void *data,
518 void *userdata) {
519
520 ExecInput *i = data, x;
521
522 assert(filename);
523 assert(lvalue);
524 assert(rvalue);
525 assert(data);
526
527 if ((x = exec_input_from_string(rvalue)) < 0) {
528 log_error("[%s:%u] Failed to parse input specifier: %s", filename, line, rvalue);
529 return -EBADMSG;
530 }
531
532 *i = x;
533
Lennart Poettering071830f2010-01-28 02:06:20 +0100534 return 0;
535}
536
537int config_parse_facility(
538 const char *filename,
539 unsigned line,
540 const char *section,
541 const char *lvalue,
542 const char *rvalue,
543 void *data,
544 void *userdata) {
545
Lennart Poettering071830f2010-01-28 02:06:20 +0100546
Lennart Poettering94f04342010-01-30 01:55:42 +0100547 int *o = data, x;
Lennart Poettering071830f2010-01-28 02:06:20 +0100548
549 assert(filename);
550 assert(lvalue);
551 assert(rvalue);
552 assert(data);
553
Lennart Poettering94f04342010-01-30 01:55:42 +0100554 if ((x = log_facility_from_string(rvalue)) < 0)
Lennart Poettering071830f2010-01-28 02:06:20 +0100555
556 /* Second try, let's see if this is a number. */
Lennart Poettering94f04342010-01-30 01:55:42 +0100557 if (safe_atoi(rvalue, &x) < 0 || !log_facility_to_string(x)) {
558 log_error("[%s:%u] Failed to parse log facility: %s", filename, line, rvalue);
Lennart Poettering071830f2010-01-28 02:06:20 +0100559 return -EBADMSG;
560 }
Lennart Poettering94f04342010-01-30 01:55:42 +0100561
562 *o = LOG_MAKEPRI(x, LOG_PRI(*o));
Lennart Poettering071830f2010-01-28 02:06:20 +0100563
564 return 0;
565}
566
567int config_parse_level(
568 const char *filename,
569 unsigned line,
570 const char *section,
571 const char *lvalue,
572 const char *rvalue,
573 void *data,
574 void *userdata) {
575
Lennart Poettering071830f2010-01-28 02:06:20 +0100576
Lennart Poettering94f04342010-01-30 01:55:42 +0100577 int *o = data, x;
Lennart Poettering071830f2010-01-28 02:06:20 +0100578
579 assert(filename);
580 assert(lvalue);
581 assert(rvalue);
582 assert(data);
583
Lennart Poettering94f04342010-01-30 01:55:42 +0100584 if ((x = log_level_from_string(rvalue)) < 0)
Lennart Poettering071830f2010-01-28 02:06:20 +0100585
586 /* Second try, let's see if this is a number. */
Lennart Poettering94f04342010-01-30 01:55:42 +0100587 if (safe_atoi(rvalue, &x) < 0 || !log_level_to_string(x)) {
588 log_error("[%s:%u] Failed to parse log level: %s", filename, line, rvalue);
Lennart Poettering071830f2010-01-28 02:06:20 +0100589 return -EBADMSG;
590 }
Lennart Poettering071830f2010-01-28 02:06:20 +0100591
Lennart Poettering94f04342010-01-30 01:55:42 +0100592 *o = LOG_MAKEPRI(LOG_FAC(*o), x);
Lennart Poettering071830f2010-01-28 02:06:20 +0100593 return 0;
594}
595
Lennart Poettering9eba9da2010-01-29 20:46:22 +0100596int config_parse_io_class(
597 const char *filename,
598 unsigned line,
599 const char *section,
600 const char *lvalue,
601 const char *rvalue,
602 void *data,
603 void *userdata) {
604
Lennart Poettering9eba9da2010-01-29 20:46:22 +0100605 ExecContext *c = data;
Lennart Poettering94f04342010-01-30 01:55:42 +0100606 int x;
Lennart Poettering9eba9da2010-01-29 20:46:22 +0100607
608 assert(filename);
609 assert(lvalue);
610 assert(rvalue);
611 assert(data);
612
Lennart Poettering94f04342010-01-30 01:55:42 +0100613 if ((x = ioprio_class_from_string(rvalue)) < 0)
Lennart Poettering9eba9da2010-01-29 20:46:22 +0100614
615 /* Second try, let's see if this is a number. */
Lennart Poettering94f04342010-01-30 01:55:42 +0100616 if (safe_atoi(rvalue, &x) < 0 || !ioprio_class_to_string(x)) {
617 log_error("[%s:%u] Failed to parse IO scheduling class: %s", filename, line, rvalue);
Lennart Poettering9eba9da2010-01-29 20:46:22 +0100618 return -EBADMSG;
619 }
Lennart Poettering9eba9da2010-01-29 20:46:22 +0100620
Lennart Poettering94f04342010-01-30 01:55:42 +0100621 c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
Lennart Poettering9eba9da2010-01-29 20:46:22 +0100622 c->ioprio_set = true;
623
624 return 0;
625}
626
627int config_parse_io_priority(
628 const char *filename,
629 unsigned line,
630 const char *section,
631 const char *lvalue,
632 const char *rvalue,
633 void *data,
634 void *userdata) {
635
636 ExecContext *c = data;
637 int i;
638
639 assert(filename);
640 assert(lvalue);
641 assert(rvalue);
642 assert(data);
643
Lennart Poettering94f04342010-01-30 01:55:42 +0100644 if (safe_atoi(rvalue, &i) < 0 || i < 0 || i >= IOPRIO_BE_NR) {
Lennart Poettering9eba9da2010-01-29 20:46:22 +0100645 log_error("[%s:%u] Failed to parse io priority: %s", filename, line, rvalue);
646 return -EBADMSG;
647 }
648
Lennart Poettering94f04342010-01-30 01:55:42 +0100649 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
Lennart Poettering9eba9da2010-01-29 20:46:22 +0100650 c->ioprio_set = true;
651
652 return 0;
653}
654
Lennart Poettering94f04342010-01-30 01:55:42 +0100655int config_parse_cpu_sched_policy(
656 const char *filename,
657 unsigned line,
658 const char *section,
659 const char *lvalue,
660 const char *rvalue,
661 void *data,
662 void *userdata) {
663
664
665 ExecContext *c = data;
666 int x;
667
668 assert(filename);
669 assert(lvalue);
670 assert(rvalue);
671 assert(data);
672
673 if ((x = sched_policy_from_string(rvalue)) < 0)
674
675 /* Second try, let's see if this is a number. */
676 if (safe_atoi(rvalue, &x) < 0 || !sched_policy_to_string(x)) {
677 log_error("[%s:%u] Failed to parse CPU scheduling policy: %s", filename, line, rvalue);
678 return -EBADMSG;
679 }
680
681 c->cpu_sched_policy = x;
682 c->cpu_sched_set = true;
683
684 return 0;
685}
686
687int config_parse_cpu_sched_prio(
688 const char *filename,
689 unsigned line,
690 const char *section,
691 const char *lvalue,
692 const char *rvalue,
693 void *data,
694 void *userdata) {
695
696 ExecContext *c = data;
697 int i;
698
699 assert(filename);
700 assert(lvalue);
701 assert(rvalue);
702 assert(data);
703
704 /* On Linux RR/FIFO have the same range */
705 if (safe_atoi(rvalue, &i) < 0 || i < sched_get_priority_min(SCHED_RR) || i > sched_get_priority_max(SCHED_RR)) {
706 log_error("[%s:%u] Failed to parse CPU scheduling priority: %s", filename, line, rvalue);
707 return -EBADMSG;
708 }
709
710 c->cpu_sched_priority = i;
711 c->cpu_sched_set = true;
712
713 return 0;
714}
715
716int config_parse_cpu_affinity(
717 const char *filename,
718 unsigned line,
719 const char *section,
720 const char *lvalue,
721 const char *rvalue,
722 void *data,
723 void *userdata) {
724
725 ExecContext *c = data;
726 char *w;
727 size_t l;
728 char *state;
729
730 assert(filename);
731 assert(lvalue);
732 assert(rvalue);
733 assert(data);
734
735 FOREACH_WORD(w, &l, rvalue, state) {
736 char *t;
737 int r;
738 unsigned cpu;
739
740 if (!(t = strndup(w, l)))
741 return -ENOMEM;
742
743 r = safe_atou(t, &cpu);
744 free(t);
745
746 if (r < 0 || cpu >= CPU_SETSIZE) {
747 log_error("[%s:%u] Failed to parse CPU affinity: %s", filename, line, rvalue);
748 return -EBADMSG;
749 }
750
751 CPU_SET(cpu, &c->cpu_affinity);
752 }
753
754 c->cpu_affinity_set = true;
755
756 return 0;
757}
758
759int config_parse_capabilities(
760 const char *filename,
761 unsigned line,
762 const char *section,
763 const char *lvalue,
764 const char *rvalue,
765 void *data,
766 void *userdata) {
767
768 ExecContext *c = data;
769 cap_t cap;
770
771 assert(filename);
772 assert(lvalue);
773 assert(rvalue);
774 assert(data);
775
776 if (!(cap = cap_from_text(rvalue))) {
777 if (errno == ENOMEM)
778 return -ENOMEM;
779
780 log_error("[%s:%u] Failed to parse capabilities: %s", filename, line, rvalue);
781 return -EBADMSG;
782 }
783
784 if (c->capabilities)
785 cap_free(c->capabilities);
786 c->capabilities = cap;
787
788 return 0;
789}
790
791int config_parse_secure_bits(
792 const char *filename,
793 unsigned line,
794 const char *section,
795 const char *lvalue,
796 const char *rvalue,
797 void *data,
798 void *userdata) {
799
800 ExecContext *c = data;
801 char *w;
802 size_t l;
803 char *state;
804
805 assert(filename);
806 assert(lvalue);
807 assert(rvalue);
808 assert(data);
809
810 FOREACH_WORD(w, &l, rvalue, state) {
811 if (first_word(w, "keep-caps"))
812 c->secure_bits |= SECURE_KEEP_CAPS;
813 else if (first_word(w, "keep-caps-locked"))
814 c->secure_bits |= SECURE_KEEP_CAPS_LOCKED;
815 else if (first_word(w, "no-setuid-fixup"))
816 c->secure_bits |= SECURE_NO_SETUID_FIXUP;
817 else if (first_word(w, "no-setuid-fixup-locked"))
818 c->secure_bits |= SECURE_NO_SETUID_FIXUP_LOCKED;
819 else if (first_word(w, "noroot"))
820 c->secure_bits |= SECURE_NOROOT;
821 else if (first_word(w, "noroot-locked"))
822 c->secure_bits |= SECURE_NOROOT_LOCKED;
823 else {
824 log_error("[%s:%u] Failed to parse secure bits: %s", filename, line, rvalue);
825 return -EBADMSG;
826 }
827 }
828
829 return 0;
830}
831
832int config_parse_bounding_set(
833 const char *filename,
834 unsigned line,
835 const char *section,
836 const char *lvalue,
837 const char *rvalue,
838 void *data,
839 void *userdata) {
840
841 ExecContext *c = data;
842 char *w;
843 size_t l;
844 char *state;
845
846 assert(filename);
847 assert(lvalue);
848 assert(rvalue);
849 assert(data);
850
851 FOREACH_WORD(w, &l, rvalue, state) {
852 char *t;
853 int r;
854 cap_value_t cap;
855
856 if (!(t = strndup(w, l)))
857 return -ENOMEM;
858
859 r = cap_from_name(t, &cap);
860 free(t);
861
862 if (r < 0) {
863 log_error("[%s:%u] Failed to parse capability bounding set: %s", filename, line, rvalue);
864 return -EBADMSG;
865 }
866
867 c->capability_bounding_set_drop |= 1 << cap;
868 }
869
870 return 0;
871}
872
873static int config_parse_timer_slack_ns(
874 const char *filename,
875 unsigned line,
876 const char *section,
877 const char *lvalue,
878 const char *rvalue,
879 void *data,
880 void *userdata) {
881
882 ExecContext *c = data;
883 unsigned long u;
884 int r;
885
886 assert(filename);
887 assert(lvalue);
888 assert(rvalue);
889 assert(data);
890
891 if ((r = safe_atolu(rvalue, &u)) < 0) {
892 log_error("[%s:%u] Failed to parse time slack value: %s", filename, line, rvalue);
893 return r;
894 }
895
896 c->timer_slack_ns = u;
897
898 return 0;
899}
900
901static int config_parse_limit(
902 const char *filename,
903 unsigned line,
904 const char *section,
905 const char *lvalue,
906 const char *rvalue,
907 void *data,
908 void *userdata) {
909
910 struct rlimit **rl = data;
911 unsigned long long u;
912 int r;
913
914 assert(filename);
915 assert(lvalue);
916 assert(rvalue);
917 assert(data);
918
919 if ((r = safe_atollu(rvalue, &u)) < 0) {
920 log_error("[%s:%u] Failed to parse resource value: %s", filename, line, rvalue);
921 return r;
922 }
923
924 if (!*rl)
925 if (!(*rl = new(struct rlimit, 1)))
926 return -ENOMEM;
927
928 (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
929 return 0;
930}
931
Lennart Poettering071830f2010-01-28 02:06:20 +0100932#define FOLLOW_MAX 8
Lennart Poettering87f0e412010-01-26 21:39:06 +0100933
Lennart Poettering0301abf2010-01-27 00:15:56 +0100934static int open_follow(char **filename, FILE **_f, Set *names, char **_id) {
935 unsigned c = 0;
Lennart Poettering87f0e412010-01-26 21:39:06 +0100936 int fd, r;
937 FILE *f;
Lennart Poettering0301abf2010-01-27 00:15:56 +0100938 char *id = NULL;
Lennart Poettering87f0e412010-01-26 21:39:06 +0100939
940 assert(filename);
941 assert(*filename);
942 assert(_f);
943 assert(names);
944
Lennart Poettering0301abf2010-01-27 00:15:56 +0100945 /* This will update the filename pointer if the loaded file is
946 * reached by a symlink. The old string will be freed. */
Lennart Poettering87f0e412010-01-26 21:39:06 +0100947
Lennart Poettering0301abf2010-01-27 00:15:56 +0100948 for (;;) {
Lennart Poettering87f0e412010-01-26 21:39:06 +0100949 char *target, *k, *name;
950
Lennart Poettering0301abf2010-01-27 00:15:56 +0100951 if (c++ >= FOLLOW_MAX)
952 return -ELOOP;
953
Lennart Poetteringb08d03f2010-01-29 02:07:41 +0100954 path_kill_slashes(*filename);
955
Lennart Poettering87f0e412010-01-26 21:39:06 +0100956 /* Add the file name we are currently looking at to
957 * the names of this unit */
Lennart Poettering0301abf2010-01-27 00:15:56 +0100958 name = file_name_from_path(*filename);
959 if (!(id = set_get(names, name))) {
Lennart Poettering87f0e412010-01-26 21:39:06 +0100960
Lennart Poettering0301abf2010-01-27 00:15:56 +0100961 if (!(id = strdup(name)))
962 return -ENOMEM;
963
964 if ((r = set_put(names, id)) < 0) {
965 free(id);
966 return r;
Lennart Poettering87f0e412010-01-26 21:39:06 +0100967 }
Lennart Poettering87f0e412010-01-26 21:39:06 +0100968 }
969
Lennart Poettering0301abf2010-01-27 00:15:56 +0100970 /* Try to open the file name, but don't if its a symlink */
971 if ((fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW)) >= 0)
Lennart Poettering87f0e412010-01-26 21:39:06 +0100972 break;
973
Lennart Poettering0301abf2010-01-27 00:15:56 +0100974 if (errno != ELOOP)
975 return -errno;
Lennart Poettering87f0e412010-01-26 21:39:06 +0100976
Lennart Poettering0301abf2010-01-27 00:15:56 +0100977 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
978 if ((r = readlink_malloc(*filename, &target)) < 0)
979 return r;
980
Lennart Poetteringc25fb0e2010-01-27 22:39:10 +0100981 k = file_in_same_dir(*filename, target);
Lennart Poettering87f0e412010-01-26 21:39:06 +0100982 free(target);
983
Lennart Poettering0301abf2010-01-27 00:15:56 +0100984 if (!k)
985 return -ENOMEM;
Lennart Poettering87f0e412010-01-26 21:39:06 +0100986
Lennart Poettering0301abf2010-01-27 00:15:56 +0100987 free(*filename);
988 *filename = k;
Lennart Poettering87f0e412010-01-26 21:39:06 +0100989 }
990
991 if (!(f = fdopen(fd, "r"))) {
992 r = -errno;
993 assert(close_nointr(fd) == 0);
Lennart Poettering0301abf2010-01-27 00:15:56 +0100994 return r;
Lennart Poettering87f0e412010-01-26 21:39:06 +0100995 }
996
997 *_f = f;
Lennart Poettering0301abf2010-01-27 00:15:56 +0100998 *_id = id;
999 return 0;
Lennart Poettering87f0e412010-01-26 21:39:06 +01001000}
1001
Lennart Poettering0301abf2010-01-27 00:15:56 +01001002static int load_from_path(Unit *u, const char *path) {
Lennart Poettering87f0e412010-01-26 21:39:06 +01001003
1004 static const char* const section_table[_UNIT_TYPE_MAX] = {
1005 [UNIT_SERVICE] = "Service",
1006 [UNIT_TIMER] = "Timer",
1007 [UNIT_SOCKET] = "Socket",
1008 [UNIT_TARGET] = "Target",
1009 [UNIT_DEVICE] = "Device",
1010 [UNIT_MOUNT] = "Mount",
1011 [UNIT_AUTOMOUNT] = "Automount",
1012 [UNIT_SNAPSHOT] = "Snapshot"
Lennart Poettering42f4e3c2010-01-19 02:56:37 +01001013 };
1014
Lennart Poettering034c6ed2010-01-26 04:18:44 +01001015#define EXEC_CONTEXT_CONFIG_ITEMS(context, section) \
Lennart Poettering9eba9da2010-01-29 20:46:22 +01001016 { "WorkingDirectory", config_parse_path, &(context).working_directory, section }, \
1017 { "RootDirectory", config_parse_path, &(context).root_directory, section }, \
Lennart Poettering1c01f822010-01-27 02:16:11 +01001018 { "User", config_parse_string, &(context).user, section }, \
1019 { "Group", config_parse_string, &(context).group, section }, \
1020 { "SupplementaryGroups", config_parse_strv, &(context).supplementary_groups, section }, \
Lennart Poetteringfb33a392010-01-28 02:53:56 +01001021 { "Nice", config_parse_nice, &(context), section }, \
1022 { "OOMAdjust", config_parse_oom_adjust, &(context), section }, \
Lennart Poettering9eba9da2010-01-29 20:46:22 +01001023 { "IOSchedulingClass", config_parse_io_class, &(context), section }, \
Lennart Poettering94f04342010-01-30 01:55:42 +01001024 { "IOSchedulingPriority", config_parse_io_priority, &(context), section }, \
1025 { "CPUSchedulingPolicy", config_parse_cpu_sched_policy,&(context), section }, \
1026 { "CPUSchedulingPriority", config_parse_cpu_sched_prio, &(context), section }, \
1027 { "CPUAffinity", config_parse_cpu_affinity, &(context), section }, \
Lennart Poettering1c01f822010-01-27 02:16:11 +01001028 { "UMask", config_parse_umask, &(context).umask, section }, \
Lennart Poettering071830f2010-01-28 02:06:20 +01001029 { "Environment", config_parse_strv, &(context).environment, section }, \
1030 { "Output", config_parse_output, &(context).output, section }, \
Lennart Poettering94f04342010-01-30 01:55:42 +01001031 { "Input", config_parse_input, &(context).input, section }, \
Lennart Poettering071830f2010-01-28 02:06:20 +01001032 { "SyslogIdentifier", config_parse_string, &(context).syslog_identifier, section }, \
1033 { "SyslogFacility", config_parse_facility, &(context).syslog_priority, section }, \
Lennart Poettering94f04342010-01-30 01:55:42 +01001034 { "SyslogLevel", config_parse_level, &(context).syslog_priority, section }, \
1035 { "Capabilities", config_parse_capabilities, &(context), section }, \
1036 { "SecureBits", config_parse_secure_bits, &(context), section }, \
1037 { "CapabilityBoundingSetDrop", config_parse_bounding_set, &(context), section }, \
1038 { "TimerSlackNS", config_parse_timer_slack_ns, &(context), section }, \
1039 { "LimitCPU", config_parse_limit, &(context).rlimit[RLIMIT_CPU], section }, \
1040 { "LimitFSIZE", config_parse_limit, &(context).rlimit[RLIMIT_FSIZE], section }, \
1041 { "LimitDATA", config_parse_limit, &(context).rlimit[RLIMIT_DATA], section }, \
1042 { "LimitSTACK", config_parse_limit, &(context).rlimit[RLIMIT_STACK], section }, \
1043 { "LimitCORE", config_parse_limit, &(context).rlimit[RLIMIT_CORE], section }, \
1044 { "LimitRSS", config_parse_limit, &(context).rlimit[RLIMIT_RSS], section }, \
1045 { "LimitNOFILE", config_parse_limit, &(context).rlimit[RLIMIT_NOFILE], section }, \
1046 { "LimitAS", config_parse_limit, &(context).rlimit[RLIMIT_AS], section }, \
1047 { "LimitNPROC", config_parse_limit, &(context).rlimit[RLIMIT_NPROC], section }, \
1048 { "LimitMEMLOCK", config_parse_limit, &(context).rlimit[RLIMIT_MEMLOCK], section }, \
1049 { "LimitLOCKS", config_parse_limit, &(context).rlimit[RLIMIT_LOCKS], section }, \
1050 { "LimitSIGPENDING", config_parse_limit, &(context).rlimit[RLIMIT_SIGPENDING], section }, \
1051 { "LimitMSGQUEUE", config_parse_limit, &(context).rlimit[RLIMIT_MSGQUEUE], section }, \
1052 { "LimitNICE", config_parse_limit, &(context).rlimit[RLIMIT_NICE], section }, \
1053 { "LimitRTPRIO", config_parse_limit, &(context).rlimit[RLIMIT_RTPRIO], section }, \
1054 { "LimitRTTIME", config_parse_limit, &(context).rlimit[RLIMIT_RTTIME], section }
Lennart Poettering034c6ed2010-01-26 04:18:44 +01001055
Lennart Poettering3efd4192009-11-19 23:13:20 +01001056 const ConfigItem items[] = {
Lennart Poettering1c01f822010-01-27 02:16:11 +01001057 { "Names", config_parse_names, u, "Meta" },
1058 { "Description", config_parse_string, &u->meta.description, "Meta" },
1059 { "Requires", config_parse_deps, UINT_TO_PTR(UNIT_REQUIRES), "Meta" },
1060 { "SoftRequires", config_parse_deps, UINT_TO_PTR(UNIT_SOFT_REQUIRES), "Meta" },
1061 { "Wants", config_parse_deps, UINT_TO_PTR(UNIT_WANTS), "Meta" },
1062 { "Requisite", config_parse_deps, UINT_TO_PTR(UNIT_REQUISITE), "Meta" },
1063 { "SoftRequisite", config_parse_deps, UINT_TO_PTR(UNIT_SOFT_REQUISITE), "Meta" },
1064 { "Conflicts", config_parse_deps, UINT_TO_PTR(UNIT_CONFLICTS), "Meta" },
1065 { "Before", config_parse_deps, UINT_TO_PTR(UNIT_BEFORE), "Meta" },
1066 { "After", config_parse_deps, UINT_TO_PTR(UNIT_AFTER), "Meta" },
Lennart Poetteringf3bff0e2010-01-29 20:47:09 +01001067 { "RecursiveStop", config_parse_bool, &u->meta.recursive_stop, "Meta" },
1068 { "StopWhenUnneeded", config_parse_bool, &u->meta.stop_when_unneeded, "Meta" },
Lennart Poettering034c6ed2010-01-26 04:18:44 +01001069
Lennart Poettering1c01f822010-01-27 02:16:11 +01001070 { "PIDFile", config_parse_path, &u->service.pid_file, "Service" },
1071 { "ExecStartPre", config_parse_exec, u->service.exec_command+SERVICE_EXEC_START_PRE, "Service" },
1072 { "ExecStart", config_parse_exec, u->service.exec_command+SERVICE_EXEC_START, "Service" },
1073 { "ExecStartPost", config_parse_exec, u->service.exec_command+SERVICE_EXEC_START_POST, "Service" },
1074 { "ExecReload", config_parse_exec, u->service.exec_command+SERVICE_EXEC_RELOAD, "Service" },
1075 { "ExecStop", config_parse_exec, u->service.exec_command+SERVICE_EXEC_STOP, "Service" },
1076 { "ExecStopPost", config_parse_exec, u->service.exec_command+SERVICE_EXEC_STOP_POST, "Service" },
1077 { "RestartSec", config_parse_usec, &u->service.restart_usec, "Service" },
1078 { "TimeoutSec", config_parse_usec, &u->service.timeout_usec, "Service" },
1079 { "Type", config_parse_service_type, &u->service, "Service" },
1080 { "Restart", config_parse_service_restart, &u->service, "Service" },
Lennart Poettering87f0e412010-01-26 21:39:06 +01001081 EXEC_CONTEXT_CONFIG_ITEMS(u->service.exec_context, "Service"),
Lennart Poettering034c6ed2010-01-26 04:18:44 +01001082
Lennart Poettering1c01f822010-01-27 02:16:11 +01001083 { "ListenStream", config_parse_listen, &u->socket, "Socket" },
1084 { "ListenDatagram", config_parse_listen, &u->socket, "Socket" },
1085 { "ListenSequentialPacket", config_parse_listen, &u->socket, "Socket" },
1086 { "ListenFIFO", config_parse_listen, &u->socket, "Socket" },
1087 { "BindIPv6Only", config_parse_socket_bind, &u->socket, "Socket" },
1088 { "Backlog", config_parse_unsigned, &u->socket.backlog, "Socket" },
Lennart Poetteringacbb0222010-01-27 04:31:52 +01001089 { "BindToDevice", config_parse_bindtodevice, &u->socket, "Socket" },
Lennart Poettering1c01f822010-01-27 02:16:11 +01001090 { "ExecStartPre", config_parse_exec, u->socket.exec_command+SOCKET_EXEC_START_PRE, "Socket" },
1091 { "ExecStartPost", config_parse_exec, u->socket.exec_command+SOCKET_EXEC_START_POST, "Socket" },
1092 { "ExecStopPre", config_parse_exec, u->socket.exec_command+SOCKET_EXEC_STOP_PRE, "Socket" },
1093 { "ExecStopPost", config_parse_exec, u->socket.exec_command+SOCKET_EXEC_STOP_POST, "Socket" },
Lennart Poettering87f0e412010-01-26 21:39:06 +01001094 EXEC_CONTEXT_CONFIG_ITEMS(u->socket.exec_context, "Socket"),
Lennart Poettering034c6ed2010-01-26 04:18:44 +01001095
Lennart Poettering87f0e412010-01-26 21:39:06 +01001096 EXEC_CONTEXT_CONFIG_ITEMS(u->automount.exec_context, "Automount"),
Lennart Poettering034c6ed2010-01-26 04:18:44 +01001097
Lennart Poettering3efd4192009-11-19 23:13:20 +01001098 { NULL, NULL, NULL, NULL }
1099 };
1100
Lennart Poettering034c6ed2010-01-26 04:18:44 +01001101#undef EXEC_CONTEXT_CONFIG_ITEMS
Lennart Poettering42f4e3c2010-01-19 02:56:37 +01001102
Lennart Poettering42f4e3c2010-01-19 02:56:37 +01001103 const char *sections[3];
Lennart Poettering0301abf2010-01-27 00:15:56 +01001104 char *k;
1105 int r;
Lennart Poettering87f0e412010-01-26 21:39:06 +01001106 Set *symlink_names;
Lennart Poettering0301abf2010-01-27 00:15:56 +01001107 FILE *f;
1108 char *filename, *id;
Lennart Poettering3efd4192009-11-19 23:13:20 +01001109
Lennart Poettering42f4e3c2010-01-19 02:56:37 +01001110 sections[0] = "Meta";
Lennart Poettering87f0e412010-01-26 21:39:06 +01001111 sections[1] = section_table[u->meta.type];
Lennart Poettering42f4e3c2010-01-19 02:56:37 +01001112 sections[2] = NULL;
1113
Lennart Poettering87f0e412010-01-26 21:39:06 +01001114 if (!(symlink_names = set_new(string_hash_func, string_compare_func)))
1115 return -ENOMEM;
Lennart Poettering3efd4192009-11-19 23:13:20 +01001116
Lennart Poettering0301abf2010-01-27 00:15:56 +01001117 /* Instead of opening the path right away, we manually
1118 * follow all symlinks and add their name to our unit
1119 * name set while doing so */
1120 if (!(filename = path_make_absolute(path, unit_path()))) {
1121 r = -ENOMEM;
Lennart Poettering87f0e412010-01-26 21:39:06 +01001122 goto finish;
Lennart Poettering034c6ed2010-01-26 04:18:44 +01001123 }
1124
Lennart Poettering0301abf2010-01-27 00:15:56 +01001125 if ((r = open_follow(&filename, &f, symlink_names, &id)) < 0) {
1126 if (r == -ENOENT)
1127 r = 0; /* returning 0 means: no suitable config file found */
Lennart Poettering87f0e412010-01-26 21:39:06 +01001128
Lennart Poettering0301abf2010-01-27 00:15:56 +01001129 goto finish;
1130 }
1131
1132 /* Now, parse the file contents */
1133 r = config_parse(filename, f, sections, items, u);
1134 if (r < 0)
1135 goto finish;
1136
1137 /* Let's try to add in all symlink names we found */
1138 while ((k = set_steal_first(symlink_names))) {
1139 if ((r = unit_add_name(u, k)) < 0)
1140 goto finish;
1141
Lennart Poettering0301abf2010-01-27 00:15:56 +01001142
Lennart Poetteringf50e0a02010-01-29 03:18:09 +01001143 if (id == k)
1144 unit_choose_id(u, id);
Lennart Poettering0301abf2010-01-27 00:15:56 +01001145 free(k);
1146 }
1147
Lennart Poetteringb08d03f2010-01-29 02:07:41 +01001148
Lennart Poettering0301abf2010-01-27 00:15:56 +01001149 free(u->meta.load_path);
1150 u->meta.load_path = filename;
1151 filename = NULL;
1152
1153 r = 1; /* returning 1 means: suitable config file found and loaded */
Lennart Poettering87f0e412010-01-26 21:39:06 +01001154
1155finish:
1156 while ((k = set_steal_first(symlink_names)))
1157 free(k);
Lennart Poettering87f0e412010-01-26 21:39:06 +01001158 set_free(symlink_names);
Lennart Poettering0301abf2010-01-27 00:15:56 +01001159 free(filename);
1160
1161 return r;
1162}
1163
1164int unit_load_fragment(Unit *u) {
Lennart Poetteringd46de8a2010-01-28 02:44:47 +01001165 int r = 0;
Lennart Poettering071830f2010-01-28 02:06:20 +01001166 ExecContext *c;
Lennart Poettering0301abf2010-01-27 00:15:56 +01001167
1168 assert(u);
1169 assert(u->meta.load_state == UNIT_STUB);
1170
1171 if (u->meta.load_path)
1172 r = load_from_path(u, u->meta.load_path);
1173 else {
1174 Iterator i;
1175 char *t;
1176
1177 /* Try to find a name we can load this with */
1178 SET_FOREACH(t, u->meta.names, i)
1179 if ((r = load_from_path(u, t)) != 0)
1180 return r;
1181 }
Lennart Poettering87f0e412010-01-26 21:39:06 +01001182
Lennart Poettering071830f2010-01-28 02:06:20 +01001183 if (u->meta.type == UNIT_SOCKET)
1184 c = &u->socket.exec_context;
1185 else if (u->meta.type == UNIT_SERVICE)
1186 c = &u->service.exec_context;
1187 else
1188 c = NULL;
1189
1190 if (r >= 0 && c &&
Lennart Poettering94f04342010-01-30 01:55:42 +01001191 (c->output == EXEC_OUTPUT_KERNEL || c->output == EXEC_OUTPUT_SYSLOG)) {
Lennart Poetteringd46de8a2010-01-28 02:44:47 +01001192 int k;
1193
Lennart Poettering071830f2010-01-28 02:06:20 +01001194 /* If syslog or kernel logging is requested, make sure
1195 * our own logging daemon is run first. */
1196
Lennart Poetteringf50e0a02010-01-29 03:18:09 +01001197 if ((k = unit_add_dependency_by_name(u, UNIT_AFTER, SPECIAL_LOGGER_SOCKET)) < 0)
Lennart Poetteringd46de8a2010-01-28 02:44:47 +01001198 return k;
Lennart Poettering071830f2010-01-28 02:06:20 +01001199
Lennart Poetteringf50e0a02010-01-29 03:18:09 +01001200 if ((k = unit_add_dependency_by_name(u, UNIT_REQUIRES, SPECIAL_LOGGER_SOCKET)) < 0)
Lennart Poetteringd46de8a2010-01-28 02:44:47 +01001201 return k;
Lennart Poettering071830f2010-01-28 02:06:20 +01001202 }
1203
Lennart Poettering87f0e412010-01-26 21:39:06 +01001204 return r;
Lennart Poettering3efd4192009-11-19 23:13:20 +01001205}